Developer guideAutomations
Contacts and events
Contacts with attributes and your app's events through the Couryo API (POST /v1/contacts and POST /v1/events), idempotent, that start and end sequences. No charge per contact.
A contact is a person who gets your sequences, with attributes to personalize (name, plan, timezone). An event is something that happened in your app (user.signed_up, order.paid): it puts the contact in the sequences that start with that name and ends the ones waiting for it as conversion.
No charge per contact. Having 100 or 100,000 contacts costs the same: only the emails sent count in the plan quota.
Send an event#
curl https://api.couryo.com/v1/events \
-H "Authorization: Bearer $COURYO_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: signup-ana-1042" \
-d '{
"contact": { "email": "ana@example.com", "attributes": { "name": "Ana", "plan": "free" } },
"name": "user.signed_up",
"properties": { "source": "site" }
}'{
"id": "cev_8k2m4q9w1x7z3abc",
"contact_id": "con_3n5p7r9t1v2x4zab",
"name": "user.signed_up",
"enrolled": [{ "sequence_id": "seq_q8w2e4r6t8y0u1io", "enrollment_id": "enr_a1s3d5f7g9h2j4kl" }],
"converted": [],
"created_at": "2026-10-08T18:30:00Z"
}- The contact is created or updated by email (attributes are merged into the existing ones).
enrolledlists the active sequences this event started. A contact enters a sequence by event once; to put it back, use the manual entry.convertedlists the enrollments closed because this is their conversion event.propertiesare available in the sequence emails as{{event.source}}.- Event name: letters, numbers,
.,_,:and-, up to 100 characters. - Scope: a
send(oradmin) key. Ack_test_key puts the contact in test mode: the sequence emails are captured and never delivered.
Idempotency#
Send Idempotency-Key with every event. The same key with the same body returns the same response, with Idempotent-Replayed: true, and creates no other event or enrollment. A different body with the same key returns 409 idempotency_conflict. Beyond the usual 24 hours, the event keeps the key: repeating it later still returns the same event.
Contacts#
curl https://api.couryo.com/v1/contacts \
-H "Authorization: Bearer $COURYO_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "email": "ana@example.com", "attributes": { "plan": "pro", "city": null } }'- Returns
201when it creates and200when it updates. - Attributes are plain values (text, number, true or false).
nullremoves the attribute. - The
timezoneattribute (for exampleAmerica/New_York) is used by waits "until HH:mm in the contact's time zone". subscribedisfalsewhen the address is on the suppression list for marketing (unsubscribe, bounce, complaint or manual). Unsubscribes always win: the contact gets no marketing sequences, and a running sequence ends right away.
| Method and path | Scope | What it does |
|---|---|---|
POST /v1/contacts |
send |
creates or updates by email |
GET /v1/contacts |
read |
lists, newest first; q searches part of the email, limit and starting_after paginate |
GET /v1/contacts/{id} |
read |
one contact, by id (con_...) or by email |
PATCH /v1/contacts/{id} |
admin |
changes the email or the attributes |
DELETE /v1/contacts/{id} |
admin |
deletes the contact and its events; it leaves the sequences (suppression stays) |
POST /v1/events |
send |
records an event of the contact |
Through MCP#
The track_event (scope send, with idempotency_key) and upsert_contact (scope send) tools do the same through the MCP server, so your AI agent can record sign-ups and purchases.