API reference
Connect your app to 1Confirmed. Send messages, schedule broadcasts, and manage your account with our REST API.
https://1confirmed.com/api/v1
Identifiers in v1 Use IDs from this version
Account API record identifiers use numeric IDs. Some integrations and AI Flow selections already use UUIDs; follow the field-specific notes. V1 template sender choices return group_id; v2 returns account_id.
Switch versions above to update paths, field descriptions and examples. Only documented methods are described here; a version prefix does not make other routes available. Read the migration guide before changing an existing integration.
Authentication
Start with a login request, then send your access token with every protected request. Premium accounts can also register users with that token. Non-premium accounts need a registration token issued by an administrator.
Log in with your credentials
Send your email and password to Login. No registration token or Turnstile is required. Complete two-factor authentication if enabled.
1 per second · 5 per minute · 20 per 15 minutes per IPUse your access token
Copy the token returned by Login into the Authorization header. Use it to access your account’s protected endpoints.
Need to create accounts?
Restricted accessThe Register endpoint accepts your normal API token if your account has an active premium subscription. Otherwise, an administrator must issue you a dedicated registration token.
Registration API access# Get your account details curl https://1confirmed.com/api/v1/user \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ -H "Accept: application/json"
YOUR_ACCESS_TOKEN with your login token.Request headers
- Authorization
Bearer {token}Required for protected endpoints- Content-Type
application/jsonFor requests with a JSON body- Accept
application/json
Login
Get an access token for an existing account.
/api/v1/login
No registration token or turnstile_token is required.
Phone verification must be complete. External clients must send two_factor_code in the login request when two-factor verification is enabled; an external request without the code fails with HTTP 404.
Invalid credentials, unverified phone and invalid two-factor codes return HTTP 404 with {success: false, message}. Invalid request fields return 422. Rate limits return 429 with Retry-After in seconds.
Login limits are shared per client IP across API versions and Shopify login: 1 per second · 5 per minute · 20 per 15 minutes. Successful, failed and invalid attempts count.
emailRequired- stringValid account email address.
passwordRequired- stringAccount password.
two_factor_codeConditional- stringExactly 6 characters. Include a valid authenticator code when two-factor verification is enabled.
curl --request POST 'https://1confirmed.com/api/v1/login' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"email": "[email protected]",
"password": "YOUR_PASSWORD"
}'Response
{
"success": true,
"data": {
"id": 7,
"name": "Sam Smith",
"email": "[email protected]",
"phone": "212600000000",
"shop_domain": null,
"auth_type": null,
"language": "en",
"phone_verified_at": "2026-09-22T10:00:00.000000Z",
"two_factor_enabled": false,
"two_factor_verified": false,
"first_message_wizard_completed": false,
"roles": [
"client"
],
"credit": {
"id": 8,
"credit": 100
},
"subscription": null,
"cr_account": null,
"custom_credit": {},
"accounts": [],
"token": "YOUR_NEW_ACCESS_TOKEN"
},
"message": "Example response message"
}{
"success": true,
"data": {
"id": 7,
"name": "Sam Smith",
"email": "[email protected]",
"phone": "212600000000",
"shop_domain": null,
"auth_type": null,
"language": "en",
"phone_verified_at": "2026-09-22T10:00:00.000000Z",
"two_factor_enabled": false,
"two_factor_verified": false,
"first_message_wizard_completed": false,
"roles": [
"client"
],
"credit": {
"id": 8,
"credit": 100
},
"subscription": {
"price": 100,
"start_date": "01/09/2026",
"end_date": "01/10/2026",
"status": "active",
"is_expired": false,
"auto_renewable": false
},
"cr_account": {
"id": 52,
"name": "Example account"
},
"custom_credit": {},
"accounts": [
{
"id": 53,
"name": "Example sender",
"bs_id": "Example provider identifier",
"catalog_id": null
}
],
"token": "YOUR_NEW_ACCESS_TOKEN"
},
"message": "Example response message"
}Register
Create an account using your premium account API token, or a registration token issued by an administrator.
/api/v1/register
Authorization: Bearer YOUR_TOKEN.
Registration API access ↗
Both token owners must have an active account and a verified phone. Admin approval alone does not make a non-premium account’s normal API token eligible; use the dedicated token issued by the administrator.
No turnstile_token. The new account must verify its phone before using protected endpoints.
Missing, invalid, expired, revoked or ineligible tokens return 401. Invalid fields return 422. Registration failures return 404. Rate limits return 429 with Retry-After.
Registration is limited to 5 attempts per minute and 100 per day per token owner; per-IP limits also apply.
nameRequired- string2–50 Latin letters/spaces after normalization. Prohibited names and unsafe content are rejected.
emailRequired- stringUnique email with valid syntax and DNS, maximum 255 characters. Prohibited values are rejected.
phoneRequired- stringUnique, valid international phone number. Formatting is stripped; national numbers are normalized using country_code.
country_codeRequired- stringExisting two-letter uppercase country code, for example MA.
passwordRequired- string8–255 characters. At least one lowercase letter, uppercase letter, digit and symbol from @$!%*?&#. Only these symbols and Latin letters/digits are allowed; unsafe patterns are rejected.
c_passwordRequired- stringMust match password.
curl --request POST 'https://1confirmed.com/api/v1/register' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer YOUR_PREMIUM_API_OR_ADMIN_ISSUED_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
"name": "Sam Smith",
"email": "[email protected]",
"phone": "212600000000",
"country_code": "MA",
"password": "CHANGEme123!",
"c_password": "CHANGEme123!"
}'Response
{
"success": true,
"data": {
"id": 7,
"name": "Sam Smith",
"email": "[email protected]",
"phone": "212600000000",
"shop_domain": null,
"auth_type": null,
"language": "en",
"phone_verified_at": null,
"two_factor_enabled": false,
"two_factor_verified": false,
"first_message_wizard_completed": false,
"roles": [
"client"
],
"credit": {
"id": 8,
"credit": 100
},
"subscription": null,
"cr_account": null,
"custom_credit": {},
"accounts": [],
"token": "YOUR_NEW_ACCESS_TOKEN"
},
"message": "Example response message"
}User info
Read the authenticated account.
/api/v1/user
No request body or query parameters.
curl --request GET 'https://1confirmed.com/api/v1/user' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
Response
{
"success": true,
"data": {
"id": 7,
"name": "Sam Smith",
"email": "[email protected]",
"phone": "212600000000",
"shop_domain": null,
"auth_type": null,
"language": "en",
"phone_verified_at": "2026-09-22T10:00:00.000000Z",
"two_factor_enabled": false,
"two_factor_verified": false,
"first_message_wizard_completed": false,
"roles": [
"client"
],
"credit": {
"id": 8,
"credit": 100
},
"subscription": null,
"cr_account": null,
"custom_credit": {}
},
"message": "Example response message"
}{
"success": true,
"data": {
"id": 7,
"name": "Sam Smith",
"email": "[email protected]",
"phone": "212600000000",
"shop_domain": null,
"auth_type": null,
"language": "en",
"phone_verified_at": "2026-09-22T10:00:00.000000Z",
"two_factor_enabled": false,
"two_factor_verified": false,
"first_message_wizard_completed": false,
"roles": [
"client"
],
"credit": {
"id": 8,
"credit": 100
},
"subscription": {
"price": 100,
"start_date": "01/09/2026",
"end_date": "01/10/2026",
"status": "active",
"is_expired": false,
"auto_renewable": false
},
"cr_account": {
"id": 52,
"name": "Example account"
},
"custom_credit": {}
},
"message": "Example response message"
}Categories
List template categories.
/api/v1/categories
No request body or query parameters.
curl --request GET 'https://1confirmed.com/api/v1/categories' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
Response
{
"success": true,
"data": [
{
"id": 42,
"name": "Marketing"
}
],
"message": "Example response message"
}Templates
Find templates and their variable definitions.
/api/v1/templates
V1 includes active public templates and your attached private templates, unless your account is configured for private templates only.
language_idRequired query- integerExisting language ID; always numeric.
is_broadcastRequired query- 0 or 1Use 1 to append recipient phone and any file URL variable to the returned variables.
nameOptional query- stringCase-insensitive partial match on the display name.
category_idOptional query- integer IDFilter by category.
has_flow_formOptional query- 0 or 1Filter by this template capability.
has_carouselOptional query- 0 or 1Filter by this template capability.
has_flowOptional query- 0 or 1Filter by this template capability.
is_calendarOptional query- 0 or 1Filter by this template capability.
is_otpOptional query- 0 or 1Filter by this template capability.
with_fb_componentsOptional query- query flagPresence includes direct_message and fb_template_components, even if the value is 0.
curl --request GET 'https://1confirmed.com/api/v1/templates' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \ --get \ --data-urlencode 'language_id=1' \ --data-urlencode 'is_broadcast=0'
Response
{
"success": true,
"data": [
{
"id": 42,
"name": "Example template",
"description": "",
"image": "https://example.com/template.png",
"variables": [],
"global_variables": [],
"catch_data": [],
"has_file": false,
"has_flow_form": false,
"has_flow": false,
"is_carousel": false,
"is_calendar": false,
"file_data": null,
"pricing": null
}
],
"message": "Example response message"
}{
"success": true,
"data": [
{
"id": 42,
"name": "Example template",
"description": "",
"image": "https://example.com/template.png",
"variables": [],
"global_variables": [],
"catch_data": [],
"has_file": false,
"has_flow_form": false,
"has_flow": false,
"is_carousel": false,
"is_calendar": false,
"file_data": null,
"pricing": {
"name": "Example category",
"credit": 1
},
"direct_message": false,
"fb_template_components": []
}
],
"message": "Example response message"
}Provider components appear only when the with_fb_components query flag is present. Pricing can be null; it requires pricing to be enabled for both the account and template.
Template variable definitions and file metadata depend on the selected template. They are returned as decoded JSON, not JSON-encoded strings.
Template accounts
Get sender choices for a selected template.
/api/v1/template/accounts
Send messages with template_account_flow_id, not the account/group ID. The sender must be active and its account subscription active.
V1 can include public sender accounts as well as accounts assigned to you.
template_idRequired query- integer IDTemplate returned by Templates.
curl --request GET 'https://1confirmed.com/api/v1/template/accounts' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \ --get \ --data-urlencode 'template_id=42'
Response
{
"success": true,
"data": [
{
"group_id": 52,
"has_form": false,
"template_account_flow_id": 73,
"phone": "212600000000",
"private": true,
"country": {
"id": 9,
"name": "Morocco",
"code": "MA",
"flag": ""
}
}
],
"message": "Example response message"
}Languages
List the language IDs used in requests.
/api/v1/languages
No request body or query parameters.
curl --request GET 'https://1confirmed.com/api/v1/languages' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
Response
{
"success": true,
"data": [
{
"id": 1,
"language": "English",
"flag": ""
}
],
"message": "Example response message"
}Credits
Read the account credit record.
/api/v1/credits
No request body or query parameters.
curl --request GET 'https://1confirmed.com/api/v1/credits' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
Response
{
"success": true,
"data": {
"id": 42,
"credit": 100
},
"message": "Example response message"
}If the account has no credit record, the balance is 0. V2 omits the empty record ID.
Send message
Send one template message or schedule it for later.
/api/v1/messages
Example variables are illustrative. Replace data with the exact variables returned for your template. Replace every example ID and phone number before sending.
Optional Idempotency-Key header: 8–128 letters, digits, dots, colons, underscores or hyphens. Reuse the same key and payload for retries. Invalid keys return 422. Reusing a key with different input returns 409; an operation still being processed can return 202.
Available credit, recipient opt-outs and template/sender access are checked before sending. SMS fallback depends on SMS availability and credit. Accepted WhatsApp sends wait for the configured delay and are checked for delivery; rejected sends can fall back immediately.
nameRequired- stringName for the message/broadcast record.
template_idRequired- integer IDAccessible template ID.
template_account_flow_idRequired- integer IDSubscribed sender flow for the selected template.
phoneRequired- numeric stringRecipient number with country calling code, without punctuation.
country_idOptional- integer IDExisting Country record ID.
dataConditional- objectAll variables and global variables required by the selected template, keyed by variable name. OTP values must contain digits only; URL variables must use http or https.
{file_data.variable}Conditional- file uploadFor templates with has_file, upload under the name in file_data.variable using multipart/form-data.
is_testOptional- booleanFor a file template, a truthy value allows a file URL under file_data.variable instead of an uploaded file.
as_formOptional- presence flagFor a form template, including this field selects form sending. Omit it to disable; even as_form: false counts as present in this endpoint.
delayed_toOptional- date/timeAt least 15 minutes in the future. Include an explicit timezone when using a timezone-aware date.
ai_flow_configOptional- object or JSON stringSelect an owned, published AI Flow. See AI Flow configuration below.
listener_urlOptional- URLReceive broadcast status and contact updates at this URL. See Status listener below.
sms_fallbackOptional- booleanEnable SMS fallback after a WhatsApp attempt. Only for accounts that have bought credits at least once, or premium accounts; free credits cover WhatsApp only, so any other account is refused with 422.
sms_fallback_textConditional- stringRequired when sms_fallback is true or 1. Maximum 640 characters.
sms_fallback_delayOptional- integerSeconds: 30–86400. Default 60.
sms_fallback_fromOptional- stringSender name, maximum 64 characters. Must be a public sender name or one assigned to your account, and enabled; anything else is refused with 422. Omit it to use the default sender name.
sms_fallback_operatorOptional- stringIAM, ORANGE or INWI.
curl --request POST 'https://1confirmed.com/api/v1/messages' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
"name": "Order update",
"template_id": 42,
"template_account_flow_id": 73,
"phone": "212600000000",
"data": {
"customer_name": "Sam"
}
}'Response
{
"data": null,
"message": "Example scheduling message",
"scheduled_for": "2026-09-23 10:00:00",
"broadcast_id": 42,
"message_info_url": "https://example.com/message-status"
}{
"data": null,
"message": "Example delivery pending message",
"status": "delivery_unknown",
"broadcast_id": 42,
"message_info_url": "https://example.com/message-status"
}Immediate sends return the provider result in data. Scheduled sends return scheduled_for; queued carousel responses include queued: true. A 202 response means delivery is still pending.
Provider rejections can return 422. Template data or business-rule failures can return 404.
Send broadcast
Create and queue a broadcast in one request.
/api/v1/send-broadcast
Fetch Templates with is_broadcast=1 first. Replace customer_name with your template variables. Recipient phone values must be digits (an optional leading + is accepted); duplicate phones are rejected unless sending as a form. File templates need their file URL variable in each row.
The follow-up template must be active, accessible and available on the same sender as the primary template. Its mapping must have exactly as many rows as data.data, in original recipient order, with values keyed by variable name. Each required value must be a nonempty scalar, maximum 1000 characters.
Optional Idempotency-Key is supported as for Send message. Queued acceptance does not mean delivery; inspect contacts and status callbacks.
Connector-specific webhook_* and zoho_* fields are described under Result connectors below. They are optional and are separate from listener_url.
nameRequired- stringNonempty broadcast name; the literal string null is rejected.
language_idRequired- integerExisting language ID.
template_idRequired- integer IDAccessible template.
template_account_flow_idRequired- integer IDSubscribed sender flow for that template.
dataRequired- JSON-encoded stringEncode an object with a data array of recipient objects. Each row contains phone and the selected template variables. This field is a string, not a JSON object or array.
global_dataOptional- objectShared template variable values keyed by variable name. Supply values required by the template; OTP globals must be digits and URL globals must be HTTP(S) URLs.
country_idOptional- integer IDExisting Country record.
as_formOptional- booleantrue/false, 1/0, "true"/"false", "on"/"off" are accepted. True requires a form template. Unlike single messages, false disables form sending.
fileOptional- file uploadExcel xlsx/xls source file, using multipart/form-data. data is still required.
saved_list_idOptional- integer IDOwned or shared saved list. data is still required.
delayed_toOptional- stringY-m-d H:i:s in the application timezone, at least 15 minutes in the future. Omit for immediate queuing.
calendar_idConditional- integer IDYour valid calendar for a calendar template.
use_best_timeOptional- booleanUse recipient best-time scheduling.
best_time_fallbackOptional- stringnow or global; controls recipients without their own send time when use_best_time is enabled.
follow_up_configurationOptional- object or JSON stringFinite follow-up. Include hours (integer 1–168), template_id and mapping (one row per recipient in recipient order, keyed by template-variable name; use an empty array for a row with no variables).
follow_up_configuration.hoursConditional- integerRequired with follow_up_configuration. 1–168 hours.
follow_up_configuration.template_idConditional- integer IDRequired with follow_up_configuration. Follow-up template on the same sender.
follow_up_configuration.mappingConditional- array of objectsRequired with follow_up_configuration. At least one row; one row per original recipient, keyed by variable name.
list_nameOptional- stringWhen nonempty, also save a recipient list. Supply json_data alongside it.
json_dataConditional- JSON-encoded stringList contents to persist when list_name is supplied. Separate from the required sending data field.
follow_up_configuration.global_variablesOptional- objectShared follow-up template values. Nonempty scalar values, maximum 1000 characters; OTP and URL rules also apply.
follow_up_configuration.calendar_idConditional- integer IDOwned, valid calendar when the follow-up template is a calendar template.
follow_up_configuration.as_formOptional- booleanSame accepted values as as_form; true requires a follow-up form template.
follow_up_configuration.ai_flow_configOptional- object or JSON stringPublished AI Flow selection for the follow-up.
ai_flow_configOptional- object or JSON stringSelect an owned, published AI Flow. See AI Flow configuration below.
listener_urlOptional- URLReceive broadcast status and contact updates at this URL. See Status listener below.
sms_fallbackOptional- booleanEnable SMS fallback after a WhatsApp attempt. Only for accounts that have bought credits at least once, or premium accounts; free credits cover WhatsApp only, so any other account is refused with 422.
sms_fallback_textConditional- stringRequired when sms_fallback is true or 1. Maximum 640 characters.
sms_fallback_delayOptional- integerSeconds: 30–86400. Default 60.
sms_fallback_fromOptional- stringSender name, maximum 64 characters. Must be a public sender name or one assigned to your account, and enabled; anything else is refused with 422. Omit it to use the default sender name.
sms_fallback_operatorOptional- stringIAM, ORANGE or INWI.
curl --request POST 'https://1confirmed.com/api/v1/send-broadcast' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
"name": "Order updates",
"language_id": 1,
"template_id": 42,
"template_account_flow_id": 73,
"data": "{\"data\":[{\"phone\":\"212600000000\",\"customer_name\":\"Sam\"}]}"
}'Response
{
"success": true,
"data": {
"id": 42,
"sent_at": "2026-09-22",
"name": "Order updates",
"contacts": 1,
"language": "English",
"template": "Example template",
"whatsapp_area": null,
"is_draft": false,
"mapping": null,
"global_data": null,
"confirmations": 0,
"has_file": false,
"is_flow_form": false,
"file": "",
"listener_url": null
},
"message": "Example response message"
}{
"success": true,
"data": {
"id": 42,
"sent_at": "2026-09-22",
"name": "Order updates",
"contacts": 1,
"language": "English",
"template": "Example template",
"whatsapp_area": null,
"is_draft": false,
"mapping": null,
"global_data": null,
"confirmations": 0,
"has_file": false,
"is_flow_form": false,
"file": "",
"listener_url": null,
"follow_up_configuration": {
"hours": 24,
"template_id": 11,
"calendar_id": 12,
"mapping": [
{
"customer_name": "Sam"
}
],
"global_data": [],
"is_flow_form": false
}
},
"message": "Example response message"
}Create draft
Create a draft record. This request does not send messages.
/api/v1/broadcasts
nameRequired- stringBroadcast name.
language_idRequired- integerAn ID returned by Languages. Numeric in both versions.
ai_flow_configOptional- object or JSON stringSelect an owned, published AI Flow. See AI Flow configuration below.
listener_urlOptional- URLReceive broadcast status and contact updates at this URL. See Status listener below.
curl --request POST 'https://1confirmed.com/api/v1/broadcasts' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
"name": "My broadcast",
"language_id": 1
}'Response
{
"success": true,
"data": {
"id": 42,
"sent_at": "2026-09-22",
"name": "Order updates",
"contacts": 0,
"language": null,
"template": null,
"whatsapp_area": null,
"is_draft": true,
"mapping": null,
"global_data": null,
"confirmations": 0,
"has_file": false,
"is_flow_form": false,
"file": "",
"listener_url": null
},
"message": "Example response message"
}Broadcast list
Search your broadcasts by name or template name. Returns 15 records per page.
/api/v1/broadcasts
searchOptional query- stringSearch the records described above.
pageOptional query- integerPage number, starting at 1.
curl --request GET 'https://1confirmed.com/api/v1/broadcasts' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
Response
{
"success": true,
"data": {
"broadcasts": [
{
"id": 42,
"sent_at": "2026-09-22",
"name": "Order updates",
"contacts": 0,
"language": null,
"template": null,
"whatsapp_area": null,
"is_draft": true,
"confirmations": 0,
"has_file": false,
"stop_notifications": 0,
"template_image": "https://example.com/template.png",
"read": 0,
"delivered": 0,
"sent": 0,
"interacted": 0,
"cost": 0,
"file_extension": "",
"status": null,
"in_queue": false,
"reengagement": null,
"delayed_to": null,
"refused": false,
"scheduled_jobs_count": 0,
"cancellation_comment": null
}
],
"pagination": {
"total": 1,
"count": 1,
"per_page": 15,
"next_page_url": null,
"prev_page_url": null,
"current_page": 1,
"total_pages": 1
}
},
"message": "Example response message"
}sent_at is a display label and can describe a scheduled or cancelled broadcast.
Broadcast details
Read a broadcast belonging to your account.
/api/v1/broadcasts/{id}
Replace {id} in the path with the integer ID of the record described below. The cURL example uses an illustrative ID.
broadcastRequired path- integer IDReplace the sample ID with the broadcast ID.
curl --request GET 'https://1confirmed.com/api/v1/broadcasts/123' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
Response
{
"success": true,
"data": {
"id": 42,
"sent_at": "2026-09-22",
"name": "Order updates",
"contacts": 0,
"language": null,
"template": null,
"whatsapp_area": null,
"is_draft": true,
"mapping": null,
"global_data": null,
"confirmations": 0,
"has_file": false,
"is_flow_form": false,
"file": "",
"listener_url": null
},
"message": "Example response message"
}Update draft
Update the name, language, AI Flow or listener on a draft. PATCH is also supported.
/api/v1/broadcasts/{id}
Replace {id} in the path with the integer ID of the record described below. The cURL example uses an illustrative ID.
This endpoint does not reschedule a send. It refuses broadcasts that are no longer drafts. Scheduling changes in the portal are browser-session operations.
nameRequired- stringBroadcast name.
language_idRequired- integerAn ID returned by Languages. Numeric in both versions.
ai_flow_configOptional- object or JSON stringSelect an owned, published AI Flow. See AI Flow configuration below.
listener_urlOptional- URLReceive broadcast status and contact updates at this URL. See Status listener below.
curl --request PUT 'https://1confirmed.com/api/v1/broadcasts/123' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
"name": "Updated broadcast",
"language_id": 1
}'Response
{
"success": true,
"data": {
"id": 42,
"sent_at": "2026-09-22",
"name": "Order updates",
"contacts": 0,
"language": null,
"template": null,
"whatsapp_area": null,
"is_draft": true,
"mapping": null,
"global_data": null,
"confirmations": 0,
"has_file": false,
"is_flow_form": false,
"file": "",
"listener_url": null
},
"message": "Example response message"
}Broadcast contacts
List contacts in one of your broadcasts, 15 per page.
/api/v1/contacts
broadcast_idRequired query- integer IDBroadcast belonging to your account.
follow_upOptional query- 0 or 10 (default) lists primary contacts; 1 lists follow-up contacts.
pageOptional query- integerPage number, starting at 1.
curl --request GET 'https://1confirmed.com/api/v1/contacts' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \ --get \ --data-urlencode 'broadcast_id=123'
Response
{
"success": true,
"data": {
"contacts": [
{
"id": 42,
"phone": "212600000000",
"broadcast_name": "Order updates",
"data": "{\"customer_name\":\"Sam\"}",
"delivery_date": "2026-09-22 10:00:00",
"received_at": "2026-09-22 10:00:00",
"confirmed": true,
"canceled": false,
"interacted": true,
"cost": 1,
"is_sent": true,
"sms_fallback": null,
"reply_at": null,
"statuses": [
{
"id": 16,
"status": "delivered",
"timestamp": "1790071200"
}
]
}
],
"pagination": {
"total": 1,
"count": 1,
"per_page": 15,
"next_page_url": null,
"prev_page_url": null,
"current_page": 1,
"total_pages": 1
}
},
"message": "Example response message"
}Filter contacts
Search contacts in your broadcasts, 20 per page.
/api/v1/filter/contacts/segments
broadcast_idOptional query- integer IDLimit to one broadcast.
statusOptional query- stringMatch a stored message status, for example delivered or read.
phoneOptional query- stringPartial phone-number match.
is_sentOptional query- booleanFilter by this value; use 1 or 0.
confirmedOptional query- booleanFilter by this value; use 1 or 0.
interactedOptional query- booleanFilter by this value; use 1 or 0.
canceledOptional query- booleanFilter by this value; use 1 or 0.
has_dataOptional query- booleanFilter by this value; use 1 or 0.
date_range[]Optional query- two datesStart and end bounds for contact created_at.
pageOptional query- integerPage number, starting at 1.
curl --request GET 'https://1confirmed.com/api/v1/filter/contacts/segments' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \ --get \ --data-urlencode 'broadcast_id=123'
Response
{
"success": true,
"data": {
"contacts": [
{
"id": 42,
"phone": "212600000000",
"broadcast_name": "Order updates",
"data": "{\"customer_name\":\"Sam\"}",
"delivery_date": "2026-09-22 10:00:00",
"received_at": "2026-09-22 10:00:00",
"confirmed": true,
"canceled": false,
"interacted": true,
"cost": 1,
"is_sent": true,
"sms_fallback": null,
"reply_at": null,
"statuses": [
{
"id": 16,
"status": "delivered",
"timestamp": "1790071200"
}
]
}
],
"pagination": {
"total": 1,
"count": 1,
"per_page": 20,
"next_page_url": null,
"prev_page_url": null,
"current_page": 1,
"total_pages": 1
}
},
"message": "Example response message"
}Blacklist
Read opt-outs associated with your broadcasts, account memberships or manual blocks. Search phone or broadcast name; 10 per page.
/api/v1/black-list
searchOptional query- stringSearch the records described above.
pageOptional query- integerPage number, starting at 1.
curl --request GET 'https://1confirmed.com/api/v1/black-list' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
Response
{
"success": true,
"data": {
"list": [
{
"id": 42,
"contact_phone": "212600000000",
"broadcast": "Order updates",
"sender": "Example sender",
"account": "Example account",
"created_at": "2026-09-22 10:00:00"
}
],
"pagination": {
"total": 1,
"count": 1,
"per_page": 10,
"next_page_url": null,
"prev_page_url": null,
"current_page": 1,
"total_pages": 1
}
},
"message": "Example response message"
}Add to blacklist
Create a manual account-specific block.
/api/v1/black-list
phoneRequired- stringMaximum 15 characters. An existing manual block for this phone/account is rejected.
cr_account_idRequired- integer IDAccount assigned to you.
curl --request POST 'https://1confirmed.com/api/v1/black-list' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
"phone": "212600000000",
"cr_account_id": 52
}'Response
{
"success": true,
"data": {
"id": 42,
"phone": "212600000000",
"for_all": 2
},
"message": "Example response message"
}Confirmations
List paid, confirmed contacts in your broadcasts. Search phone or broadcast name; 15 per page.
/api/v1/confirmations
searchOptional query- stringSearch the records described above.
pageOptional query- integerPage number, starting at 1.
curl --request GET 'https://1confirmed.com/api/v1/confirmations' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
Response
{
"success": true,
"data": {
"paid_messages": {
"confirmations": [
{
"id": 42,
"phone": "212600000000",
"broadcast_name": "Order updates",
"data": "{\"customer_name\":\"Sam\"}",
"delivery_date": "2026-09-22 10:00:00",
"received_at": "2026-09-22 10:00:00",
"confirmed": true,
"canceled": false,
"statuses": [
{
"id": 16,
"status": "delivered",
"timestamp": "1790071200"
}
]
}
],
"pagination": {
"total": 1,
"count": 1,
"per_page": 15,
"next_page_url": null,
"prev_page_url": null,
"current_page": 1,
"total_pages": 1
}
},
"unpaid_messages": {
"messages_unpaid_count": 0,
"messages_unpaid_credit": 0
}
},
"message": "Example response message"
}Confirmation listener
Read your account-level confirmation listener.
/api/v1/confirmation/listeners
No request body or query parameters.
curl --request GET 'https://1confirmed.com/api/v1/confirmation/listeners' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
Response
{
"success": true,
"data": {
"target_url": "https://example.com/confirmations",
"active": true,
"updated_at": "2026-09-22 10:00:00"
},
"message": "Example response message"
}An account without a configured listener can return 404.
Save confirmation listener
Create or update the listener for your account.
/api/v1/confirmation/listeners
target_urlRequired- URLCallback destination.
activeOptional- 0 or 1Whether the listener is active.
curl --request POST 'https://1confirmed.com/api/v1/confirmation/listeners' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
"target_url": "https://example.com/confirmations",
"active": 1
}'Response
{
"success": true,
"data": {
"target_url": "https://example.com/confirmations",
"active": true,
"updated_at": "2026-09-22 10:00:00"
},
"message": "Example response message"
}Payments
List your payments, newest first, 10 per page.
/api/v1/payments
pageOptional query- integerPage number, starting at 1.
curl --request GET 'https://1confirmed.com/api/v1/payments' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
Response
{
"success": true,
"data": {
"payments": [
{
"id": 42,
"price": 100,
"credit": 100,
"user_id": 7,
"is_paid": true,
"method": "Stripe",
"expired": false,
"created_at": "2026-09-22 10:00:00",
"updated_at": "2026-09-22 10:00:00"
}
],
"pagination": {
"total": 1,
"count": 1,
"per_page": 10,
"next_page_url": null,
"prev_page_url": null,
"current_page": 1,
"total_pages": 1
}
},
"message": "Example response message"
}Create payment
Create a checkout session for a credit purchase.
/api/v1/payments
The sample credit amount is illustrative; use your account purchase limits. The server calculates price.
creditRequired- numberAt least the configured minimum purchase, and no more than the configured maximum when one is set. Limits can differ per account.
methodRequired- stringStripe or Paypal, exactly as written. The selected gateway must be available.
curl --request POST 'https://1confirmed.com/api/v1/payments' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
"credit": 100,
"method": "Stripe"
}'Response
{
"success": true,
"data": {
"url": "https://example.com/provider-checkout"
},
"message": "Example response message"
}Open the returned URL to complete checkout. Creating the checkout does not mean payment has completed.
Connections
Read your login history, newest first, 10 per page.
/api/v1/connections
pageOptional query- integerPage number, starting at 1.
curl --request GET 'https://1confirmed.com/api/v1/connections' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
Response
{
"success": true,
"data": {
"logs": [
{
"id": 42,
"user_id": 7,
"device": "Desktop",
"ip_address": "192.0.2.1",
"browser": "Chrome",
"operating_system": "macOS",
"city": null,
"country": null,
"logged_in_at": "2026-09-22 10:00:00",
"logged_out_at": null
}
],
"pagination": {
"total": 1,
"count": 1,
"per_page": 10,
"next_page_url": null,
"prev_page_url": null,
"current_page": 1,
"total_pages": 1
}
},
"message": "Example response message"
}Saved lists
Read lists you own and lists shared with you.
/api/v1/saved-list
Saved-list endpoints require an active premium subscription or the admin role, in addition to the normal account access token.
searchOptional query- stringSearch the records described above.
pageOptional query- integerPage number, starting at 1.
curl --request GET 'https://1confirmed.com/api/v1/saved-list' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
Response
{
"success": true,
"data": [
{
"id": 42,
"name": "Customers",
"is_shared": false
}
],
"message": "Example response message"
}{
"success": true,
"data": {
"lists": [
{
"id": 42,
"name": "Customers",
"is_shared": false,
"created_at": "2026-09-22 10:00:00",
"updated_at": "2026-09-22 10:00:00"
}
],
"pagination": {
"total": 1,
"count": 1,
"per_page": 10,
"next_page_url": null,
"prev_page_url": null,
"current_page": 1,
"total_pages": 1
}
},
"message": "Example response message"
}Create saved list
Store recipient data for later use.
/api/v1/saved-list
Saved-list endpoints require an active premium subscription or the admin role, in addition to the normal account access token.
nameRequired- stringMaximum 255 characters.
json_dataRequired- JSON-encoded stringList data encoded as JSON.
broadcast_idOptional- integer IDA broadcast you own.
curl --request POST 'https://1confirmed.com/api/v1/saved-list' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
"name": "Customers",
"json_data": "{\"data\":[{\"phone\":\"212600000000\"}]}"
}'Response
{
"success": true,
"data": {
"id": 42,
"uuid": "018f16b6-7696-4ae8-8cf0-000000000042",
"name": "Customers",
"json_data": "{\"data\":[{\"phone\":\"212600000000\"}]}"
},
"message": "Example response message"
}Saved list details
Read an owned or shared list, including json_data and is_shared.
/api/v1/saved-list/{id}
Replace {id} in the path with the integer ID of the record described below. The cURL example uses an illustrative ID.
Saved-list endpoints require an active premium subscription or the admin role, in addition to the normal account access token.
savedListRequired path- integer IDID returned by Saved lists.
curl --request GET 'https://1confirmed.com/api/v1/saved-list/123' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
Response
{
"success": true,
"data": {
"id": 42,
"uuid": "018f16b6-7696-4ae8-8cf0-000000000042",
"name": "Customers",
"json_data": "{\"data\":[{\"phone\":\"212600000000\"}]}",
"is_shared": false
},
"message": "Example response message"
}Update saved list
Update a list you own. PATCH is also supported.
/api/v1/saved-list/{id}
Replace {id} in the path with the integer ID of the record described below. The cURL example uses an illustrative ID.
Saved-list endpoints require an active premium subscription or the admin role, in addition to the normal account access token.
nameOptional- stringNonempty, maximum 255 characters when supplied.
json_dataOptional- JSON-encoded stringNonempty valid JSON when supplied.
curl --request PUT 'https://1confirmed.com/api/v1/saved-list/123' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
"name": "Updated customers"
}'Response
{
"success": true,
"data": {
"id": 42,
"uuid": "018f16b6-7696-4ae8-8cf0-000000000042",
"name": "Customers",
"json_data": "{\"data\":[{\"phone\":\"212600000000\"}]}"
},
"message": "Example response message"
}Clone saved list
Copy an owned or shared list into your account.
/api/v1/saved-list/{id}/clone
Replace {id} in the path with the integer ID of the record described below. The cURL example uses an illustrative ID.
Saved-list endpoints require an active premium subscription or the admin role, in addition to the normal account access token.
No request body or query parameters.
curl --request POST 'https://1confirmed.com/api/v1/saved-list/123/clone' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
Response
{
"success": true,
"data": {
"id": 42,
"uuid": "018f16b6-7696-4ae8-8cf0-000000000042",
"name": "Customers",
"json_data": "{\"data\":[{\"phone\":\"212600000000\"}]}"
},
"message": "Example response message"
}Delete saved list
Delete a list you own.
/api/v1/saved-list/{id}
Replace {id} in the path with the integer ID of the record described below. The cURL example uses an illustrative ID.
Saved-list endpoints require an active premium subscription or the admin role, in addition to the normal account access token.
No request body or query parameters.
curl --request DELETE 'https://1confirmed.com/api/v1/saved-list/123' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
Response
{
"success": true,
"data": true,
"message": "Example response message"
}Send SMS
Send an SMS using your account credit. SMS is available once your account has bought credits at least once, or on a premium account; free credits cover WhatsApp only.
/api/v1/sms/send
422 covers invalid fields, an account that has never bought credits (reason sms_requires_purchase), insufficient credit or rejected sends; unexpected sending failures return 500. Provider acceptance is not a delivery receipt.
phoneRequired- string9–20 characters. Use a supported Moroccan number with calling code 212.
textRequired- stringMaximum 640 characters.
fromOptional- stringSender name, maximum 11 characters. Must be a public sender name or one assigned to your account, and enabled; anything else is refused with 422. Omit it to use the default sender name.
operatorOptional- stringIAM, ORANGE or INWI; omitted means provider/operator detection.
preferenceOptional- stringNormal (default), Broadcast or Retry.
intervalConditional- integerRequired with preference=Retry. 1–60 minutes.
curl --request POST 'https://1confirmed.com/api/v1/sms/send' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
"phone": "212600000000",
"text": "Your order is ready."
}'Response
{
"success": true,
"data": {
"id": 42,
"user_id": 7,
"phone": "212600000000",
"text": "Your order is ready.",
"from_name": "Example",
"cost": 1,
"status": "ACCEPTED",
"created_at": "2026-09-22 10:00:00",
"updated_at": "2026-09-22 10:00:00"
},
"message": "Example response message",
"credit_cost": 1
}SMS history
List your SMS messages, newest first.
/api/v1/sms
pageOptional query- integerPage number, starting at 1.
per_pageOptional query- integerPage size; default 15.
phoneOptional query- stringPartial phone match.
curl --request GET 'https://1confirmed.com/api/v1/sms' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
Response
{
"success": true,
"data": {
"data": [
{
"id": 42,
"user_id": 7,
"phone": "212600000000",
"text": "Your order is ready.",
"from_name": "Example",
"cost": 1,
"status": "ACCEPTED",
"created_at": "2026-09-22 10:00:00",
"updated_at": "2026-09-22 10:00:00"
}
],
"current_page": 1,
"last_page": 1,
"per_page": 15,
"total": 1,
"from": 1,
"to": 1,
"stats": {
"total": 1,
"accepted": 1,
"failed": 0,
"today": 1
}
},
"message": "Example response message"
}Statistics cover the whole account, not just the filtered page.
SMS details
Read one of your SMS messages.
/api/v1/sms/{id}
Replace {id} in the path with the integer ID of the record described below. The cURL example uses an illustrative ID.
smsMessageRequired path- integer IDID returned by SMS history.
curl --request GET 'https://1confirmed.com/api/v1/sms/123' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
Response
{
"success": true,
"data": {
"id": 42,
"user_id": 7,
"phone": "212600000000",
"text": "Your order is ready.",
"from_name": "Example",
"cost": 1,
"status": "ACCEPTED",
"created_at": "2026-09-22 10:00:00",
"updated_at": "2026-09-22 10:00:00"
},
"message": "Example response message"
}SMS cost
Read your current per-message SMS credit cost.
/api/v1/sms/cost
No request body or query parameters.
curl --request GET 'https://1confirmed.com/api/v1/sms/cost' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
Response
{
"success": true,
"cost": 1
}Choose template
After Create draft, attach the template.
/api/v1/broadcast/template
broadcast_idRequired- integer IDID of a draft you own.
template_idRequired- integer IDAccessible template ID.
curl --request POST 'https://1confirmed.com/api/v1/broadcast/template' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
"broadcast_id": 123,
"template_id": 42
}'Response
{
"success": true,
"data": {
"id": 42,
"sent_at": "2026-09-22",
"name": "Order updates",
"contacts": 0,
"language": "English",
"template": "Example template",
"whatsapp_area": null,
"is_draft": true,
"mapping": null,
"global_data": null,
"confirmations": 0,
"has_file": false,
"is_flow_form": false,
"file": "",
"listener_url": null
},
"message": "Example response message"
}Upload source file
Attach a recipient source file to a draft. Existing attached media is replaced.
/api/v1/broadcast/file
broadcast_idRequired- integer IDID of a draft you own.
fileRequired- file uploadcsv, txt, xlsx or xls. Use multipart/form-data.
curl --request POST 'https://1confirmed.com/api/v1/broadcast/file' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \ --form 'broadcast_id=123' \ --form '[email protected]'
Response
{
"success": true,
"data": {
"id": 42,
"sent_at": "2026-09-22",
"name": "Order updates",
"contacts": 0,
"language": null,
"template": null,
"whatsapp_area": null,
"is_draft": true,
"mapping": null,
"global_data": null,
"confirmations": 0,
"has_file": false,
"is_flow_form": false,
"file": "",
"listener_url": null
},
"message": "Example response message"
}Map recipients
Supply recipients and template values after choosing the template.
/api/v1/broadcast/mapping
Replace customer_name with the selected template variable names. File templates require a valid file URL in each row. OTP values must contain digits only.
broadcast_idRequired- integer IDID of a draft you own.
dataRequired- JSON-encoded stringObject with a data array of recipient rows, including phone and template variable keys. Same row format as Send broadcast.
global_dataConditional- objectInclude all global variable keys required by the template.
as_formOptional- presence flagIncluding this field enables form sending; omit it to disable.
curl --request POST 'https://1confirmed.com/api/v1/broadcast/mapping' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
"broadcast_id": 123,
"data": "{\"data\":[{\"phone\":\"212600000000\",\"customer_name\":\"Sam\"}]}"
}'Response
{
"success": true,
"data": {
"id": 42,
"sent_at": "2026-09-22",
"name": "Order updates",
"contacts": 0,
"language": "English",
"template": "Example template",
"whatsapp_area": null,
"is_draft": true,
"mapping": null,
"global_data": null,
"confirmations": 0,
"has_file": false,
"is_flow_form": false,
"file": "",
"listener_url": null
},
"message": "Example response message"
}Choose sender
Set the sending account flow for the draft.
/api/v1/broadcast/country
broadcast_idRequired- integer IDID of a draft you own.
template_account_flow_idRequired- integer IDSender flow for the selected template.
country_idOptional- integer IDCountry record ID.
curl --request POST 'https://1confirmed.com/api/v1/broadcast/country' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
"broadcast_id": 123,
"template_account_flow_id": 73
}'Response
{
"success": true,
"data": {
"id": 42,
"sent_at": "2026-09-22",
"name": "Order updates",
"contacts": 0,
"language": "English",
"template": "Example template",
"whatsapp_area": null,
"is_draft": true,
"mapping": null,
"global_data": null,
"confirmations": 0,
"has_file": false,
"is_flow_form": false,
"file": "",
"listener_url": null
},
"message": "Example response message"
}Send draft
Queue a prepared draft after template, mapping and sender steps.
/api/v1/broadcast/send
Supports the optional Idempotency-Key header. Requires valid mapped recipients and enough credit. Large or flagged broadcasts can be held for review.
broadcast_idRequired- integer IDID of a draft you own.
delayed_toOptional- date/timeAt least 15 minutes in the future.
ai_flow_configOptional- object or JSON stringSelect an owned, published AI Flow. See AI Flow configuration below.
curl --request POST 'https://1confirmed.com/api/v1/broadcast/send' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
"broadcast_id": 123
}'Response
{
"success": true,
"data": {
"id": 42,
"sent_at": "2026-09-22",
"name": "Order updates",
"contacts": 1,
"language": "English",
"template": "Example template",
"whatsapp_area": null,
"is_draft": false,
"mapping": null,
"global_data": null,
"confirmations": 0,
"has_file": false,
"is_flow_form": false,
"file": "",
"listener_url": null
},
"message": "Example response message"
}Download source file
Download the source file attached to your broadcast.
/api/v1/broadcast/download/{id}
Replace {id} in the path with the integer ID of the record described below. The cURL example uses an illustrative ID.
No request body or query parameters.
curl --request GET 'https://1confirmed.com/api/v1/broadcast/download/123' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
Response
HTTP 200 returns the file attachment. This response is not JSON. Missing files return 404; a v1 ownership failure returns 403.
Stop queued broadcast
Stop remaining queued work for your broadcast.
/api/v1/broadcast/{id}/stop
Replace {id} in the path with the integer ID of the record described below. The cURL example uses an illustrative ID.
No request body or query parameters.
curl --request POST 'https://1confirmed.com/api/v1/broadcast/123/stop' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
Response
{
"success": true,
"data": true,
"message": "Example response message"
}Scheduled jobs
Inspect the schedule state of your broadcast.
/api/v1/broadcast/{id}/scheduled-jobs
Replace {id} in the path with the integer ID of the record described below. The cURL example uses an illustrative ID.
No request body or query parameters.
curl --request GET 'https://1confirmed.com/api/v1/broadcast/123/scheduled-jobs' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
Response
{
"success": true,
"data": {
"broadcast_id": 42,
"scheduled_jobs_count": 0,
"scheduled_jobs": [],
"is_scheduled": false,
"delayed_to": null,
"refused": false
},
"message": "Example response message"
}V2 limits job entries to scheduling metadata. V1 returns legacy queue records.
Cancel scheduled broadcast
Cancel remaining scheduled work. Already cancelled or already processed broadcasts can return 400.
/api/v1/broadcast/{id}/cancel-schedule
Replace {id} in the path with the integer ID of the record described below. The cURL example uses an illustrative ID.
No request body or query parameters.
curl --request POST 'https://1confirmed.com/api/v1/broadcast/123/cancel-schedule' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
Response
{
"success": true,
"data": {
"refund_reconciliation_pending": false,
"broadcast_id": 42,
"deleted_jobs_count": 1,
"message": "Example cancellation message",
"cancelled_at": "2026-09-22 10:00:00",
"cancelled_by": "Sam Smith"
},
"message": "Example response message"
}Refund reconciliation may still be pending. Check refund_reconciliation_pending before treating the refund as complete.
Calendars
Read your calendars.
/api/v1/calendars
No request body or query parameters.
curl --request GET 'https://1confirmed.com/api/v1/calendars' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
Response
{
"success": true,
"data": {
"calendars": [
{
"id": 42,
"uuid": "018f16b6-7696-4ae8-8cf0-000000000042",
"name": "Appointments",
"description": null,
"date_start": "2026-09-23",
"date_end": "2026-10-23",
"is_active": true,
"language": "en",
"logo_url": "",
"is_valid": false,
"has_time_slots": false,
"is_expired": false,
"is_not_started": true,
"days_until_start": 1,
"created_at": "2026-09-22 10:00:00",
"updated_at": "2026-09-22 10:00:00"
}
]
},
"message": "Example response message"
}Related records and relationship counts are included when loaded by this operation.
Create calendar
Create a calendar for appointment templates.
/api/v1/calendars
nameRequired- stringMaximum 255 characters.
descriptionOptional- stringCalendar description.
date_startRequired- dateToday or later when creating a calendar.
date_endRequired- dateAfter date_start.
is_activeOptional- booleanEnable or disable this calendar.
languageOptional- stringen or fr. This is not language_id.
logoOptional- file uploadjpeg, png, jpg, gif or webp image, maximum 2048 KB; use multipart/form-data.
curl --request POST 'https://1confirmed.com/api/v1/calendars' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
"name": "Appointments",
"date_start": "2026-11-13",
"date_end": "2026-12-12"
}'Response
{
"success": true,
"data": {
"id": 42,
"uuid": "018f16b6-7696-4ae8-8cf0-000000000042",
"name": "Appointments",
"description": null,
"date_start": "2026-09-23",
"date_end": "2026-10-23",
"is_active": true,
"language": "en",
"logo_url": "",
"is_valid": false,
"has_time_slots": false,
"is_expired": false,
"is_not_started": true,
"days_until_start": 1,
"created_at": "2026-09-22 10:00:00",
"updated_at": "2026-09-22 10:00:00"
},
"message": "Example response message"
}Related records and relationship counts are included when loaded by this operation.
Calendar details
Read an owned calendar with its schedule tree.
/api/v1/calendars/{id}
Replace {id} in the path with the integer ID of the record described below. The cURL example uses an illustrative ID.
No request body or query parameters.
curl --request GET 'https://1confirmed.com/api/v1/calendars/123' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
Response
{
"success": true,
"data": {
"id": 42,
"uuid": "018f16b6-7696-4ae8-8cf0-000000000042",
"name": "Appointments",
"description": null,
"date_start": "2026-09-23",
"date_end": "2026-10-23",
"is_active": true,
"language": "en",
"logo_url": "",
"is_valid": false,
"has_time_slots": false,
"is_expired": false,
"is_not_started": true,
"days_until_start": 1,
"created_at": "2026-09-22 10:00:00",
"updated_at": "2026-09-22 10:00:00"
},
"message": "Example response message"
}{
"success": true,
"data": {
"id": 42,
"uuid": "018f16b6-7696-4ae8-8cf0-000000000042",
"name": "Appointments",
"description": null,
"date_start": "2026-09-23",
"date_end": "2026-10-23",
"is_active": true,
"language": "en",
"logo_url": "",
"is_valid": false,
"has_time_slots": false,
"is_expired": false,
"is_not_started": true,
"days_until_start": 1,
"created_at": "2026-09-22 10:00:00",
"updated_at": "2026-09-22 10:00:00",
"cities": [
{
"id": 42,
"city_name": "Casablanca",
"address": null,
"description": null,
"is_active": true,
"created_at": "2026-09-22 10:00:00",
"updated_at": "2026-09-22 10:00:00",
"weekday_schedules": [
{
"id": 42,
"day_of_week": 1,
"day_name": "Monday",
"is_active": true,
"special_notes": null,
"created_at": "2026-09-22 10:00:00",
"updated_at": "2026-09-22 10:00:00",
"time_ranges": [
{
"id": 42,
"start_time": "09:00",
"end_time": "17:00",
"duration_minutes": 30,
"capacity": 1,
"is_active": true,
"created_at": "2026-09-22 10:00:00",
"updated_at": "2026-09-22 10:00:00"
}
]
}
]
}
]
},
"message": "Example response message"
}Related records and relationship counts are included when loaded by this operation.
Update calendar
Update fields on a calendar you own. PATCH is also supported.
/api/v1/calendars/{id}
Replace {id} in the path with the integer ID of the record described below. The cURL example uses an illustrative ID.
name, date_start and date_end cannot be empty when supplied.
nameOptional- stringMaximum 255 characters.
descriptionOptional- stringCalendar description.
date_startOptional- dateValid date. If updating date_end, also supply date_start for its comparison.
date_endOptional- dateAfter date_start.
is_activeOptional- booleanEnable or disable this calendar.
languageOptional- stringen or fr. This is not language_id.
logoOptional- file uploadjpeg, png, jpg, gif or webp image, maximum 2048 KB; use multipart/form-data.
curl --request PUT 'https://1confirmed.com/api/v1/calendars/123' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
"name": "Updated appointments"
}'Response
{
"success": true,
"data": {
"id": 42,
"uuid": "018f16b6-7696-4ae8-8cf0-000000000042",
"name": "Appointments",
"description": null,
"date_start": "2026-09-23",
"date_end": "2026-10-23",
"is_active": true,
"language": "en",
"logo_url": "",
"is_valid": false,
"has_time_slots": false,
"is_expired": false,
"is_not_started": true,
"days_until_start": 1,
"created_at": "2026-09-22 10:00:00",
"updated_at": "2026-09-22 10:00:00"
},
"message": "Example response message"
}Related records and relationship counts are included when loaded by this operation.
Delete calendar
Delete a calendar you own.
/api/v1/calendars/{id}
Replace {id} in the path with the integer ID of the record described below. The cURL example uses an illustrative ID.
No request body or query parameters.
curl --request DELETE 'https://1confirmed.com/api/v1/calendars/123' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
Response
{
"success": true,
"data": null,
"message": "Example response message"
}City list
List records in a parent calendar you own.
/api/v1/calendars/{id}/cities
Replace {id} in the path with the integer ID of the record described below. The cURL example uses an illustrative ID.
No request body or query parameters.
curl --request GET 'https://1confirmed.com/api/v1/calendars/123/cities' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
Response
{
"success": true,
"data": [
{
"id": 42,
"city_name": "Casablanca",
"address": null,
"description": null,
"is_active": true,
"created_at": "2026-09-22 10:00:00",
"updated_at": "2026-09-22 10:00:00"
}
],
"message": "Example response message"
}Related records and relationship counts are included when loaded by this operation.
Create city
Add a record to an owned calendar.
/api/v1/cities
calendar_idRequired- integer IDParent record belonging to your calendar.
city_nameRequired- stringMaximum 255 characters.
addressOptional- stringLocation address.
descriptionOptional- stringCity description.
is_activeOptional- booleanEnable or disable this city.
curl --request POST 'https://1confirmed.com/api/v1/cities' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
"calendar_id": 123,
"city_name": "Casablanca"
}'Response
{
"success": true,
"data": {
"id": 42,
"city_name": "Casablanca",
"address": null,
"description": null,
"is_active": true,
"created_at": "2026-09-22 10:00:00",
"updated_at": "2026-09-22 10:00:00"
},
"message": "Example response message"
}City details
Read a record in your calendar.
/api/v1/cities/{id}
Replace {id} in the path with the integer ID of the record described below. The cURL example uses an illustrative ID.
No request body or query parameters.
curl --request GET 'https://1confirmed.com/api/v1/cities/123' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
Response
{
"success": true,
"data": {
"id": 42,
"city_name": "Casablanca",
"address": null,
"description": null,
"is_active": true,
"created_at": "2026-09-22 10:00:00",
"updated_at": "2026-09-22 10:00:00"
},
"message": "Example response message"
}Related records and relationship counts are included when loaded by this operation.
Update city
Update this record. PATCH is also supported. Its parent cannot be changed here.
/api/v1/cities/{id}
Replace {id} in the path with the integer ID of the record described below. The cURL example uses an illustrative ID.
Required creation fields cannot be empty when supplied.
city_nameOptional- stringMaximum 255 characters.
addressOptional- stringLocation address.
descriptionOptional- stringCity description.
is_activeOptional- booleanEnable or disable this city.
curl --request PUT 'https://1confirmed.com/api/v1/cities/123' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
"city_name": "Casablanca"
}'Response
{
"success": true,
"data": {
"id": 42,
"city_name": "Casablanca",
"address": null,
"description": null,
"is_active": true,
"created_at": "2026-09-22 10:00:00",
"updated_at": "2026-09-22 10:00:00"
},
"message": "Example response message"
}Delete city
Delete a record in your calendar.
/api/v1/cities/{id}
Replace {id} in the path with the integer ID of the record described below. The cURL example uses an illustrative ID.
No request body or query parameters.
curl --request DELETE 'https://1confirmed.com/api/v1/cities/123' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
Response
{
"success": true,
"data": null,
"message": "Example response message"
}Weekday schedule list
List records in a parent calendar you own.
/api/v1/cities/{id}/weekday-schedules
Replace {id} in the path with the integer ID of the record described below. The cURL example uses an illustrative ID.
No request body or query parameters.
curl --request GET 'https://1confirmed.com/api/v1/cities/123/weekday-schedules' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
Response
{
"success": true,
"data": [
{
"id": 42,
"day_of_week": 1,
"day_name": "Monday",
"is_active": true,
"special_notes": null,
"created_at": "2026-09-22 10:00:00",
"updated_at": "2026-09-22 10:00:00"
}
],
"message": "Example response message"
}Related records and relationship counts are included when loaded by this operation.
Create weekday schedule
Add a record to an owned calendar.
/api/v1/weekday-schedules
city_idRequired- integer IDParent record belonging to your calendar.
day_of_weekRequired- integer1–7.
is_activeOptional- booleanEnable or disable this day.
special_notesOptional- stringNotes for this day.
curl --request POST 'https://1confirmed.com/api/v1/weekday-schedules' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
"city_id": 123,
"day_of_week": 1
}'Response
{
"success": true,
"data": {
"id": 42,
"day_of_week": 1,
"day_name": "Monday",
"is_active": true,
"special_notes": null,
"created_at": "2026-09-22 10:00:00",
"updated_at": "2026-09-22 10:00:00"
},
"message": "Example response message"
}Weekday schedule details
Read a record in your calendar.
/api/v1/weekday-schedules/{id}
Replace {id} in the path with the integer ID of the record described below. The cURL example uses an illustrative ID.
No request body or query parameters.
curl --request GET 'https://1confirmed.com/api/v1/weekday-schedules/123' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
Response
{
"success": true,
"data": {
"id": 42,
"day_of_week": 1,
"day_name": "Monday",
"is_active": true,
"special_notes": null,
"created_at": "2026-09-22 10:00:00",
"updated_at": "2026-09-22 10:00:00"
},
"message": "Example response message"
}Related records and relationship counts are included when loaded by this operation.
Update weekday schedule
Update this record. PATCH is also supported. Its parent cannot be changed here.
/api/v1/weekday-schedules/{id}
Replace {id} in the path with the integer ID of the record described below. The cURL example uses an illustrative ID.
Required creation fields cannot be empty when supplied.
day_of_weekOptional- integer1–7.
is_activeOptional- booleanEnable or disable this day.
special_notesOptional- stringNotes for this day.
curl --request PUT 'https://1confirmed.com/api/v1/weekday-schedules/123' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
"day_of_week": 1
}'Response
{
"success": true,
"data": {
"id": 42,
"day_of_week": 1,
"day_name": "Monday",
"is_active": true,
"special_notes": null,
"created_at": "2026-09-22 10:00:00",
"updated_at": "2026-09-22 10:00:00"
},
"message": "Example response message"
}Delete weekday schedule
Delete a record in your calendar.
/api/v1/weekday-schedules/{id}
Replace {id} in the path with the integer ID of the record described below. The cURL example uses an illustrative ID.
No request body or query parameters.
curl --request DELETE 'https://1confirmed.com/api/v1/weekday-schedules/123' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
Response
{
"success": true,
"data": null,
"message": "Example response message"
}Time range list
List records in a parent calendar you own.
/api/v1/weekday-schedules/{id}/time-ranges
Replace {id} in the path with the integer ID of the record described below. The cURL example uses an illustrative ID.
No request body or query parameters.
curl --request GET 'https://1confirmed.com/api/v1/weekday-schedules/123/time-ranges' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
Response
{
"success": true,
"data": [
{
"id": 42,
"start_time": "09:00",
"end_time": "17:00",
"duration_minutes": 30,
"capacity": 1,
"is_active": true,
"created_at": "2026-09-22 10:00:00",
"updated_at": "2026-09-22 10:00:00"
}
],
"message": "Example response message"
}Create time range
Add a record to an owned calendar.
/api/v1/time-ranges
weekday_schedule_idRequired- integer IDParent record belonging to your calendar.
start_timeRequired- stringH:i.
end_timeRequired- stringH:i, after start_time.
duration_minutesRequired- integer5–480 minutes.
capacityRequired- integer1–100.
is_activeOptional- booleanEnable or disable this time range.
curl --request POST 'https://1confirmed.com/api/v1/time-ranges' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
"weekday_schedule_id": 123,
"start_time": "09:00",
"end_time": "17:00",
"duration_minutes": 30,
"capacity": 1
}'Response
{
"success": true,
"data": {
"id": 42,
"start_time": "09:00",
"end_time": "17:00",
"duration_minutes": 30,
"capacity": 1,
"is_active": true,
"created_at": "2026-09-22 10:00:00",
"updated_at": "2026-09-22 10:00:00"
},
"message": "Example response message"
}Time range details
Read a record in your calendar.
/api/v1/time-ranges/{id}
Replace {id} in the path with the integer ID of the record described below. The cURL example uses an illustrative ID.
No request body or query parameters.
curl --request GET 'https://1confirmed.com/api/v1/time-ranges/123' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
Response
{
"success": true,
"data": {
"id": 42,
"start_time": "09:00",
"end_time": "17:00",
"duration_minutes": 30,
"capacity": 1,
"is_active": true,
"created_at": "2026-09-22 10:00:00",
"updated_at": "2026-09-22 10:00:00"
},
"message": "Example response message"
}Update time range
Update this record. PATCH is also supported. Its parent cannot be changed here.
/api/v1/time-ranges/{id}
Replace {id} in the path with the integer ID of the record described below. The cURL example uses an illustrative ID.
When updating end_time, also send start_time for the comparison. Required creation fields cannot be empty when supplied.
start_timeOptional- stringH:i.
end_timeOptional- stringH:i, after start_time.
duration_minutesOptional- integer5–480 minutes.
capacityOptional- integer1–100.
is_activeOptional- booleanEnable or disable this time range.
curl --request PUT 'https://1confirmed.com/api/v1/time-ranges/123' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
"start_time": "09:00",
"end_time": "17:00",
"duration_minutes": 30,
"capacity": 1
}'Response
{
"success": true,
"data": {
"id": 42,
"start_time": "09:00",
"end_time": "17:00",
"duration_minutes": 30,
"capacity": 1,
"is_active": true,
"created_at": "2026-09-22 10:00:00",
"updated_at": "2026-09-22 10:00:00"
},
"message": "Example response message"
}Delete time range
Delete a record in your calendar.
/api/v1/time-ranges/{id}
Replace {id} in the path with the integer ID of the record described below. The cURL example uses an illustrative ID.
No request body or query parameters.
curl --request DELETE 'https://1confirmed.com/api/v1/time-ranges/123' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
Response
{
"success": true,
"data": null,
"message": "Example response message"
}Status listener
Set listener_url when creating a message or broadcast, or when updating a draft. This is a field on those requests, not a separate API endpoint. Updates are queued as JSON POST requests to your URL.
The payload contains phone, broadcast_id, name, confirmed, canceled, interacted and statuses. Each status contains status and datetime. Delivery updates include the incoming status; contact updates include the stored status list.
broadcast_id follows the version used to create the broadcast: numeric for v1, UUID for v2. A callback for an older v1 broadcast does not change just because your client now reads the v2 documentation.
Use a public HTTPS destination. Delivery validates the URL, blocks private-network addresses and does not follow redirects. Return a successful HTTP response. Failed deliveries can be retried, so handle repeat notifications. This legacy callback does not add an HMAC signature; authenticated destinations use the separate result-connector configuration.
AI Flow configuration
ai_flow_config is optional on the messaging requests that list it. Use an object or its JSON-encoded string (maximum 32,768 bytes for the string). Omit it, or use null, to send without selecting an AI Flow.
flow_id: UUID of your published flow, in both API versions.expected_published_version: required integer matching the published version. A changed or missing version returns 409.button_routes: optional object mapping button actions to node IDs in the published flow, at most 10. Actions must be nonempty strings of at most 256 characters;did_not_request_code,stopandunsubscribeare reserved.button_limits: optional object for mapped buttons only. Each repeat allowance is an integer from 1 to 10.text_reply_enabled: optional boolean or 0/1, default false. True requires a text-message trigger in the selected flow.version_id: accepted but replaced by the server's published-version selection. Clients do not choose an internal version ID.
Other keys are rejected. Select the published flow and actions in the portal; these account API endpoints do not provide a flow-catalog lookup.
Result connectors
These optional fields on POST /send-broadcast attach result destinations. They use a different event format from listener_url. Configure and verify the destination in the portal first; a custom webhook requires the verification receipt for that exact configuration.
Custom webhook fields
webhook_enabled: boolean. When enabled,webhook_url,webhook_trigger_key,webhook_fieldsandwebhook_auth_typeare required.webhook_url: public HTTPS URL on port 443, maximum 2,048 characters. Private networks are blocked.webhook_verification: portal verification receipt, maximum 4,096 characters.webhook_trigger_key:all_broadcast_events,contact_broadcast_status_changed,new_broadcast_reply,contact_confirmed,contact_cancelledorcontact_updated.webhook_fields: 1–200 selected result fields. Optionalwebhook_sample_fieldsaccepts up to 200 of the same field names.webhook_auth_type:none,bearer,basic,header,queryorhmac.webhook_token: required for bearer/header/query/hmac, maximum 2,048 characters; no control characters.webhook_usernameandwebhook_password: required for basic authentication, maximum 255 and 2,048 characters respectively. No control characters; username cannot contain a colon.webhook_auth_name: required for header/query authentication, maximum 100 characters. Start with a letter; use letters, numbers, underscores or hyphens. Reserved transport headers and names starting withx-1confirmed-are rejected.
Zoho fields
zoho_enabled is an optional boolean. zoho_url is required when enabled, maximum 2,048 characters, and must pass the configured Zoho destination allowlist. zoho_trigger_key accepts the same triggers above and defaults to all_broadcast_events. zoho_fields optionally selects 1–200 fields; zoho_sample_fields accepts up to 200. zoho_verification accepts an optional receipt up to 4,096 characters. The Zoho connector must be enabled.
Selectable result fields
contact_phone, contact_stage, is_lead, is_sent, confirmed, cancelled, interacted, latest_status, statuses, template_values, captured_fields, flow_response. The last three also accept one child key, such as captured_fields.email; child keys use 1–100 letters, digits, underscores or hyphens.
Events always retain id, event_type, occurred_at, broadcast_id, broadcast_name, contact_id, contact_uuid and is_sample. Do not parse this payload as the legacy status-listener payload.
Pagination & errors
Where an endpoint returns pagination, its keys are total, count, per_page, next_page_url, prev_page_url, current_page and total_pages. Keep your filters when requesting the next page. SMS history uses its separately documented pagination shape.
Most successful account endpoints wrap results in success, data and message. Single-message sends and SMS cost have different shapes, shown in their sections. Response field lists describe structure, not literal JSON to send. Nullable relationships depend on your account and selected template.
For sends that accept Idempotency-Key, a repeat request can return the stored response. While the original operation is still processing, its HTTP 202 receipt contains success, queued, processing, broadcast_id, data and message. data.id identifies the broadcast when available; v2 omits unavailable broadcast_id and data.id fields. This receipt is not a delivery confirmation.
- 400: phone verification is incomplete on a protected account request (administrators are exempt), or a scheduled broadcast cannot be cancelled.
- 401: authentication failed or a registration token is invalid.
- 403: an account, role or access check refused the request.
- 404: a record/reference is unavailable, or a legacy controller returned a business error. In v2, malformed, numeric, unknown and inaccessible model references are rejected. Check the response message; this does not always mean the URL is missing.
- 409: an idempotency conflict or a published AI Flow version changed.
- 422: invalid fields or a send rejected by the provider. Validation commonly returns
messageanderrorskeyed by field. Registration also includessuccess: false. - 429: rate limit exceeded. Observe
Retry-Afterbefore retrying. - 500: an unexpected server failure. Do not blindly repeat a send; use the same idempotency key where supported.
Send Accept: application/json. Always inspect both the HTTP status and the endpoint-specific body. Do not assume every error or success has one global schema.