10xDotIn Developer Docs

Email Sending Through 10xDotIn

Configure a verified sender, create templates, queue outbound messages, and inspect delivery events through the 10x API.

Email Sending Through 10xDotIn

Use 10xDotIn email APIs to send handle-owned transactional or newsletter-style messages from a verified custom domain. The API stores the message, enqueues delivery, and exposes message status plus provider delivery events for troubleshooting.

Prerequisites

  • A 10x handle where your user has OPERATOR or owner access.
  • A custom domain attached to the account.
  • The domain email identity is READY.
  • A sender profile using one of the approved local parts: noreply, notifications, calendar, support, or hello.
  • Recipient consent for every recipient in the send request.

Endpoint Summary

JobMethod and pathAuth
Check domain email identityGET /v2/account/domains/{domain}/email-identityJWT
Reconcile domain email identityPOST /v2/account/domains/{domain}/email-identity/reconcileJWT
List sender profilesGET /v2/handles/{handle}/email/sendersJWT
Create or update sender profilePUT /v2/handles/{handle}/email/senders/{senderId}JWT
List templatesGET /v2/handles/{handle}/email/templatesJWT
Create templatePOST /v2/handles/{handle}/email/templatesJWT
Update templatePUT /v2/handles/{handle}/email/templates/{templateId}JWT
Send messagePOST /v2/handles/{handle}/email/messagesJWT
List messagesGET /v2/handles/{handle}/email/messagesJWT
Get message detailsGET /v2/handles/{handle}/email/messages/{messageId}JWT
List delivery eventsGET /v2/handles/{handle}/email/eventsJWT

Basic Flow

  1. Verify the domain email identity

    Check the domain email identity and reconcile it until the identity reports READY.

  2. Create a sender profile

    Create a sender such as support@example.com or notifications@example.com.

  3. Choose raw or template mode

    Send raw subject plus text or html, or create a reusable template and send with templateId.

  4. Queue the message

    Call POST /v2/handles/{handle}/email/messages with an idempotency key and consent attestation.

  5. Inspect status and events

    Poll the message or event endpoints for QUEUED, SENT, delivery, bounce, complaint, or failure state.

Auth Setup

Set these variables in your local shell:

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

Pass the JWT on every request:

-H "Authorization: Bearer ${TENX_JWT}"

Need help with JWTs? See API Auth and Error Model and JWT vs PAT: When to Use Each.

1. Verify Domain Email Identity

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

Expected 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 changes:

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

The reconcile endpoint returns 202 when the verification job is accepted. Re-check the identity after DNS propagation.

2. Create a Sender Profile

senderId must start with sender_. The localPart must be one of the approved values listed in prerequisites.

curl -sS -X PUT "${TENX_API_BASE}/v2/handles/${TENX_HANDLE}/email/senders/sender_support" \
  -H "Authorization: Bearer ${TENX_JWT}" \
  -H "Content-Type: application/json" \
  -d '{
    "domain": "example.com",
    "localPart": "support",
    "displayName": "Acme Support",
    "replyTo": "support@example.com",
    "purposes": ["TRANSACTIONAL_API", "PRODUCT_NOTIFICATION"],
    "enabled": true
  }'

Response:

{
  "sender": {
    "senderId": "sender_support",
    "domain": "example.com",
    "localPart": "support",
    "fromEmail": "support@example.com",
    "displayName": "Acme Support",
    "replyTo": "support@example.com",
    "purposes": ["TRANSACTIONAL_API", "PRODUCT_NOTIFICATION"],
    "enabled": true,
    "status": "READY"
  }
}

Valid purposes are:

PurposeUse it for
TRANSACTIONAL_APIReceipts, account notices, workflow-triggered messages
PRODUCT_NOTIFICATIONProduct, lifecycle, and handle-owner notifications
CALENDARCalendar-oriented messages or invites

3. Send a Raw Message

Use raw mode when the integration supplies the subject and body 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_support",
    "to": ["buyer@example.com"],
    "purpose": "TRANSACTIONAL_API",
    "idempotencyKey": "receipt-ord_12345",
    "consentAttestation": true,
    "subject": "Your receipt from Acme",
    "html": "<p>Thanks for your order.</p>",
    "text": "Thanks for your order."
  }'

