Unsubscribe

Public, anonymous endpoints that power one-click email unsubscribe. Every broadcast email automatically includes an unsubscribe footer link and RFC 8058 List-Unsubscribe / List-Unsubscribe-Post headers pointing here — you never need to build your own unsubscribe flow for broadcasts.

Unlike the rest of the API, these endpoints live at the root of the API host (not under /v1), require no authentication, and respond with HTML pages intended for the recipient's browser or mail client. Each link carries a unique per-contact token.

Confirmation page

GET
/unsubscribe?token={token}

Renders an HTML confirmation page with an 'Unsubscribe me' button that POSTs back the same token. A GET never unsubscribes anyone, so inbox link-prefetchers can't accidentally opt a contact out.

Query parameters

ParameterTypeDescription
tokenrequiredstringPer-contact unsubscribe token embedded in the email link.

Perform unsubscribe (one-click)

POST
/unsubscribe?token={token}

Performs the opt-out. This is also the RFC 8058 one-click target that mail clients invoke directly when the user presses their native Unsubscribe button.

cURL
curl -X POST "https://api.txtly.com.au/unsubscribe?token=CONTACT_TOKEN"

Unsubscribing a contact does two things:

ParameterTypeDescription
unsubscribed flageffectThe contact's unsubscribed flag is set to true, excluding them from all future broadcasts.
suppression entryeffectThe email address is added to the team's suppression list with reason 'unsubscribe', blocking every send path (transactional, batch, workflow, and broadcast).

Responses

Both endpoints always return 200 OK with an HTML page. Unknown or expired tokens receive a generic page — the endpoint never reveals whether a token (and therefore a contact) exists, and one-click mail clients expect a success response regardless. Repeating the POST for an already-unsubscribed contact is a no-op that shows the same "unsubscribed" confirmation.

Resubscribing

To opt a contact back in, set their unsubscribed flag back to false via PATCH /v1/contacts/{id} and remove the matching suppression entry via DELETE /v1/suppressions/{id}.