AI92 este live - lansarea noastră soft globală este în desfășurare: platforma completă este deschisă la nivel mondial pentru primele 30 de zile.
Meniu documentație

Această documentație pentru dezvoltatori este disponibilă momentan doar în engleză. Codul și comportamentul API-ului sunt identice în fiecare regiune.

Promote API

Promote (campaign outreach) lets you create campaigns, preview them, and send across channels with per-message pricing. Email sends are per-recipient via POST /v1/campaigns/{campaign_id}/send (there is no generic outreach/dispatch route). Routes are served under /v1/campaigns and backed by module-BDE and module-J.

Authentication

Authorization: Bearer ai92_live_<key>     # production
Authorization: Bearer ai92_test_<key>     # sandbox

Mutating requests support Idempotency-Key and are brand-gated.

Per-channel send pricing

The cost of POST /v1/campaigns/{id}/send is cost_per_message × messages_sent:

ChannelCost / message
email1 credit
whatsapp2 credits
social_media2 credits
sms_na (North America SMS)3 credits
sms_intl (international SMS)6 credits

Any other channel value is rejected with 422.

Credit costs at a glance

EndpointCost
POST /v1/campaignsFree
GET /v1/campaigns/{id}Free
GET /v1/campaigns/{id}/previewFree
POST /v1/campaigns/{id}/sendPer channel (see table above)
POST /v1/campaigns/upload-list2 cr per 1,000 records (rounded up)

POST /v1/campaigns

Cost: Free

Create a campaign. Creation is free; credits are charged on send.

Auth: Bearer

FieldTypeRequiredDescription
brand_idstringYesBrand the campaign belongs to.
namestringYesCampaign name. Length 1128.
channelsstring[]NoChannels the campaign targets. Default [].

Request

bash
curl https://api.ai92.ai/v1/campaigns \
  -H "Authorization: Bearer ai92_test_51a9c0de…" \
  -H "Content-Type: application/json" \
  -d '{"brand_id": "acme", "name": "Spring launch", "channels": ["email", "whatsapp"]}'

Response 200 OK

json
{
  "campaign_id": "camp_77a2",
  "brand_id": "acme",
  "name": "Spring launch",
  "channels": ["email", "whatsapp"],
  "status": "draft"
}

GET /v1/campaigns/{campaign_id}

Cost: Free

Retrieve a campaign by id.

Auth: Bearer

ParameterInTypeRequiredDescription
campaign_idpathstringYesThe campaign id.

Request

bash
curl https://api.ai92.ai/v1/campaigns/camp_77a2 \
  -H "Authorization: Bearer ai92_test_51a9c0de…"

Response 200 OK

json
{
  "campaign_id": "camp_77a2",
  "brand_id": "acme",
  "name": "Spring launch",
  "channels": ["email", "whatsapp"],
  "status": "draft"
}

GET /v1/campaigns/{campaign_id}/preview

Cost: Free

Render a preview of the campaign before sending.

Auth: Bearer

ParameterInTypeRequiredDescription
campaign_idpathstringYesThe campaign id.

Request

bash
curl https://api.ai92.ai/v1/campaigns/camp_77a2/preview \
  -H "Authorization: Bearer ai92_test_51a9c0de…"

Response 200 OK

json
{
  "campaign_id": "camp_77a2",
  "subject": "Meet the Spring lineup",
  "preview_html": "<html>…</html>",
  "estimated_recipients": 4200
}

POST /v1/campaigns/{campaign_id}/send

Cost: Per channel — cost_per_message × messages_sent (see pricing table)

Send a campaign message. This is the correct send endpoint — there is no POST /v1/outreach/dispatch route.

Email is per-recipient. For the email channel there is no bulk-list concept: each call sends to exactly one recipient, and you supply the message subject and body inline. Loop the call to reach multiple people. Sending without a recipient returns 422 USE_SINGLE_RECIPIENT. Broadcast (list-wide) delivery is only available on the social_media channel.

send_mode does not control broadcast; it controls the approval workflowauto sends immediately, otherwise the message enters manual review (see PATCH /v1/outreach/send-mode).

Auth: Bearer

FieldInTypeRequiredDescription
campaign_idpathstringYesThe campaign to send.
brand_idbodystringYesThe brand the campaign belongs to.
recipientbodystringYes (email)The single recipient address. Required for email; omitting it returns 422 USE_SINGLE_RECIPIENT.
subjectbodystringYes (email)Email subject line.
bodybodystringYes (email)Email body content.
channelbodystringNoOne of email, whatsapp, social_media, sms_na, sms_intl. Default email.
send_modebodystringNoApproval workflow: auto (send now) or manual review. Not a broadcast switch.

Request

bash
curl https://api.ai92.ai/v1/campaigns/camp_77a2/send \
  -H "Authorization: Bearer ai92_test_51a9c0de…" \
  -H "Content-Type: application/json" \
  -d '{"brand_id": "acme", "recipient": "[email protected]", "subject": "Your subject line", "body": "Email body content"}'

Response 200 OK

json
{
  "campaign_id": "camp_77a2",
  "recipient": "[email protected]",
  "channel": "email",
  "status": "sent",
  "credits_charged": 1,
  "balance_after": 1499
}

Errors

StatusCodeWhen
422USE_SINGLE_RECIPIENTemail send with no recipient (email is per-recipient; loop the call).
402INSUFFICIENT_CREDITSCannot reserve the required credits.
402RESERVATION_REJECTEDReservation rejected (e.g. per-key spending limit).
422(validation)channel is not a supported channel.
503BACKEND_DISPATCH_FAILEDBackend dispatch failed; credits fully refunded.

No campaign analytics/queue endpoints. GET /v1/campaigns/{id}/analytics, GET /v1/campaigns/{id}/stats, and GET /v1/outreach/dispatch-queue do not exist (404). For outreach state and feature flags use GET /v1/outreach/data; for individual async jobs poll GET /v1/jobs/{job_id}.


POST /v1/campaigns/upload-list

Cost: 2 credits per 1,000 records (rounded up per 1K pack)

Upload a contact list. Email validation is bundled at no extra charge when validate_emails=true. Cost = ceil(record_count / 1000) * 2.

Auth: Bearer

FieldTypeRequiredDescription
list_namestringYesList name. Length 1128.
record_countintegerYesNumber of records (>= 1). Drives the cost.
source_formatstringNocsv (default), json, or crm.
validate_emailsbooleanNoBundled email validation. Default true.

Request

bash
curl https://api.ai92.ai/v1/campaigns/upload-list \
  -H "Authorization: Bearer ai92_test_51a9c0de…" \
  -H "Content-Type: application/json" \
  -d '{"list_name": "Q3 leads", "record_count": 2500, "source_format": "csv", "validate_emails": true}'

Response 200 OK

json
{
  "list_id": "list_3a9c",
  "list_name": "Q3 leads",
  "record_count": 2500,
  "validated": true,
  "credits_consumed": 6
}

Errors

StatusCodeWhen
402INSUFFICIENT_CREDITSBalance below the computed cost.