Accepted response:

{
  "message": {
    "messageId": "msg_abc123",
    "handle": "acme",
    "status": "QUEUED",
    "purpose": "TRANSACTIONAL_API",
    "senderId": "sender_support",
    "recipientCount": 1,
    "fromEmail": "Acme Support <support@example.com>",
    "createdAt": "2026-05-30T08:00:00.000Z"
  }
}

The endpoint returns 202 after the message is stored and queued. Delivery happens asynchronously.

4. Create and Use a Template

Create a reusable template when multiple messages share copy and layout.

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_receipt",
    "name": "Receipt",
    "subject": "Receipt for {{orderId}}",
    "html": "<p>Thanks, {{firstName}}. Your order {{orderId}} is confirmed.</p>",
    "text": "Thanks, {{firstName}}. Your order {{orderId}} is confirmed."
  }'

Then send with the template:

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_support",
    "to": ["buyer@example.com"],
    "purpose": "TRANSACTIONAL_API",
    "idempotencyKey": "receipt-ord_12346",
    "consentAttestation": true,
    "templateId": "tmpl_receipt",
    "variables": {
      "firstName": "Asha",
      "orderId": "ord_12346"
    }
  }'

Template ids must start with tmpl_. If you omit templateVersion, the active template version is used.

5. Inspect Messages and Events

List recent messages:

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

limit defaults to 25 and is capped at 50. Use nextCursor from the response to fetch the next page:

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

Get one message and its timeline:

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

List events for a message:

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

List events by recipient:

curl -sS "${TENX_API_BASE}/v2/handles/${TENX_HANDLE}/email/events?recipient=buyer@example.com" \
  -H "Authorization: Bearer ${TENX_JWT}"

List events by purpose and time window:

curl -sS "${TENX_API_BASE}/v2/handles/${TENX_HANDLE}/email/events?purpose=TRANSACTIONAL_API&since=2026-05-30T00:00:00.000Z" \
  -H "Authorization: Bearer ${TENX_JWT}"
  • idempotencyKey is required for every send. Reusing the same key for the same handle returns 409 duplicate_idempotency_key.
  • to accepts up to 10 unique email addresses per request.
  • consentAttestation must be true. If it is missing or false, the API returns 400 consent_attestation_required.
  • Raw sends require subject and at least one of html or text.
  • Template sends require an active template with the requested templateId and optional templateVersion.
  • Messages are subject to quota and suppression checks before they are queued.

Common Errors

ErrorMeaningFix
domain_email_identity_not_readyDomain is not ready to send mailCheck DNS records and run identity reconcile
sender_profile_not_foundsenderId does not exist on this handleCreate or correct the sender profile
sender_profile_not_readySender is disabled or not readyEnable the sender or choose a ready sender
sender_purpose_not_allowedSender purpose allowlist does not include the requested purposeUpdate sender purposes or change the message purpose
email_recipient_suppressedRecipient is blocked by tenant suppression stateDo not retry until suppression is resolved
email_quota_exceededDaily or per-minute quota is exhaustedWait for quota reset or reduce volume
duplicate_idempotency_keyThe idempotency key has already been usedReuse only for safe retry checks; use a new key for a new message
invalid_email_contentRaw send is missing subject or bodyProvide subject and text or html
email_template_not_foundThe requested template does not existCreate the template or correct templateId
transactional_email_queue_unavailableDelivery queue is unavailable in the environmentRetry later or contact support
  1. Reconcile and verify the domain before enabling sending in your app.
  2. Create one sender profile per sender role, for example sender_support and sender_notifications.
  3. Use templates for repeated lifecycle messages.
  4. Generate stable idempotency keys from your own business object ids, such as receipt-${orderId}.
  5. Treat 202 QUEUED as accepted for delivery, not proof of inbox delivery.
  6. Store messageId and inspect events when debugging bounces, complaints, or provider failures.
  7. Use tracked 10x links in email CTAs when you need click and conversion attribution.

Updated Jun 19, 2026