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/contacts is the primary way to sync contact data into Datamailer. It creates or updates the global contact record, creates or updates the audience- and client-scoped subscription, applies email validation and suppression state, and assigns audience-scoped tags — all in a single atomic request.

Endpoint

POST /api/contacts

Authentication

Requires a Bearer token issued to the client whose slug matches the client field in the request body.
Authorization: Bearer <client-api-key>

Request body

email
string
required
The recipient’s email address. Must be a valid RFC 5321 address. Normalized to lowercase before storage; the original casing is preserved for display.
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 exactly match the authenticated client’s slug or the request is rejected with 403 Forbidden.
status
string
default:"pending"
Subscription status to set. One of pending, subscribed, or unsubscribed. Defaults to pending when omitted.
tags
string[]
List of tag name strings to assign to this contact within the audience. Tags are audience-scoped and created automatically if they do not exist. Pass an empty array [] or omit the field to leave existing tags unchanged.
verified
boolean
default:"false"
Whether the contact’s email address has been verified by the client application. When true and no prior verified_at timestamp exists, the current time is recorded. Already-set verified_at timestamps are preserved.
email_validation
object
External email validation result to store on the contact record.
suppression
object
Contact-level suppression flags to apply. Suppression is global — it affects deliverability across all audiences.

Response

A successful call returns HTTP 200 with the full contact status payload plus a tags array.
contact_id
integer
Internal Datamailer ID for the contact record.
email
string
Normalized (lowercased) email address for the contact.
exists
boolean
Always true for a successful upsert response.
verified
boolean
Whether the contact has a verified_at timestamp set at the contact level.
verified_at
string | null
ISO-8601 UTC timestamp of contact-level verification, or null if not verified.
email_validation
object
Current email validation state.
global_unsubscribed
boolean
Whether the contact has opted out of all marketing email globally.
hard_bounced
boolean
Whether the contact’s address has hard bounced.
complained
boolean
Whether the contact has filed a spam complaint.
audience
object
Audience-scoped subscription state.
client
object
Client-scoped subscription state. Same shape as audience.
can_send_marketing
boolean
Whether a marketing campaign email can currently be sent to this contact for this audience and client. false if the contact is suppressed, has a non-deliverable email validation status, is not subscribed, or has not been verified on any subscription level.
can_send_transactional
boolean
Whether a transactional email can currently be sent to this contact. false only if the contact has hard bounced or complained.
tags
string[]
Sorted list of tag slugs currently assigned to this contact within the audience.

Example

Request

curl -X POST https://datamailer.example.com/api/contacts \
  -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",
    "status": "subscribed",
    "tags": ["course-ml-zoomcamp"],
    "verified": true,
    "email_validation": {
      "status": "externally_validated",
      "reason": "client signup validation"
    }
  }'

Response

{
  "contact_id": 42,
  "email": "learner@example.com",
  "exists": true,
  "verified": true,
  "verified_at": "2024-09-01T10:00:00Z",
  "email_validation": {
    "status": "externally_validated",
    "reason": "client signup validation",
    "validated_at": "2024-09-01T10:00:00Z"
  },
  "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"]
}

Error codes

Validation errors return HTTP 400 (or 403 for client mismatch) with the following structure:
{
  "error": {
    "code": "validation_error",
    "fields": {
      "<field>": "<error_code>"
    }
  }
}
FieldError codeMeaning
emailrequiredemail was missing or blank.
emailinvalidemail did not pass RFC 5321 format validation.
audiencerequiredaudience was missing or blank.
audiencenot_foundNo audience with that slug exists in the authenticated client’s organization.
clientrequiredclient was missing or blank.
clientforbiddenclient does not match the authenticated client’s slug. Returns HTTP 403.
statusinvalidstatus is not one of pending, subscribed, or unsubscribed.
tagsmust_be_listtags was provided but is not a JSON array.
tagsmust_be_non_empty_stringsOne or more tag entries are not non-empty strings.
verifiedmust_be_booleanverified was provided but is not a boolean.
email_validationmust_be_objectemail_validation was provided but is not a JSON object.
email_validation.statusinvalidemail_validation.status is not a recognized EmailValidationStatus value.
suppressionmust_be_objectsuppression was provided but is not a JSON object.
suppression.global_unsubscribedmust_be_booleanSuppression flag value is not a boolean.

Build docs developers (and LLMs) love