The links
| URL | Method | Who opens it | Answer |
|---|---|---|---|
/api/o/{token} | GET | The recipient's mail client, on open | A 1×1 transparent GIF |
/api/t/{token} | GET | The recipient, on a click | A 302 to the real destination |
/api/unsubscribe/{token} | POST | The mail client (RFC 8058 one-click) | Neutral, whatever the token is worth |
/unsubscribe/{token} | page | The recipient, from the email footer | The unsubscribe page |
/subscribe/confirm/{token} | page | A new contact, from the opt-in email | The confirmation page |
Double opt-in confirmation — /subscribe/confirm/{token}
A contact created through the double opt-in flow lands in pending and receives a confirmation
mail. Opening the link moves it to subscribed. Until then it is in the audience but receives
nothing.
There is no public "subscribe" endpoint. A contact enters an audience through
POST /api/v1/lists/{listId}/contacts, with an API key — see the
Audience API. Confirmation is the only public half of the flow, and it is a page,
not an API. Nobody can push contacts into your lists from the outside.What this means for the API
The status of a contact is the meeting point between these public links and the API, and the API deliberately gives way:PATCH /api/v1/contacts/{contactId}ignores astatussent in the body. Subscription state changes through explicit acts only.- An upsert never silently resurrects an unsubscribed contact.
- A recipient who unsubscribed from their mail client is unsubscribed for good; only
POST /api/v1/contacts/{contactId}/resubscribecan undo it, and never for abouncedaddress.
/api/v1. It exists only inside the
emails that were sent to that contact.