Skip to content

Test & live modes

Every API key is bound to exactly one project and one modetest or live. The mode is baked into the key prefix:

  • sk_test_… — a test-mode key
  • sk_live_… — a live-mode key

You pass the key as a bearer token, and the mode comes along with it. There is no mode parameter on any request — the key decides.

Terminal window
# A test-mode request: builds, schedules, and delivers against test data only.
curl https://api.schedstack.com/v1/schedules \
-H "Authorization: Bearer sk_test_…" \
-H "Content-Type: application/json" \
-d '{
"endpoint": "https://example.com/hooks/orders",
"method": "POST",
"body": "{\"order_id\":\"ord_123\"}",
"delay": "30s"
}'

The resources you create echo their mode back so you always know which side you’re on:

{
"id": "sch_…",
"object": "schedule",
"mode": "test",
"endpoint": "https://example.com/hooks/orders",
"method": "POST",
"state": "active"
}

Test and live are separate datasets within the same project. A sk_test_… key cannot read, list, or mutate live data, and a sk_live_… key cannot touch test data. Isolation is enforced at the query layer — every read and write is scoped by (project, mode).

This applies to everything keyed off a request:

  • Schedules, endpoints, and deliveries are mode-scoped. GET /v1/schedules, GET /v1/deliveries/{id}, and attempt history return only rows for the calling key’s mode.
  • Idempotency keys are mode-scoped too. The same idempotency_key used by a sk_test_… request and a sk_live_… request will not collide — they resolve to independent schedules. A test request never replays a live response, or vice versa.

Only live first attempts count toward the SLO

Section titled “Only live first attempts count toward the SLO”

SchedStack publishes a 100–300 ms dispatch SLO (fired_at − scheduled_for, p99, where fired_at is the first byte out). The SLO measures dispatch initiation — when we start the send — not your receiver’s response time.

The published number is computed over a deliberately narrow population:

  • live mode only — test-mode dispatches are excluded entirely.
  • First attempts only (the initial fire). Retries, reclaim/recovery fires, rate-limit or breaker deferrals, catch-up/coalesced fires, and DST-shifted fires are all excluded.

Test mode is for correctness, not timing. Use it to verify that your endpoint receives, verifies the signature on, and idempotently handles a delivery — but don’t read anything into test-mode dispatch latency.

  1. Build against a sk_test_… key. Point your integration at the same base URL and paths — only the key changes. Schedule short delays, watch deliveries land, and inspect retries and the dead-letter view without touching live data.

  2. Verify the full contract. Confirm your endpoint verifies the Sched-Signature and dedupes on the delivery ID — at-least-once delivery means you own deduplication. Test mode is the place to prove this before real traffic.

  3. Swap to sk_live_… to go live. Same code, live key. Because data is isolated, nothing you created in test leaks into live — you start clean. Keep the test key wired into CI and local dev.

  • Idempotency — how idempotency keys are scoped and how to dedupe at-least-once delivery.
  • Retries & dead-letter — what happens when a delivery doesn’t land on the first attempt.
  • Quickstart — schedule your first durable delivery and watch it land.