Contacts
A lightweight address book scoped to each project — store the people you email, attach your own metadata, and track their subscribe state. It's a record-keeping layer, not a marketing list.
Contacts let you keep names, custom metadata, and subscribe status alongside an email address. Each project has its own address book. Drin stays transactional — there are no broadcasts or campaigns here — but a contact record is a convenient home for the data your own send logic reads.
subscribed flag is your opt-in state — you decide what it means and whether to honour it before sending. Suppressions are enforced by Drin at send time and populated automatically by bounces and complaints. They're separate systems; unsubscribing a contact does not suppress the address, and vice versa.01 Create a contact
/v1/contactsOnly email is required. firstName, lastName, subscribed (defaults to true), and an arbitrary metadata object are optional.
curl https://api.drin.run/v1/contacts \
-H "Authorization: Bearer $DRIN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"email": "sam@example.com",
"firstName": "Sam",
"lastName": "Rivera",
"metadata": { "plan": "pro" }
}'{
"id": "ct_0K3a…",
"email": "sam@example.com",
"firstName": "Sam",
"lastName": "Rivera",
"subscribed": true,
"unsubscribedAt": null,
"metadata": { "plan": "pro" },
"createdAt": "2026-06-02T09:00:00Z",
"updatedAt": "2026-06-02T09:00:00Z"
}02 List & search
/v1/contactsCursor-paged like every list endpoint. Filter with subscribed=true|false and search names and email with q.
# All contacts
curl "https://api.drin.run/v1/contacts?limit=50" \
-H "Authorization: Bearer $DRIN_API_KEY"
# Only subscribed, matching a search term
curl "https://api.drin.run/v1/contacts?subscribed=true&q=rivera" \
-H "Authorization: Bearer $DRIN_API_KEY"03 Update
/v1/contacts/{id}Partial update — send only the fields you want to change. firstName and lastName accept null to clear them. To change subscribe state, use the dedicated endpoints below rather than patching it directly.
curl -X PATCH https://api.drin.run/v1/contacts/ct_0K3a \
-H "Authorization: Bearer $DRIN_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "lastName": null, "metadata": { "plan": "scale" } }'04 Unsubscribe & resubscribe
/v1/contacts/{id}/unsubscribeUnsubscribing flips subscribed to false and stamps unsubscribedAt. Resubscribing flips it back and clears the timestamp. Both return the updated contact.
# Unsubscribe (stamps unsubscribedAt, flips subscribed → false)
curl -X POST https://api.drin.run/v1/contacts/ct_0K3a/unsubscribe \
-H "Authorization: Bearer $DRIN_API_KEY"
# Resubscribe (clears unsubscribedAt, flips subscribed → true)
curl -X POST https://api.drin.run/v1/contacts/ct_0K3a/resubscribe \
-H "Authorization: Bearer $DRIN_API_KEY"subscribed in your own send path, or add the address to suppressions when you want Drin to enforce the opt-out at the gateway.05 Delete
/v1/contacts/{id}Permanently removes the contact record. Returns 204 No Content. This deletes the address-book entry only — it has no effect on already-sent messages or the suppression list.
curl -X DELETE https://api.drin.run/v1/contacts/ct_0K3a \
-H "Authorization: Bearer $DRIN_API_KEY"