Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/DataTalksClub/datamailer/llms.txt

Use this file to discover all available pages before exploring further.

POST /api/subscriptions/subscribe is the fastest path to marking a contact as subscribed. It upserts the contact by normalized email, then calls subscribe_contact which sets status=subscribed and stamps verified_at=now on the client-scoped subscription. If you need finer control over subscription status, verified flag, or suppression fields on the same request, use the upsert endpoint (POST /api/contacts) instead.

Authentication

All requests must include a Bearer token issued for the target client.
Authorization: Bearer <client-api-key>

Request

Method and path: POST /api/subscriptions/subscribe Content-Type: application/json

Body Parameters

email
string
required
The contact’s email address. Trimmed and validated before processing. The contact is looked up and upserted by its normalized (lowercased) form.
audience
string
required
Slug of the audience to subscribe the contact to. Must belong to the same organization as the authenticated client.
client
string
required
Slug of the client making the request. Must match the authenticated client’s own slug — cross-client writes are forbidden (HTTP 403).
tags
string[]
Optional list of tag names to assign to the contact within this audience. Each entry must be a non-empty string. Tags are audience-scoped and created automatically if they do not already exist.

Behavior

1

Validate scope

Confirm that email, audience, and client are present and that client matches the authenticated token’s client slug.
2

Upsert contact

Create the contact record if one does not already exist for the normalized email address.
3

Subscribe

Call subscribe_contact, which creates or updates the client-scoped Subscription record with status=subscribed and stamps verified_at to the current UTC time.
4

Assign tags

For each name in tags, look up or create the audience-scoped tag, then create the ContactTag membership.
5

Return contact payload

Return the full contact object including subscription state and tags.

Response

HTTP 200 OK on success.
contact_id
integer
Internal ID of the contact record.
email
string
Normalized (lowercased) email address stored for this contact.
exists
boolean
true when the contact has a subscription visible to the authenticated client.
verified
boolean
true when the contact or subscription has a non-null verified_at timestamp.
verified_at
string | null
ISO 8601 timestamp of verification, or null.
email_validation
object
global_unsubscribed
boolean
true when the contact has a global marketing unsubscribe on record.
hard_bounced
boolean
true when the contact has a hard bounce on record.
complained
boolean
true when the contact has filed a spam complaint.
audience
object
client
object
can_send_marketing
boolean
true when the contact is eligible to receive marketing emails from this client right now. Requires a verified subscription and no active suppression.
can_send_transactional
boolean
true when the contact is not hard-bounced or complained, meaning transactional sends are allowed.
tags
string[]
Sorted list of tag slugs assigned to this contact within the audience.

Example

Request

curl -X POST https://datamailer.example.com/api/subscriptions/subscribe \
  -H "Authorization: Bearer dm_dtccourses_demo_transactional_email_key" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "learner@example.com",
    "audience": "dtc-courses",
    "client": "dtc-courses",
    "tags": ["course-ml-zoomcamp"]
  }'

Response

{
  "contact_id": 42,
  "email": "learner@example.com",
  "exists": true,
  "verified": true,
  "verified_at": "2024-09-01T10:00:00Z",
  "email_validation": {
    "status": "unknown",
    "reason": "",
    "validated_at": null
  },
  "global_unsubscribed": false,
  "hard_bounced": false,
  "complained": false,
  "audience": {
    "slug": "dtc-courses",
    "subscribed": false,
    "status": null,
    "verified": false,
    "verified_at": null,
    "unsubscribed_at": null,
    "unsubscribe_reason": ""
  },
  "client": {
    "slug": "dtc-courses",
    "subscribed": true,
    "status": "subscribed",
    "verified": true,
    "verified_at": "2024-09-01T10:00:00Z",
    "unsubscribed_at": null,
    "unsubscribe_reason": ""
  },
  "can_send_marketing": true,
  "can_send_transactional": true,
  "tags": ["course-ml-zoomcamp"]
}
Use POST /api/contacts (the upsert endpoint) when you need to set a specific subscription status (e.g., pending), control the verified flag independently, or write email validation and suppression data in the same request. The subscribe endpoint always sets status=subscribed and stamps verified_at.

Build docs developers (and LLMs) love