Skip to content
Cloud Services

Reliable customer email

TrackMailer — Documentation

Reach customers reliably and keep every delivery clearly visible.

Open Cloud ↗Read as Markdown

Last reviewed: 9 September 2026


01

Getting started

1. Create and verify one Cloud account. 2. Select or create the organization that owns the integration. 3. Create a project for the website, shop or brand whose data must stay together. 4. Open the product workspace and confirm that it is enabled before copying credentials or sending production traffic.

That is the complete account setup. The remaining sections are implementation guides. Credentials are always project-scoped; server secrets must never be placed in browser code, public repositories or client-side environment variables.

02

Before you integrate

Transactional sending is live only for enabled organizations with an active subscription or service entitlement, a verified sender domain and an active Live key. Contact writes are available with the contacts:write scope. Sandbox requests validate the same project contracts without storing contacts or delivering mail.

03

Create and store an API key

Open TrackMailer → API keys in the Cloud workspace. An organization owner or administrator selects Sandbox or Live, the smallest required scopes, allowed sender domains and an expiry of 1–365 days. The complete token is shown once; store it in the calling server's secret manager.

Set TRACKMAILER_API_URL to https://us-east4-markengroup-cloud-services.cloudfunctions.net/trackmailerApi. Use contacts:write for contact imports, transactional:send for transactional delivery and sequences:enroll only for contract validation because sequence execution is not enabled. Rotate by creating a replacement, deploying it, verifying traffic and then revoking the old key. The API uses Authorization: Bearer <token> and JSON request bodies.

04

Create or update a contact

POST the contacts.upsert operation to $TRACKMAILER_API_URL/v1/requests. A Live key persists the project-scoped contact; a Sandbox key returns status=validated, sent=false and persisted=false. Email identifies the contact inside the project, while externalId can hold the stable identifier from your source system.

Attributes must match fields previously defined in the workspace. Consent requires status, source and an ISO-8601 timestamp that is not in the future. A successful Live response contains status=stored, contactId and revision.

curl --request POST "$TRACKMAILER_API_URL/v1/requests" \
  --header "Authorization: Bearer $TRACKMAILER_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
  "operation": "contacts.upsert",
  "contact": {
    "email": "alex@example.com",
    "name": "Alex Rivera",
    "externalId": "crm_123",
    "attributes": {},
    "listIds": [
      "LIST_ID"
    ],
    "consent": {
      "status": "subscribed",
      "source": "checkout",
      "recordedAt": "2026-09-08T15:00:00Z"
    }
  }
}'
05

Add to or remove from a list

Create the manual list under TrackMailer → Audiences → Groups and copy its displayed list ID. Include that ID in contacts.upsert to add the contact. The API operation is intentionally additive: subsequent listIds are merged with existing membership, and an empty array does not remove prior memberships.

Removing a contact from one or more lists is currently a dashboard operation: open the contact, clear the required groups and save. There is no public replace-membership or remove-from-list endpoint yet, so an integration must not pretend that contacts.upsert performs removal.

06

Unsubscribe and suppression

To record an unsubscribe from your own preference center, send contacts.upsert with consent.status=unsubscribed, the source and the recorded time. This suppresses the contact; it is different from merely removing a list membership. Existing unsubscribed, bounced or complained contacts are never reactivated by a later import.

curl --request POST "$TRACKMAILER_API_URL/v1/requests" \
  --header "Authorization: Bearer $TRACKMAILER_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
  "operation": "contacts.upsert",
  "contact": {
    "email": "alex@example.com",
    "name": "Alex Rivera",
    "attributes": {},
    "listIds": [],
    "consent": {
      "status": "unsubscribed",
      "source": "preference-center",
      "recordedAt": "2026-09-08T16:00:00Z"
    }
  }
}'
07

Prepare a sender domain

The workspace automatically accepts the domain of your verified login email and its subdomains; no platform-admin approval is required for setup. Add the exact sender host, such as mail.example.com, under TrackMailer → Sender domains. Publish the project ownership TXT plus the DKIM, MAIL FROM MX and SPF records shown in the workspace, then wait for the complete verification to pass. Use the displayed 64-character senderDomainId in keys and send requests.

Use a dedicated subdomain for each relevant brand or stream. Every sender host still requires its own project proof and complete verification; an API key can only send through senderDomainIds explicitly attached to it.

08

Anti-Spam Health: DKIM, SPF and DMARC

TrackMailer reports domain readiness, authentication and delivery signals. Copy DNS values exactly and coordinate DMARC policy with the organization's mail administrator. Authentication reduces avoidable classification problems but cannot guarantee inbox placement.

09

Send a transactional email

POST from a trusted server to $TRACKMAILER_API_URL/v1/email/send with a Live key that has transactional:send and allows the selected senderDomainId. The request supports 1–20 unique recipients, HTML and plain text, an optional reply-to address and the purposes receipt, security or notification.

Set a unique Idempotency-Key header of 8–128 characters for the logical message. Repeating the same key and identical body returns the original messageId without creating another delivery; reusing it with different content returns HTTP 409 idempotency_conflict. A new accepted request returns HTTP 202 with status=queued.

curl --request POST "$TRACKMAILER_API_URL/v1/email/send" \
  --header "Authorization: Bearer $TRACKMAILER_API_KEY" \
  --header "Content-Type: application/json" \
  --header "Idempotency-Key: order_8472_confirmation_v1" \
  --data '{
  "senderDomainId": "SENDER_DOMAIN_ID",
  "fromLocalPart": "orders",
  "fromName": "Example Shop",
  "to": [
    {
      "email": "alex@example.com",
      "name": "Alex Rivera"
    }
  ],
  "replyTo": {
    "email": "support@example.com",
    "name": "Support"
  },
  "subject": "We received your order",
  "html": "<p>Thanks for your order.</p>",
  "text": "Thanks for your order.",
  "purpose": "receipt",
  "tags": {
    "MessageType": "order_confirmation",
    "Environment": "production"
  }
}'
10

Validate before sending

Use a Sandbox key against /v1/requests for contacts.upsert, transactional.send or sequence.enroll. Sandbox validates schema, scope and project resources but never stores, sends or enrolls. The production delivery endpoint /v1/email/send requires a Live key and cannot be used as a sandbox sender.

11

Responses, status and retries

Store requestId and messageId from every accepted send. Inspect the TrackMailer Sending view for queued, sent, delivered, bounced, complained, suppressed, failed or uncertain outcomes. HTTP 202 means durably queued, not delivered and not guaranteed to reach the inbox.

Retry 429 after the Retry-After value. Retry transient 503 responses with bounded exponential backoff and the same idempotency key and body. Do not retry 400 validation errors, 401 invalid keys, 403 scope/sender denials, 402 billing or entitlement failures, or 409 sender/suppression/idempotency conflicts until their cause is corrected.