developers.10x.in/docs/end-user/campaign-email-automation-through-10xdotin Published:

Campaign Email Automation Through 10xDotIn

This guide is for an external developer integrating with 10xDotIn email automation for a handle. It covers the supported API path for setting up verified senders, reusable templates, direct email sends, and campaign email rules such as lead-capture follow-ups or conversion-triggered messages.

Warning

Email automation currently uses JWT handle access on /v2/handles/{handle}/... routes. Personal Access Tokens are not supported for these email sender, template, message, or campaign email-rule routes yet. Do not request or depend on email:sender:* or email:rule:* scopes. Those scopes are not part of the current 10xDotIn permission model.

Quick Answer: Should This Work With JWT?

Yes, this should work with JWT when all of the following are true:

  • The token is a valid 10xDotIn/Product Suite JWT accepted by the /v2/handles/* API gateway authorizer.
  • The JWT subject maps to a user who has OPERATOR or OWNER access to the target handle.
  • The target handle is active.
  • The account owns the sending domain.
  • The domain email identity is READY.
  • The sender profile is enabled, READY, and has the correct purpose for the action.
  • The email template exists and is active.
  • The transactional email queues are configured in the target environment.

JWT alone is not enough if the user lacks handle access, the sender/domain is not ready, the template does not exist, or the environment queue is unavailable.

If the caller has only a PAT or an OpenAnalyst runtime token, the current email APIs should not be assumed to work. A server-to-server or unattended external automation would need a purpose-built PAT-facing wrapper route or a scoped extension added to 10xDotIn.

Auth Model

Use the same JWT that the signed-in Product Suite user uses for handle-admin APIs.

export TENX_API_BASE="https://ai.10x.in"
export TENX_JWT="<10xdotin-product-suite-jwt>"
export TENX_HANDLE="acme"
export TENX_DOMAIN="example.com"

Pass it on every request:

-H "Authorization: Bearer ${TENX_JWT}"

Required role by route family:

Route familyMinimum handle role
GET /v2/handles/{handle}/email/sendersOPERATOR
PUT /v2/handles/{handle}/email/senders/{senderId}OPERATOR
GET/POST/PUT /v2/handles/{handle}/email/templates*OPERATOR
POST /v2/handles/{handle}/email/messagesOPERATOR
GET /v2/handles/{handle}/email/messages*OPERATOR
GET /v2/handles/{handle}/email/eventsOPERATOR
GET /v2/handles/{handle}/campaigns/{campaignId}/email-rulesCREATOR
POST/PUT/DELETE /v2/handles/{handle}/campaigns/{campaignId}/email-rules*OPERATOR

Supported Endpoint Summary

JobMethod and pathSuccess
Check domain email identityGET /v2/account/domains/{domain}/email-identity200
Reconcile domain email identityPOST /v2/account/domains/{domain}/email-identity/reconcile202
List sender profilesGET /v2/handles/{handle}/email/senders200
Create or update sender profilePUT /v2/handles/{handle}/email/senders/{senderId}200
List templatesGET /v2/handles/{handle}/email/templates200
Create templatePOST /v2/handles/{handle}/email/templates201
Update templatePUT /v2/handles/{handle}/email/templates/{templateId}200
Queue direct email messagePOST /v2/handles/{handle}/email/messages202
List queued/sent messagesGET /v2/handles/{handle}/email/messages200
Get one message and timelineGET /v2/handles/{handle}/email/messages/{messageId}200
List delivery eventsGET /v2/handles/{handle}/email/events200
List campaign email rulesGET /v2/handles/{handle}/campaigns/{campaignId}/email-rules200
Create campaign email rulePOST /v2/handles/{handle}/campaigns/{campaignId}/email-rules201
Update campaign email rulePUT /v2/handles/{handle}/campaigns/{campaignId}/email-rules/{ruleId}200
Delete campaign email ruleDELETE /v2/handles/{handle}/campaigns/{campaignId}/email-rules/{ruleId}204

Prerequisite Setup Flow

1. Verify The Domain Email Identity

curl -sS "${TENX_API_BASE}/v2/account/domains/${TENX_DOMAIN}/email-identity" \
  -H "Authorization: Bearer ${TENX_JWT}"

Expected ready shape:

{
  "identity": {
    "identityKey": "us-east-1#example.com",
    "region": "us-east-1",
    "domain": "example.com",
    "status": "READY",
    "requiredDnsRecords": [],
    "mailFromDomain": "bounce.example.com"
  },
  "senderProfiles": []
}

If the status is not READY, reconcile after DNS is configured:

curl -sS -X POST "${TENX_API_BASE}/v2/account/domains/${TENX_DOMAIN}/email-identity/reconcile" \
  -H "Authorization: Bearer ${TENX_JWT}"

Reconcile returns 202; it does not mean DNS is ready immediately. Poll the identity endpoint until status is READY.

2. Create A Sender Profile

Sender profile rules:

  • senderId must start with sender_.
  • localPart must be one of: noreply, notifications, calendar, support, hello.
  • purposes must include the purpose you will use later.
  • Campaign email rules require PRODUCT_NOTIFICATION.
  • Lead-capture OTP verification requires LEAD_VERIFICATION.
  • Direct transactional sends usually use TRANSACTIONAL_API.
curl -sS -X PUT "${TENX_API_BASE}/v2/handles/${TENX_HANDLE}/email/senders/sender_notifications" \
  -H "Authorization: Bearer ${TENX_JWT}" \
  -H "Content-Type: application/json" \
  -d '{
    "domain": "example.com",
    "localPart": "notifications",
    "displayName": "Acme Notifications",
    "replyTo": "support@example.com",
    "purposes": ["PRODUCT_NOTIFICATION", "LEAD_VERIFICATION", "TRANSACTIONAL_API"],
    "enabled": true
  }'

Response:

{
  "sender": {
    "senderId": "sender_notifications",
    "domain": "example.com",
    "localPart": "notifications",
    "fromEmail": "notifications@example.com",
    "displayName": "Acme Notifications",
    "replyTo": "support@example.com",
    "purposes": ["PRODUCT_NOTIFICATION", "LEAD_VERIFICATION", "TRANSACTIONAL_API"],
    "enabled": true,
    "status": "READY",
    "identityKey": "us-east-1#example.com"
  }
}

3. Create A Template

Template rules:

  • templateId must start with tmpl_.
  • A template needs a subject and at least one body field, html or text.
  • Template variables use {{variableName}}.
curl -sS -X POST "${TENX_API_BASE}/v2/handles/${TENX_HANDLE}/email/templates" \
  -H "Authorization: Bearer ${TENX_JWT}" \
  -H "Content-Type: application/json" \
  -d '{
    "templateId": "tmpl_lead_followup",
    "name": "Lead follow-up",
    "subject": "Thanks for reaching out, {{firstName}}",
    "html": "<p>Hi {{firstName}}, thanks for your interest in {{service}}.</p>",
    "text": "Hi {{firstName}}, thanks for your interest in {{service}}."
  }'

Response:

{
  "template": {
    "handle": "acme",
    "templateId": "tmpl_lead_followup",
    "name": "Lead follow-up",
    "activeVersion": 1,
    "status": "ACTIVE"
  }
}

Direct Send Flow

Use POST /v2/handles/{handle}/email/messages when the integration wants to queue a single outbound email directly.

curl -sS -X POST "${TENX_API_BASE}/v2/handles/${TENX_HANDLE}/email/messages" \
  -H "Authorization: Bearer ${TENX_JWT}" \
  -H "Content-Type: application/json" \
  -d '{
    "senderId": "sender_notifications",
    "to": ["buyer@example.com"],
    "purpose": "TRANSACTIONAL_API",
    "idempotencyKey": "receipt-ord_12345",
    "consentAttestation": true,
    "templateId": "tmpl_lead_followup",
    "variables": {
      "firstName": "Asha",
      "service": "AI workflow setup"
    }
  }'

Accepted response:

{
  "message": {
    "messageId": "msg_abc123",
    "handle": "acme",
    "status": "QUEUED",
    "purpose": "TRANSACTIONAL_API",
    "senderId": "sender_notifications",
    "recipientCount": 1,
    "fromEmail": "Acme Notifications <notifications@example.com>",
    "createdAt": "2026-06-12T08:00:00.000Z"
  }
}

202 QUEUED means the API stored the message and queued delivery. It is not proof of inbox delivery. Use the message and event endpoints for delivery state.

Campaign Email Rule Flow

Use campaign email rules when 10xDotIn should send emails automatically in response to campaign events.

Supported rule triggers:

TriggerMeaningDelay
LEAD_CAPTUREDSend when a campaign lead is capturedImmediate
LEAD_CAPTURED_DELAYEDSchedule a follow-up after lead captureRequires delayMinutes
CONVERSIONSend when a campaign conversion is recordedImmediate

Delayed sends require delayMinutes from 15 through 43200 minutes, which is 30 days.

Creating a rule does not send emails to existing leads retroactively. It applies to future trigger jobs for that campaign.

Create An Immediate Lead-Captured Rule

curl -sS -X POST "${TENX_API_BASE}/v2/handles/${TENX_HANDLE}/campaigns/cmp_welcome/email-rules" \
  -H "Authorization: Bearer ${TENX_JWT}" \
  -H "Content-Type: application/json" \
  -d '{
    "trigger": "LEAD_CAPTURED",
    "templateId": "tmpl_lead_followup",
    "senderId": "sender_notifications",
    "enabled": true,
    "variableMappings": {
      "firstName": "firstName",
      "service": "fields.service"
    }
  }'

Response:

{
  "rule": {
    "ruleId": "cer_2f3ddf1b-7d15-4f70-83bb-1d28b91a42c5",
    "campaignId": "cmp_welcome",
    "trigger": "LEAD_CAPTURED",
    "delayMinutes": null,
    "templateId": "tmpl_lead_followup",
    "senderId": "sender_notifications",
    "variableMappings": {
      "firstName": "firstName",
      "service": "fields.service"
    },
    "enabled": true,
    "version": 1,
    "createdAt": "2026-06-12T08:00:00.000Z",
    "updatedAt": "2026-06-12T08:00:00.000Z"
  }
}

Create A Delayed Follow-Up Rule

curl -sS -X POST "${TENX_API_BASE}/v2/handles/${TENX_HANDLE}/campaigns/cmp_welcome/email-rules" \
  -H "Authorization: Bearer ${TENX_JWT}" \
  -H "Content-Type: application/json" \
  -d '{
    "trigger": "LEAD_CAPTURED_DELAYED",
    "delayMinutes": 1440,
    "templateId": "tmpl_lead_followup",
    "senderId": "sender_notifications",
    "enabled": true
  }'

1440 schedules the email approximately one day after the lead-capture trigger.

Create A Conversion Rule

curl -sS -X POST "${TENX_API_BASE}/v2/handles/${TENX_HANDLE}/campaigns/cmp_welcome/email-rules" \
  -H "Authorization: Bearer ${TENX_JWT}" \
  -H "Content-Type: application/json" \
  -d '{
    "trigger": "CONVERSION",
    "templateId": "tmpl_lead_followup",
    "senderId": "sender_notifications",
    "enabled": true
  }'

List Rules

curl -sS "${TENX_API_BASE}/v2/handles/${TENX_HANDLE}/campaigns/cmp_welcome/email-rules" \
  -H "Authorization: Bearer ${TENX_JWT}"

Update A Rule

Use expectedVersion when your UI or integration edits a rule to avoid overwriting a concurrent change.

curl -sS -X PUT "${TENX_API_BASE}/v2/handles/${TENX_HANDLE}/campaigns/cmp_welcome/email-rules/cer_2f3ddf1b-7d15-4f70-83bb-1d28b91a42c5" \
  -H "Authorization: Bearer ${TENX_JWT}" \
  -H "Content-Type: application/json" \
  -d '{
    "trigger": "LEAD_CAPTURED_DELAYED",
    "delayMinutes": 2880,
    "templateId": "tmpl_lead_followup",
    "senderId": "sender_notifications",
    "enabled": true,
    "expectedVersion": 1
  }'

If the version has changed, the API returns 409 version_conflict.

Delete A Rule

curl -sS -X DELETE "${TENX_API_BASE}/v2/handles/${TENX_HANDLE}/campaigns/cmp_welcome/email-rules/cer_2f3ddf1b-7d15-4f70-83bb-1d28b91a42c5" \
  -H "Authorization: Bearer ${TENX_JWT}"

The delete is a soft delete and returns 204. Repeating the delete is safe.

Template Variables For Campaign Rules

Campaign-triggered sends render variables from the lead snapshot captured at trigger time. Default variables include:

VariableSource
leadIdLead id
emailLead email
nameLead full name
firstNameExplicit first name or first word of name
phoneLead phone
companyLead company
serviceLead service
messageLead message
sourceLead source

Use variableMappings to map template variables to either top-level lead fields or custom fields:

{
  "variableMappings": {
    "requestedService": "fields.service",
    "companyName": "company"
  }
}

Mapping keys and values must be short safe identifiers containing letters, numbers, _, ., or -.

Delivery And Debugging

Campaign email rules create transactional email messages asynchronously when trigger jobs run. The final delivery worker validates the sender and domain again before sending. If a sender or domain becomes disabled after rule creation, the queued message can be denied instead of sent.

Inspect message state:

curl -sS "${TENX_API_BASE}/v2/handles/${TENX_HANDLE}/email/messages?limit=25" \
  -H "Authorization: Bearer ${TENX_JWT}"

Inspect one message timeline:

curl -sS "${TENX_API_BASE}/v2/handles/${TENX_HANDLE}/email/messages/msg_abc123" \
  -H "Authorization: Bearer ${TENX_JWT}"

Inspect events:

curl -sS "${TENX_API_BASE}/v2/handles/${TENX_HANDLE}/email/events?messageId=msg_abc123" \
  -H "Authorization: Bearer ${TENX_JWT}"

When listing events without messageId or recipient, include at least purpose or since.

Common Errors

StatusErrorMeaningFix
401missing_bearer_tokenNo bearer token was suppliedSend Authorization: Bearer <jwt>
401Authorizer failureJWT is expired, malformed, or not accepted by the API gateway authorizerObtain a fresh 10xDotIn/Product Suite JWT
403forbiddenJWT user has no access to the handle or accountGrant the user handle access
403insufficient_roleUser has a lower role than requiredUse an OPERATOR or OWNER user
404account_domain_not_foundDomain is not attached to this accountAttach the domain first
409domain_email_identity_not_readyDomain email identity is not verified and readyFix DNS and reconcile identity
400invalid_sender_idSender id is missing or does not start with sender_Use a valid sender id
400sender_local_part_not_allowedSender local part is not in the allowlistUse noreply, notifications, calendar, support, or hello
404sender_profile_not_foundSender profile does not existCreate the sender profile
409sender_profile_not_ready or sender_not_readySender is disabled or pausedEnable or recreate a ready sender
403sender_purpose_not_allowedDirect send purpose is not allowed for senderAdd the purpose or use another sender
409sender_missing_product_notification_purposeCampaign rule sender lacks PRODUCT_NOTIFICATIONAdd PRODUCT_NOTIFICATION to sender purposes
404campaign_not_foundCampaign id does not exist for this handleCreate or correct the campaign id
404email_template_not_foundTemplate id does not existCreate or correct the template id
409email_template_not_activeTemplate exists but is paused/inactiveActivate or update the template
400invalid_triggerCampaign email trigger is invalidUse LEAD_CAPTURED, LEAD_CAPTURED_DELAYED, or CONVERSION
400delay_minutes_required_for_delayed_triggerDelayed trigger is missing delayProvide delayMinutes
400delay_minutes_below_minimumDelay is shorter than 15 minutesUse LEAD_CAPTURED or set delay to at least 15
400delay_minutes_above_maximumDelay is longer than 30 daysUse a delay no greater than 43200
409version_conflictRule was edited since the caller read itRe-read and retry with latest expectedVersion
400consent_attestation_requiredDirect send did not attest recipient consentSet consentAttestation: true
409email_recipient_suppressedRecipient is suppressed for this tenantDo not retry until suppression is resolved
429email_quota_exceededTenant email quota is exhaustedRetry after quota reset or reduce volume
503transactional_email_queue_unavailableDelivery queue is not configured or unavailableCheck target environment health

Validation Checklist For External Developers

Before enabling automation for a customer:

  1. Confirm GET /v2/account/domains/{domain}/email-identity returns identity.status = "READY".
  2. Confirm GET /v2/handles/{handle}/email/senders returns the selected sender with enabled = true, status = "READY", and the required purpose.
  3. Confirm GET /v2/handles/{handle}/email/templates returns the selected active template.
  4. Queue one direct test email with a unique idempotencyKey.
  5. Create a test campaign email rule on a test campaign.
  6. Trigger a test lead or conversion event.
  7. Confirm a message appears under GET /v2/handles/{handle}/email/messages.
  8. Confirm events show SENT or a specific denial/failure reason.

Security Guidance

  • Do not expose JWTs in browser logs, server logs, analytics payloads, or screenshots.
  • Do not store user JWTs as permanent credentials. Treat them as session credentials and rotate/refresh through the product's normal auth flow.
  • Do not use PATs for current email routes. They are not accepted on this surface.
  • Do not write directly to DynamoDB tables. The APIs perform handle access, sender purpose, identity readiness, suppression, quota, and idempotency checks.
  • For external BFFs, proxy only an allowlist of the routes in this document and preserve upstream status codes and error codes.
  • For unattended server-to-server email automation, request a new 10xDotIn public PAT wrapper design instead of trying to reuse internal JWT-only routes.

Related Guide

For direct one-off email sending examples and message/event inspection, see Email Sending Through 10xDotIn.