Verification & subscription
Resend the verification email, resubscribe a contact you unsubscribed or imported as not subscribed, or unsubscribe one. The email-consent lifecycle, from your own backend.
The email-consent lifecycle, over HTTP. These are the same state changes your recipients trigger from a verification link or a one-click unsubscribe. Here you drive them from your own backend, for a preferences page or a CRM sync.
Resend verification#
POST /v1/contacts/{contact}/resend_verification
Requires contacts:write. Resends the verification email. Only meaningful while the contact is
waiting for verification: they were asked to verify their email and have not yet (verification: waiting on the
contact). A contact who has already verified, or who was never asked to, returns 422 contact_not_pending.
{
"object": "verification_resend",
"contact": "con_4mKp9Wq2Rx",
"sent": true,
"reason": "sent"
}
sent is honest: several guards can decline a send, and when one does you get sent: false rather
than a claim that mail went out. reason names which one:
reason |
What happened |
|---|---|
sent |
A fresh link was minted and the mail was queued. |
cooldown |
A verification email went to this contact moments ago, so this one was skipped. |
mail_cap |
The address is over its hourly budget for verification mail across all projects. |
undeliverable |
The address is known to bounce, or is a disposable inbox. Named once you have checked the address. |
unavailable |
The address cannot be mailed. Check the contact's email in LaunchList to see why. |
suppressed |
The address is on this project's do-not-mail list (a hard bounce, a complaint, or a block you set). |
already_verified |
The contact had already verified. In practice this endpoint answers 422 contact_not_pending before it gets here, so you will not normally see this reason. |
no_email_channel |
The contact has no email identity to verify. |
Unsubscribe#
POST /v1/contacts/{contact}/unsubscribe
Requires contacts:write. Moves the contact out of your mailing audience: status becomes
unsubscribed, and the campaign send gate skips them from then on.
Returns the full contact object in its new state.
Resubscribe#
POST /v1/contacts/{contact}/resubscribe
Requires contacts:write. Subscribes one contact so your broadcasts and automations can reach them, and
returns the contact object plus an outcome. Use it for someone you unsubscribed, or an imported contact you
added as not subscribed (status: pending). You do not need it for new signups: everyone who joins is
subscribed already.
What happens, by who the contact is:
| The contact is | Result |
|---|---|
Not subscribed (pending) |
Subscribed. outcome: subscribed. |
| Unsubscribed by you (the API, a bulk action, an import) | The unsubscribe is lifted and they are subscribed. outcome: subscribed. |
| Already subscribed | Left as they are. 200 with outcome: already. |
| Unsubscribed by themselves, or marked an email as spam | Refused with 409 contact_unsubscribed_themselves. Only they can rejoin. |
| Bounced, blocked, with no email address, or on a bounce or block list | Refused with 422 contact_cannot_be_emailed. |
| Held for review as a suspected fake signup | Refused with 409 contact_held. Approve it in the dashboard first. |
It sends no email, so nobody is welcomed or asked to verify. Lifting an unsubscribe sends the
email.resubscribed webhook; subscribing a contact you imported as not subscribed sends none. It never undoes a
person's own unsubscribe: a backend cannot quietly re-subscribe someone who left by clicking the link in
an email.
{
"object": "contact",
"id": "con_4mKp9Wq2Rx",
"status": "subscribed",
"consent": "owner",
"consented_at": "2026-10-27T09:30:00+00:00",
"outcome": "subscribed"
}
It is safe to retry, and honors Idempotency-Key like the other write calls.
Who ended a subscription#
unsubscribed_by on the contact says who ended it, so you know whether you can undo it:
unsubscribed_by |
Meaning | Can you resubscribe them? |
|---|---|---|
owner |
You or a teammate: the API, the dashboard, an import or an agent. | Yes |
contact |
They used the unsubscribe link, or their mail app's unsubscribe button. | No |
complaint |
They marked an email as spam. | No |
If you unsubscribed someone and they later unsubscribe themselves, it becomes theirs
(unsubscribed_by changes to contact), and you can no longer undo it. A spam complaint outranks
both.
Next#
- Broadcasts for the send gate these states feed, and the Who in this audience choice
- Update a contact for stage, attributes and your own id
- Delete a contact to remove or erase, when consent is not the point
Common questions
Does unsubscribing delete the contact?
No. It moves them out of your mailing audience, so their status becomes unsubscribed and the send gate skips them, but the record, its position and its referral graph all stay. If you unsubscribed them, resubscribe puts them back. If they unsubscribed themselves, only they can come back.
Do I need to subscribe new signups?
No. Everyone who signs up through a form or POST /v1/contacts is subscribed when they join. Verifying their email is a separate fact, reported as verification on the contact. Resubscribe is for someone you unsubscribed, or an imported contact you added as not subscribed.
Can I resubscribe someone who unsubscribed themselves?
No. If a person left from the link in one of your emails, or marked an email as spam, only they can rejoin, by signing up again and verifying their email. Resubscribe refuses with a 409 and tells you so.
Why did resend verification return sent false?
A per-contact cooldown suppressed it, so you did not re-send the same mail seconds after the last one. It is reported honestly rather than pretending a mail went out.