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.

Updated ·5 min read
POST/v1/contacts/{contact}/unsubscribe

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#

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.

Was this page helpful?
curl -X POST "https://api.getlaunchlist.com/v1/contacts/con_4mKp9Wq2Rx/unsubscribe" \\
  -H "Authorization: Bearer llk_live_8xKq3Rp9Wm2Nz7Vt6yL1cG5dH0jA4sE8uNqB2fXk"
{
  "object": "contact",
  "id": "con_4mKp9Wq2Rx",
  "livemode": true,
  "project": "prj_7Qk2mN4pR8",
  "identifier": "ada@lovelace.dev",
  "identifier_type": "email",
  "email": "ada@lovelace.dev",
  "external_id": "user_9182",
  "attributes": { "role": "Founder" },
  "status": "unsubscribed",
  "stage": "waitlist",
  "deliverability": null,
  "trust_tier": "verified",
  "position": 1284,
  "referral": {
    "code": "ADA7X2",
    "url": "https://acme.launchlist.page?ref=ADA7X2",
    "count": 3,
    "referred_by": null,
    "state": null
  },
  "unsubscribed": true,
  "locked": false,
  "verified_at": "2026-07-28T14:02:55+00:00",
  "opt_in_confirmed_at": "2026-07-28T14:02:55+00:00",
  "consent": "signup",
  "consented_at": "2026-08-01T09:24:11+00:00",
  "unsubscribed_by": "owner",
  "unsubscribed_at": "2026-08-02T10:00:00+00:00",
  "created_at": "2026-08-01T09:24:11+00:00",
  "url": "/v1/contacts/con_4mKp9Wq2Rx"
}