Documentation overview

API & Integrations

Everything programmatic lives behind one kind of credential: an API key from Settings → API keys (/settings/api), scoped to exactly what it may do. Keys are server-to-server credentials – never ship one in browser code, a mobile app, or anything a customer can inspect.

Authentication

Every request carries the key in a header – either works:

text
Authorization: Bearer theaicmo_...
X-Api-Key: theaicmo_...

Keys are shown once at creation. Each key carries scopes (ticked when you create it) and per-minute/per-day rate limits; 429 responses include a Retry-After header.

Send a service message

Scope: send:transactional. Receipts, password resets, notifications – delivered on your transactional identity and never blocked by marketing opt-outs (a receipt is not a promotion).

bash
curl -X POST https://theaicmo.com/api/send \
  -H "X-Api-Key: theaicmo_..." \
  -H "Content-Type: application/json" \
  -d '{
    "channel": "email",
    "to": "customer@example.com",
    "subject": "Your order shipped",
    "html": "<p>It is on the way.</p>",
    "idempotency_key": "order-1042-shipped"
  }'

Parameters

FieldNotes
channelemail, sms, whatsapp, push, or inbox
toThe recipient – email address or E.164 phone, per channel
subjectEmail only; optional when a library_item_id carries one
html / textInline email content (either or both)
library_item_idSend an email built in the platform instead of inline content – see below
external_idYour own customer id, used for contact matching and suppression
categoryreceipt, order, delivery, payout, security, account, support, legal, other
client_idWhich business profile sends – required when the key isn't bound to one and the account has several
idempotency_keyExactly-once: the same key replays the original result, never a second send
allow_unknowntrue sends to a recipient who is not a contact yet – see below

Sends go to known customers by default. The recipient must match a contact on the business profile (by email, phone, or external_id); anyone else answers 403 unknown_recipient. For flows where the send legitimately precedes the contact record – a brand-new customer's first receipt or OTP – pass "allow_unknown": true to override for that one request:

bash
curl -X POST https://theaicmo.com/api/send \
  -H "X-Api-Key: theaicmo_..." \
  -H "Content-Type: application/json" \
  -d '{
    "channel": "email",
    "to": "brand-new-customer@example.com",
    "subject": "Welcome – your account is ready",
    "html": "<p>Your login is ready.</p>",
    "allow_unknown": true,
    "idempotency_key": "signup-8812-welcome"
  }'

Blocked lists, hard suppressions and GDPR erasures apply either way: an identity erased on request answers 410 identity_erased on every channel, override or not.

Send an email from your library

Emails you built in the platform – the email designer, the campaign generator, journey drafts – live in your library and can be sent by reference instead of pasting HTML:

bash
curl -X POST https://theaicmo.com/api/send \
  -H "X-Api-Key: theaicmo_..." \
  -H "Content-Type: application/json" \
  -d '{
    "channel": "email",
    "to": "customer@example.com",
    "library_item_id": "<the library item id>",
    "idempotency_key": "welcome-cust-8812"
  }'
  • The item's own subject line is used when it carries one; a subject in the request overrides it. Provide one or the other.
  • Personalization renders for the recipient exactly as a journey send would render it – {{p.*}} tokens and survey links resolve to this person before delivery.
  • Brand-locked. The item must belong to the same business profile the key resolves to; anything else is refused with 403 wrong_profile. Accounts with several profiles pass client_id explicitly. A key bound to one brand can never send another brand's asset.
  • Pass either library_item_id or inline html/text – not both.
  • This endpoint stays service-only. An item sent by reference must still be a service message; the content check flags marketing copy riding a service send, exactly as it does for inline content.

The item id is shown on the item's detail panel in the library ("API id" – click to copy).

Trigger a journey

Scope: journeys:trigger. Start a published journey for one person from your own systems – "order shipped", "deposit made", "ticket resolved".

bash
curl -X POST https://theaicmo.com/api/journeys/trigger \
  -H "X-Api-Key: theaicmo_..." \
  -H "Content-Type: application/json" \
  -d '{
    "journey_id": "<the journey id>",
    "email": "customer@example.com",
    "event": { "order_number": "1042", "amount": 89.90 },
    "idempotency_key": "order-1042-shipped"
  }'

Event properties (up to 20) reach your message copy as personalization. Every entry door still applies: suppression, contact status, and the journey's own re-entry rules. The journey's id and a ready-made curl live on the journey's trigger settings in the builder.

Loyalty: balance, rewards, redemption

Scope: loyalty. Render points and tier inside your product, list the rewards shop, and redeem – full walkthrough in the Loyalty Program guide.

bash
curl -H "X-Api-Key: theaicmo_..." \
  "https://theaicmo.com/api/loyalty/balance?identity=customer@example.com"

Redemptions are idempotent (same idempotency_key returns the original receipt) and can never overdraw a balance.

Run a tool

Scope: tools:execute. Any generation tool, programmatically – same tools, same credits as in the product.

bash
curl -X POST https://theaicmo.com/api/execute-tool-api \
  -H "Authorization: Bearer theaicmo_..." \
  -H "Content-Type: application/json" \
  -d '{
    "tool_id": "social-post-generator",
    "parameters": {
      "productName": "Aurora Coffee",
      "platform": "linkedin",
      "variations": 2
    }
  }'

The response carries the generated output plus credits_used and credits_remaining. Tool ids and per-tool credit prices are listed on each tool's page in the product.

Errors

StatusMeaning
401Missing or invalid key
402Insufficient credits (tools) or insufficient points (loyalty)
403Key lacks the required scope, the resource belongs to a different business profile (wrong_profile), or the recipient is not a known contact (unknown_recipient – see allow_unknown)
404Resource not found or not yours
409Idempotency conflict – same key, different payload
410Identity erased on request (GDPR) – cannot be messaged or enrolled
422No verified sending identity, or the referenced library item has no sendable content
429Rate limited – honor Retry-After

Error bodies are JSON with a stable error code and a human message.