Developer guideGetting started
Test mode
ck_test_ keys capture emails without delivering them and simulate delivery, bounces, complaints and deferrals by recipient address, with real events and webhooks.
With a ck_test_ key, Couryo does everything it would do for real (validates the request, applies idempotency, creates events and calls your webhooks), except deliver. No email leaves for the internet.
How to use it#
- Create a test key under Keys (mode
test). - Use it instead of the
ck_live_key, with no other code change. - The response has
status: "captured":
{ "id": "msg_t3st0k9a1b2c3d4e", "status": "captured" }The email's status stays captured; what happened to each recipient shows up in the events.
Simulated addresses#
The part before the recipient's @ decides what the test simulates, on any domain:
| Recipient | What happens | Events |
|---|---|---|
bounced@... or bounce@... |
hard bounce | sent and bounced with 550 5.1.1 (unknown user) |
complained@... or complaint@... |
delivered, then marked as spam | sent, delivered and complained |
deferred@... |
deferred, then delivered | sent, deferred with 421 4.7.0 and delivered |
| anything else | delivered | sent and delivered with 250 2.0.0 |
Events arrive right after the send, with times (at) that mimic the real pace: the complaint 5 seconds after delivery, and the deferred email's delivery 1 minute after the deferral.
curl https://api.couryo.com/v1/emails \
-H "Authorization: Bearer $COURYO_TEST_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "Shop <orders@example.com>",
"to": ["bounced@example.com", "ana@example.com"],
"subject": "Bounce test",
"text": "Hello"
}'Simulated events go through the same path as real ones: they show up in the timeline (GET /v1/emails/{id}), in GET /v1/events and in your webhooks, with an SMTP response marked as simulated and a plain-language explanation. It is how you test bounce and complaint handling without hurting anyone's reputation.
What is different from a live key#
- No verified domain needed in
from, and no level 0 (sandbox) restriction. - Does not count toward the level's daily and monthly limits or the plan quota. The per-second request limit applies as usual.
- Never touches suppression or the account's bounce and complaint rates: a simulated
bounced@is not added to your suppression list. - The content check (shortened links and the like) only runs live. To check an email first, use
POST /v1/emails/check.
In the dashboard#
The email shows up under Emails with the captured status and the simulated timeline, and webhook calls appear in the delivery history, so you can check your integration. Viewing the rendered content and sharing a review link with your team: coming soon.
Good for#
- Automated tests and CI: no email ever reaches real customers.
- Staging environments with data copied from production.
- Testing how you handle bounce, complaint and deferral webhooks.
- Using the MCP server with your agent at no risk.