API reference
Connect a WhatsApp Business Account from Meta and assign its numbers to assistants.
- GET
/api/integrations/whatsapp/connectionsList WhatsApp accounts and numbers - POST
/api/integrations/whatsapp/connectionsConnect a WhatsApp Business account - PATCH
/api/integrations/whatsapp/connections/{id}Update a WhatsApp connection - DELETE
/api/integrations/whatsapp/connections/{id}Disconnect a WhatsApp account - PUT
/api/integrations/whatsapp/connections/{id}/numbers/{numberId}Assign a WhatsApp number to an assistant - POST
/api/integrations/whatsapp/connections/{id}/subscribeSubscribe an account to its message callback - POST
/api/integrations/whatsapp/connections/{id}/syncSync an account's phone numbers
List WhatsApp accounts and numbers
GET/api/integrations/whatsapp/connections
Every connected WhatsApp Business Account with its numbers, the assistant each number is assigned to, and counts of replies and turns that failed. Credentials are never returned. Needs an org-wide key.
Secret API key, org-wide (not pinned to a project). How it works
Returns
200 Connections
Response attributes
dataarray of WhatsAppConnectionrequired9 attributes
idstringorg_idstringnamestringwaba_idstringThe WhatsApp Business Account id.
api_versionstringconfiguredbooleanCredentials are stored. False after a disconnect.
enabledbooleanFalse while paused: messages are not answered.
webhook_pathstringThe path of the callback URL to give Meta (on the API origin).
numbersarray of WhatsAppNumber10 attributes
idstringconnection_idstringphone_number_idstringdisplay_phone_numberstringverified_namestring | nullassistant_idstring | nullenabledbooleanmodestringOne of
livetestfailed_repliesintegerList only: replies that could not be sent.
failed_turnsintegerList only: incoming messages the assistant failed to answer.
- 400
invalid_request: the body failed validation - 403
org_scope_required(needs an org-wide key; project keys get 403) or the role is too low - 404
not_found: no such connection or number in this organization - 409
whatsapp_already_connected,whatsapp_credentials_required,whatsapp_disconnected, or on syncwhatsapp_number_already_connected(a number already belongs to another connection) - 422 Meta refused the request (
meta_<Meta error code>, ormeta_http_<status>), or could not be reached (meta_unreachable, which says nothing about whether Meta acted on it) - 429 Rate limit exceeded (
rate_limited). WaitRetry-Afterseconds. Budgets are per 60-second window: developer API 120 per key and 600 per organization; public chat 30 per IP address, except polling for updates (60 per conversation and IP address) and analytics events (120 per IP address).
curl "https://api.myleadsfactory.tech/api/integrations/whatsapp/connections" \
-H "Authorization: Bearer $MLF_API_KEY"{
"data": [
{
"id": "id_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
"org_id": "org_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
"name": "Front desk",
"waba_id": "id_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
"api_version": "string",
"configured": true,
"enabled": true,
"webhook_path": "string",
"numbers": [
{
"id": "pn_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
"connection_id": "id_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
"phone_number_id": "+14155550123",
"display_phone_number": "+14155550123",
"verified_name": "string",
"assistant_id": "asst_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
"enabled": true,
"mode": "live",
"failed_replies": 1,
"failed_turns": 1
}
]
}
]
}Connect a WhatsApp Business account
POST/api/integrations/whatsapp/connections
Checks the credentials with Meta, stores them encrypted and imports the account's phone numbers, unassigned. Then subscribe the account to its callback and assign numbers to assistants. Needs an org-wide key.
Secret API key, not read-only, org-wide (not pinned to a project). How it works
Request body
namestringrequiredup to 100 charactersYour label for the account.
waba_idstringrequiredThe WhatsApp Business Account id (digits).
api_versionstringGraph API version.
Default
"v25.0"credentialsobjectrequiredFrom your Meta app. Write-only: stored encrypted and never returned.
3 attributes
access_tokenstringrequiredup to 8192 characterswrite-only, never returnedA system user access token with WhatsApp permissions.
app_secretstringrequiredup to 256 characterswrite-only, never returnedVerifies Meta's callback signatures.
verify_tokenstringrequired16 to 256 characterswrite-only, never returnedAny string you choose; Meta echoes it when it verifies the callback.
Returns
201 Connected
Response attributes
dataWhatsAppConnectionrequired9 attributes
idstringorg_idstringnamestringwaba_idstringThe WhatsApp Business Account id.
api_versionstringconfiguredbooleanCredentials are stored. False after a disconnect.
enabledbooleanFalse while paused: messages are not answered.
webhook_pathstringThe path of the callback URL to give Meta (on the API origin).
numbersarray of WhatsAppNumber10 attributes
idstringconnection_idstringphone_number_idstringdisplay_phone_numberstringverified_namestring | nullassistant_idstring | nullenabledbooleanmodestringOne of
livetestfailed_repliesintegerList only: replies that could not be sent.
failed_turnsintegerList only: incoming messages the assistant failed to answer.
- 400
invalid_request: the body failed validation - 403
org_scope_required(needs an org-wide key; project keys get 403) or the role is too low - 404
not_found: no such connection or number in this organization - 409
whatsapp_already_connected,whatsapp_credentials_required,whatsapp_disconnected, or on syncwhatsapp_number_already_connected(a number already belongs to another connection) - 422 Meta refused the request (
meta_<Meta error code>, ormeta_http_<status>), or could not be reached (meta_unreachable, which says nothing about whether Meta acted on it) - 429 Rate limit exceeded (
rate_limited). WaitRetry-Afterseconds. Budgets are per 60-second window: developer API 120 per key and 600 per organization; public chat 30 per IP address, except polling for updates (60 per conversation and IP address) and analytics events (120 per IP address).
curl -X POST "https://api.myleadsfactory.tech/api/integrations/whatsapp/connections" \
-H "Authorization: Bearer $MLF_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Acme Travel WhatsApp",
"waba_id": "102938475610293",
"credentials": {
"access_token": "EAAG...",
"app_secret": "3f6c2a8e4b1d...",
"verify_token": "acme-verify-7d2e9b14c6a04f3e"
}
}'{
"data": {
"id": "id_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
"org_id": "org_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
"name": "Front desk",
"waba_id": "id_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
"api_version": "string",
"configured": true,
"enabled": true,
"webhook_path": "string",
"numbers": [
{
"id": "pn_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
"connection_id": "id_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
"phone_number_id": "+14155550123",
"display_phone_number": "+14155550123",
"verified_name": "string",
"assistant_id": "asst_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
"enabled": true,
"mode": "live",
"failed_replies": 1,
"failed_turns": 1
}
]
}
}Update a WhatsApp connection
PATCH/api/integrations/whatsapp/connections/{id}
enabled: false pauses every number on the account; true resumes. New credentials are checked with Meta before they replace the stored ones. A disconnected account needs credentials to resume (409 whatsapp_credentials_required).
Secret API key, not read-only, org-wide (not pinned to a project). How it works
Path parameters
idstringrequiredWhatsApp connection id.
Request body
namestringup to 100 charactersenabledbooleancredentialsobjectFrom your Meta app. Write-only: stored encrypted and never returned.
3 attributes
access_tokenstringrequiredup to 8192 characterswrite-only, never returnedA system user access token with WhatsApp permissions.
app_secretstringrequiredup to 256 characterswrite-only, never returnedVerifies Meta's callback signatures.
verify_tokenstringrequired16 to 256 characterswrite-only, never returnedAny string you choose; Meta echoes it when it verifies the callback.
Returns
200 Updated
Response attributes
dataWhatsAppConnectionrequired9 attributes
idstringorg_idstringnamestringwaba_idstringThe WhatsApp Business Account id.
api_versionstringconfiguredbooleanCredentials are stored. False after a disconnect.
enabledbooleanFalse while paused: messages are not answered.
webhook_pathstringThe path of the callback URL to give Meta (on the API origin).
numbersarray of WhatsAppNumber10 attributes
idstringconnection_idstringphone_number_idstringdisplay_phone_numberstringverified_namestring | nullassistant_idstring | nullenabledbooleanmodestringOne of
livetestfailed_repliesintegerList only: replies that could not be sent.
failed_turnsintegerList only: incoming messages the assistant failed to answer.
- 400 Invalid body, or resuming would route a number to an assistant whose chat model cannot answer
- 403
org_scope_required(needs an org-wide key; project keys get 403) or the role is too low - 404
not_found: no such connection or number in this organization - 409
whatsapp_already_connected,whatsapp_credentials_required,whatsapp_disconnected, or on syncwhatsapp_number_already_connected(a number already belongs to another connection) - 422 Meta refused the request (
meta_<Meta error code>, ormeta_http_<status>), or could not be reached (meta_unreachable, which says nothing about whether Meta acted on it) - 429 Rate limit exceeded (
rate_limited). WaitRetry-Afterseconds. Budgets are per 60-second window: developer API 120 per key and 600 per organization; public chat 30 per IP address, except polling for updates (60 per conversation and IP address) and analytics events (120 per IP address).
curl -X PATCH "https://api.myleadsfactory.tech/api/integrations/whatsapp/connections/CONNECTION_ID" \
-H "Authorization: Bearer $MLF_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Front desk",
"enabled": true
}'{
"data": {
"id": "id_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
"org_id": "org_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
"name": "Front desk",
"waba_id": "id_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
"api_version": "string",
"configured": true,
"enabled": true,
"webhook_path": "string",
"numbers": [
{
"id": "pn_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
"connection_id": "id_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
"phone_number_id": "+14155550123",
"display_phone_number": "+14155550123",
"verified_name": "string",
"assistant_id": "asst_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
"enabled": true,
"mode": "live",
"failed_replies": 1,
"failed_turns": 1
}
]
}
}Disconnect a WhatsApp account
DELETE/api/integrations/whatsapp/connections/{id}
Disconnects the account: messages stop being answered and the stored credentials are erased. Numbers, assignments and conversation history stay, so reconnecting with new credentials picks up where it left off.
Secret API key, not read-only, org-wide (not pinned to a project). How it works
Path parameters
idstringrequiredWhatsApp connection id.
Returns
200 Disconnected
Response attributes
dataobjectrequired1 attribute
disconnectedbooleanrequiredOne of
true
- 400
invalid_request: the body failed validation - 403
org_scope_required(needs an org-wide key; project keys get 403) or the role is too low - 404
not_found: no such connection or number in this organization - 409
whatsapp_already_connected,whatsapp_credentials_required,whatsapp_disconnected, or on syncwhatsapp_number_already_connected(a number already belongs to another connection) - 422 Meta refused the request (
meta_<Meta error code>, ormeta_http_<status>), or could not be reached (meta_unreachable, which says nothing about whether Meta acted on it) - 429 Rate limit exceeded (
rate_limited). WaitRetry-Afterseconds. Budgets are per 60-second window: developer API 120 per key and 600 per organization; public chat 30 per IP address, except polling for updates (60 per conversation and IP address) and analytics events (120 per IP address).
curl -X DELETE "https://api.myleadsfactory.tech/api/integrations/whatsapp/connections/CONNECTION_ID" \
-H "Authorization: Bearer $MLF_API_KEY"{
"data": {
"disconnected": true
}
}Assign a WhatsApp number to an assistant
PUT/api/integrations/whatsapp/connections/{id}/numbers/{numberId}
Routes the number's WhatsApp messages to an assistant (assistant_id: null unassigns it), optionally pausing just this number. The assistant answers with its web chat model, so that model must be one chat supports.
Secret API key, not read-only, org-wide (not pinned to a project). How it works
Path parameters
idstringrequiredWhatsApp connection id.
numberIdstringrequiredWhatsApp number id, from the connection's
numbers.
Request body
assistant_idstring | nullrequirednot emptyAssistant id, or null to unassign.
enabledbooleanFalse pauses this number only.
modestringOne of
livetest
Returns
200 Assigned
Response attributes
dataWhatsAppNumberrequired10 attributes
idstringconnection_idstringphone_number_idstringdisplay_phone_numberstringverified_namestring | nullassistant_idstring | nullenabledbooleanmodestringOne of
livetestfailed_repliesintegerList only: replies that could not be sent.
failed_turnsintegerList only: incoming messages the assistant failed to answer.
- 400 Invalid body, or the assistant's chat model has no chat adapter
- 403
org_scope_required(needs an org-wide key; project keys get 403) or the role is too low - 404
not_found: no such connection or number in this organization - 409
whatsapp_already_connected,whatsapp_credentials_required,whatsapp_disconnected, or on syncwhatsapp_number_already_connected(a number already belongs to another connection) - 422 Meta refused the request (
meta_<Meta error code>, ormeta_http_<status>), or could not be reached (meta_unreachable, which says nothing about whether Meta acted on it) - 429 Rate limit exceeded (
rate_limited). WaitRetry-Afterseconds. Budgets are per 60-second window: developer API 120 per key and 600 per organization; public chat 30 per IP address, except polling for updates (60 per conversation and IP address) and analytics events (120 per IP address).
curl -X PUT "https://api.myleadsfactory.tech/api/integrations/whatsapp/connections/CONNECTION_ID/numbers/NUMBER_ID" \
-H "Authorization: Bearer $MLF_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"assistant_id": "asst_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f"
}'{
"data": {
"id": "pn_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
"connection_id": "id_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
"phone_number_id": "+14155550123",
"display_phone_number": "+14155550123",
"verified_name": "string",
"assistant_id": "asst_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
"enabled": true,
"mode": "live",
"failed_replies": 1,
"failed_turns": 1
}
}Subscribe an account to its message callback
POST/api/integrations/whatsapp/connections/{id}/subscribe
Tells Meta to post this account's messages to its callback, then Meta verifies it with your verify_token. Use the public API origin with the connection's webhook_path (/public/whatsapp/webhooks/{id}); the older /whatsapp/webhooks/{id} path is also accepted. callback_url must be HTTPS with no query, fragment or credentials, at one of those paths (otherwise 400 whatsapp_public_https_webhook_required).
Secret API key, not read-only, org-wide (not pinned to a project). How it works
Path parameters
idstringrequiredWhatsApp connection id.
Request body
callback_urlstringrequireduriup to 2048 characters
Returns
200 Subscribed
Response attributes
dataobjectrequired1 attribute
subscribedbooleanrequiredOne of
true
- 400
invalid_request: the body failed validation - 403
org_scope_required(needs an org-wide key; project keys get 403) or the role is too low - 404
not_found: no such connection or number in this organization - 409
whatsapp_already_connected,whatsapp_credentials_required,whatsapp_disconnected, or on syncwhatsapp_number_already_connected(a number already belongs to another connection) - 422 Meta refused the request (
meta_<Meta error code>, ormeta_http_<status>), or could not be reached (meta_unreachable, which says nothing about whether Meta acted on it) - 429 Rate limit exceeded (
rate_limited). WaitRetry-Afterseconds. Budgets are per 60-second window: developer API 120 per key and 600 per organization; public chat 30 per IP address, except polling for updates (60 per conversation and IP address) and analytics events (120 per IP address).
curl -X POST "https://api.myleadsfactory.tech/api/integrations/whatsapp/connections/CONNECTION_ID/subscribe" \
-H "Authorization: Bearer $MLF_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"callback_url": "https://example.com/hook"
}'{
"data": {
"subscribed": true
}
}Sync an account's phone numbers
POST/api/integrations/whatsapp/connections/{id}/sync
Fetches the account's current phone numbers from Meta. New numbers arrive unassigned; existing ones keep their assistant.
Secret API key, not read-only, org-wide (not pinned to a project). How it works
Path parameters
idstringrequiredWhatsApp connection id.
Returns
200 The account's numbers
Response attributes
dataarray of WhatsAppNumberrequired10 attributes
idstringconnection_idstringphone_number_idstringdisplay_phone_numberstringverified_namestring | nullassistant_idstring | nullenabledbooleanmodestringOne of
livetestfailed_repliesintegerList only: replies that could not be sent.
failed_turnsintegerList only: incoming messages the assistant failed to answer.
- 400
invalid_request: the body failed validation - 403
org_scope_required(needs an org-wide key; project keys get 403) or the role is too low - 404
not_found: no such connection or number in this organization - 409
whatsapp_already_connected,whatsapp_credentials_required,whatsapp_disconnected, or on syncwhatsapp_number_already_connected(a number already belongs to another connection) - 422 Meta refused the request (
meta_<Meta error code>, ormeta_http_<status>), or could not be reached (meta_unreachable, which says nothing about whether Meta acted on it) - 429 Rate limit exceeded (
rate_limited). WaitRetry-Afterseconds. Budgets are per 60-second window: developer API 120 per key and 600 per organization; public chat 30 per IP address, except polling for updates (60 per conversation and IP address) and analytics events (120 per IP address).
curl -X POST "https://api.myleadsfactory.tech/api/integrations/whatsapp/connections/CONNECTION_ID/sync" \
-H "Authorization: Bearer $MLF_API_KEY"{
"data": [
{
"id": "pn_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
"connection_id": "id_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
"phone_number_id": "+14155550123",
"display_phone_number": "+14155550123",
"verified_name": "string",
"assistant_id": "asst_5f0c2a9e7b1d4c3e8a6f0b2d4c6e8a1f",
"enabled": true,
"mode": "live",
"failed_replies": 1,
"failed_turns": 1
}
]
}