Subscribe or unsubscribe a contact from a topic
The two directions behave differently, and the asymmetry is deliberate: consent needs proof, withdrawal of consent does not.
subscribed: true does NOT subscribe anyone. It parks the contact at pending and returns a confirmation_url; nothing is mailed on this topic until somebody opens it. There is no parameter to skip that step. A caller asserting a subscription is not evidence that the mailbox holder agreed — anyone can type an address into a form — and treating the assertion as consent is the exact failure double opt-in exists to prevent. Sendly does not send the confirmation email; you do, from your own verified domain, because it is your relationship with the contact and your sending reputation.
subscribed: false records the opt-out immediately. Requiring somebody to confirm that they want to stop is a dark pattern, and it is also the fastest route to a spam report.
Requires the topics:write scope — Create and edit topics, and change what your contacts are subscribed to — this decides who your campaigns reach.
API key authentication. Use a sk_* (FULL) or pk_* (SENDING_ONLY) key as the bearer token. Public keys (pk_*) are restricted to the email-send endpoints and the self-serve list subscribe/unsubscribe pair; every other endpoint — event tracking included — answers 403 for them. In scope terms (used by /api/v1/* operations): FULL keys hold every scope; SENDING_ONLY keys hold only emails:send.
In: header
Path Parameters
Resource id.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/problem+json
application/problem+json
application/problem+json
application/problem+json
application/problem+json
application/problem+json
curl -X POST "https://example.com/api/v1/topics/497f6eca-6276-4993-bfeb-53cbbbba6f08/subscriptions" \ -H "Content-Type: application/json" \ -d '{ "contact_id": "f245e2a3-e141-4d41-912c-b1c1f5bd5598", "subscribed": true }'{
"topic_id": "string",
"contact_id": "string",
"status": "pending",
"confirmed_at": "2019-08-24T14:15:22Z",
"confirmation_url": "string"
}{
"type": "http://example.com",
"title": "string",
"status": 0,
"detail": "string",
"instance": "string",
"code": "string",
"request_id": "string",
"errors": [
{
"pointer": "string",
"code": "string",
"message": "string"
}
]
}{
"type": "http://example.com",
"title": "string",
"status": 0,
"detail": "string",
"instance": "string",
"code": "string",
"request_id": "string",
"errors": [
{
"pointer": "string",
"code": "string",
"message": "string"
}
]
}{
"type": "http://example.com",
"title": "string",
"status": 0,
"detail": "string",
"instance": "string",
"code": "string",
"request_id": "string",
"errors": [
{
"pointer": "string",
"code": "string",
"message": "string"
}
]
}{
"type": "http://example.com",
"title": "string",
"status": 0,
"detail": "string",
"instance": "string",
"code": "string",
"request_id": "string",
"errors": [
{
"pointer": "string",
"code": "string",
"message": "string"
}
]
}{
"type": "http://example.com",
"title": "string",
"status": 0,
"detail": "string",
"instance": "string",
"code": "string",
"request_id": "string",
"errors": [
{
"pointer": "string",
"code": "string",
"message": "string"
}
]
}{
"type": "http://example.com",
"title": "string",
"status": 0,
"detail": "string",
"instance": "string",
"code": "string",
"request_id": "string",
"errors": [
{
"pointer": "string",
"code": "string",
"message": "string"
}
]
}