Test keys

A test key lets you build and run an integration without emailing your customers.

It does everything a real key does — reads your data, renders the statement, works out who would receive it, records the run, fires your webhooks — and stops at the last step. The email is never handed to our mail provider.

Getting one

  1. Account → API → New key.
  2. Give it a label and the permissions it needs.
  3. Tick Test key.

Test tokens look different, so you can tell at a glance which one you are holding:

stky_test_kZq3n8VYc2sL5pR1tW7xJb4hD6gF9mA0eU    ← test
stky_Yb7mK2pQ9wR4tN6vX1zC8dF3gH5jL0aS           ← live

A key is test or live for its whole life. There is no switch. To go live, create a second key without the box ticked and move your system across — which is what you would want anyway, so your staging and production systems hold different credentials.

You can confirm which one you have at any time:

curl https://app.statey.app/api/v1/organisation \
  -H "Authorization: Bearer stky_test_your_key_here"
{
  "api_key": { "label": "Staging", "scopes": ["read", "write", "send"], "sandbox": true }
}

What is different, and what is not

Test key
Reads your real data Yes — same contacts, same balances
Renders the statement PDF Yes
Works out who would receive one Yes
Records the run and its recipients Yes, marked as a test
Fires your webhooks Yes
Uses your daily send allowance Yes
Actually emails anyone No

Two of those surprise people, so they are worth saying plainly.

It reads your real data. A test key is not a separate sandbox account with invented customers. It sees your live contacts and their real balances, and renders the statement they would actually receive. That is deliberate — the failures worth catching are the ones involving your own data, like a customer whose statement comes back blank.

It uses your daily allowance. A test run of 300 contacts spends 300 of your 5,000. Testing is not a free send path. Keep rehearsals modest and check X-Quota-Remaining .

Seeing what happened

A test run appears in Sent items like any other, badged "Test run — not sent". Use the Exclude test runs filter for a clean view of real sends.

Through the API, campaigns carry a sandbox  flag:

curl https://app.statey.app/api/v1/campaigns/7a6b5c4d-... \
  -H "Authorization: Bearer stky_test_your_key_here"
{
  "campaign": { "id": "7a6b5c4d-...", "sandbox": true, "subject": "August statements" },
  "recipients": [
    { "contact_id": "9f8e...", "contact_name": "Acme Supplies",
      "email_address": "accounts@acme.example", "status": "pending" }
  ]
}

The recipient list is the useful part: these are the people who would have been emailed, with the addresses that would have been used. Check it before you go live.

Their status  stays pending , because nothing was delivered and so no delivery ever came back.

Webhooks from a test run

Test runs fire your webhooks, so you can build and verify a receiver end to end.

  • statement_run.sent fires as normal, with "sandbox": true  in the payload.
  • statement.delivery_updated is simulated — one delivered  event per recipient, also marked "sandbox": true .

The second needs explaining. That event normally relays what our mail provider tells us, and a test run never reaches them, so no real event will ever arrive. Without simulation, the webhook most people want to test would be the one a test key could not exercise.

So a simulated delivered  is emitted instead. Two things follow:

  • You cannot rehearse a bounce. Simulated events are always delivered . To test bounce handling, post a sample payload to your own endpoint directly.
  • Filter on sandbox  if it matters. If your integration writes back to a ledger or raises tasks, ignore events carrying "sandbox": true , or a rehearsal will show up in your real records.

Suggested way to use it

1. Create a test key with the permissions you need.
2. Build against it. Check the recipient list on each run, not just the 202.
3. Point your webhook receiver at it and confirm you handle duplicates and signatures.
4. Create a live key, move the credential across, and revoke nothing —
   keep the test key for your staging environment.

Step 4 is the point of separate keys: you keep a safe place to try changes after you have gone live.