AI92 đã ra mắt - chương trình ra mắt thử nghiệm toàn cầu của chúng tôi đang diễn ra: nền tảng đầy đủ mở cửa trên toàn thế giới trong 30 ngày đầu tiên.
Menu tài liệu

Các tài liệu dành cho nhà phát triển này hiện chỉ có bằng tiếng Anh. Mã và hành vi API giống hệt nhau ở mọi khu vực.

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.