Outbound Notifications API

Overview

The Outbound Notifications API, a Talkdesk Digital Engagement™ solution, allows you to send notification messages at scale through multiple channels, utilizing various message types. You can proactively reach your customers by sending messages via WhatsApp or SMS to multiple recipients in a single batch request.


📘

Use Case

Consider the case where you need to send bulk notifications to your customers — such as order confirmations, appointment reminders, or promotional messages. You can use the Outbound Notifications API to send messages from a WhatsApp or SMS sender you control. For WhatsApp, each message can be sent as free-form content or using pre-approved templates. For SMS, messages are sent as plain text. Each message can target multiple destinations in a single request.


📘

👍


Outbound Notifications API

The Outbound Notifications API lets clients send outbound notification messages in bulk through Talkdesk's outbound messaging service. To send messages, provide the channel, a sender identifier, and an array of messages, each with at least one destination. Content can be sent as plain text or via a pre-approved WhatsApp template, specified by name, language, and optional variables for personalization. Messages are trackable using a unique bulk request identifier and can be grouped with an optional identifier, name, and metadata. Outbound messages can also be linked to active Talkdesk conversations.

Channel support

The API supports the following channels:

WhatsApp — two message types:

  • direct content messages
  • template-based messages
    • For contacts without reply in the last 24 hours, only WhatsApp template messages are permitted. See this process to register templates.

SMS — one message type:

  • plain text messages via the body field

Sender configuration

ChannelSender requirement
WhatsAppMust be configured as a WhatsApp touchpoint in Channels App, following this process.
SMSSMS sender identifier. Must be a valid Talkdesk touchpoint (phone number) registered with the "PROACTIVE" use type.

This operation is asynchronous. A successful call returns 202 Accepted with provider message identifiers and an initial delivery status.

Endpoint

POST https://api.talkdeskapp.com/outbound/notifications
  • Method: POST
  • Path: /outbound/notifications
  • Operation ID: SendOutboundNotificationMessage
  • Tag: Outbound Messaging

Authentication

This endpoint requires the Draft security scheme with the following scope:

  • outbound-notifications:write

Request body

Content type: application/json

Top-level request schema:

FieldTypeRequiredDescription
channelstringYesChannel used to send the notification. Allowed values: WHATSAPP, SMS.
senderstringYesSender identifier applied to all messages in the request.
messagesarrayYesMessages to send. Minimum 1, maximum 500. The message schema depends on the channel (see below).
optionsobjectNoOptional batch-level settings such as grouping metadata and conversation binding. See Request options below.

messages[].destinations[] (common)

Each message must include a destinations array with at least one recipient. This schema is shared across all channels:

FieldTypeRequiredDescription
tostringYesRecipient destination identifier, such as a phone number.
message_idstringNoOptional client-provided message identifier for tracking.

WhatsApp message format

When channel is WHATSAPP, each item in messages[] must provide exactly one of:

  • content — a direct content message
  • template — a template-based message
FieldTypeRequiredDescription
destinationsarrayYesRecipient list. See destinations[] above.
contentobjectConditionallyRequired when sending a direct content message.
templateobjectConditionallyRequired when sending a template-based message.

Direct content messages

Due to Meta restrictions, this only applies to contact numbers that have sent messages to the touchpoint sender within the last 24 hours.

When using content, the payload shape follows the WhatsApp content model.

Text message body

{
  "content": {
    "body": {
      "type": "TEXT",
      "text": "Hello, how can I help you?"
    }
  }
}

Supported direct body variants:

FieldTypeRequiredNotes
content.body.typestringYesTEXT.
content.body.textstringDependsRequired for TEXT.

Template messages

The template must be approved by Meta. The sending success rate depends on the quality of the sender and the template.

The template's header (text, image, video or document), button types, and carousel card layout are now resolved automatically from the approved WhatsApp template configuration. You only need to send the dynamic values below, and every one of them is optional — a template with no placeholders at all still needs nothing but name and language (see the Example below).

When using a template, provide the WhatsApp template metadata:

FieldTypeRequiredDescription
template.namestringYesTemplate name.
template.languagestringYesTemplate language code, for example en.
template.variablesobject<string,string>NoOptional template variables keyed by numeric string, such as "1" and "2".
template.header_variablesobject<string,string>NoVariables for the template header, only used when the header is TEXT and contains a placeholder. Uses its own numeric keys, independent from variables. Omit entirely for IMAGE, VIDEO or DOCUMENT headers — the media is resolved automatically from the template's configuration and never needs to be sent — and for TEXT headers without a placeholder.
template.buttonsarray<object>NoDynamic values for the template's buttons, in the same order as the buttons that need one (URL buttons with a placeholder, and COPY_CODE/authentication buttons). Static buttons (PHONE_NUMBER, plain QUICK_REPLY) are resolved automatically and must be omitted from this array. Omit the whole array if no button needs a dynamic value — the common case. See template.buttons[] below.
template.carouselarray<object>NoOne entry per carousel card, in the same order as the cards configured on the template. Required only for carousel templates; omit entirely otherwise. See template.carousel[] below.

template.buttons[]

FieldTypeRequiredDescription
suffixstringNoDynamic value for the button — the URL's trailing placeholder for a URL button, or the one-time code for a COPY_CODE/authentication button.

template.carousel[]

FieldTypeRequiredDescription
variablesobject<string,string>NoThis card's body variables keyed by numeric string.
buttonsarray<object>NoDynamic values for this card's buttons, following the same rules as template.buttons[] above.

Here's the available language code for the template:

LanguageCode
Afrikaansaf
Arabicar
Arabic (UAE)ar_AE
Arabic (EGY)ar_EG
Arabic (LBN)ar_LB
Arabic (MAR)ar_MA
Arabic (QAT)ar_QA
Azerbaijaniaz
Belarusianbe_BY
Bulgarianbg
Bengalibn
Bengali (IND)bn_IN
Catalanca
Czechcs
Danishda
Germande
German (AUT)de_AT
German (CHE)de_CH
Greekel
Englishen
English (UAE)en_AE
English (AUS)en_AU
English (CAN)en_CA
English (UK)en_GB
English (GHA)en_GH
English (IRL)en_IE
English (IND)en_IN
English (JAM)en_JM
English (MYS)en_MY
English (NZL)en_NZ
English (QAT)en_QA
English (SGP)en_SG
English (UGA)en_UG
English (US)en_US
English (ZAF)en_ZA
Spanishes
Spanish (ARG)es_AR
Spanish (CHL)es_CL
Spanish (COL)es_CO
Spanish (CRI)es_CR
Spanish (DOM)es_DO
Spanish (ECU)es_EC
Spanish (SPA)es_ES
Spanish (HND)es_HN
Spanish (MEX)es_MX
Spanish (PAN)es_PA
Spanish (PER)es_PE
Spanish (URY)es_UY
Estonianet
Persianfa
Finnishfi
Filipinofil
Frenchfr
French (BEL)fr_BE
French (CAN)fr_CA
French (CHE)fr_CH
French (CIV)fr_CI
French (MAR)fr_MA
Irishga
Gujaratigu
Hausaha
Hebrewhe
Hindihi
Croatianhr
Hungarianhu
Indonesianid
Italianit
Japaneseja
Georgianka
Kazakhkk
Kannadakn
Koreanko
Kyrgyz (Kyrgyzstan)ky_KG
Laolo
Lithuanianlt
Latvianlv
Macedonianmk
Malayalamml
Marathimr
Malayms
Norwegiannb
Dutchnl
Dutch (BEL)nl_BE
Punjabipa
Polishpl
Dariprs_AF
Pashtops_AF
Portuguese (BR)pt_BR
Portuguese (POR)pt_PT
Romanianro
Russianru
Kinyarwandarw_RW
Sinhalasi_LK
Slovaksk
Sloveniansl
Albaniansq
Serbiansr
Swedishsv
Swahilisw
Tamilta
Telugute
Thaith
Turkishtr
Ukrainianuk
Urduur
Uzbekuz
Vietnamesevi
Chinese (CHN)zh_CN
Chinese (HKG)zh_HK
Chinese (TAI)zh_TW
Zuluzu

Example:

{
  "template": {
    "name": "welcome_message",
    "language": "en",
    "variables": {
      "1": "Talkdesk",
      "2": "Support Team"
    }
  }
}

Header variables (TEXT header with a placeholder):

{
  "template": {
    "name": "order_notification",
    "language": "en",
    "header_variables": {
      "1": "Wireless Bluetooth Headset"
    },
    "variables": {
      "1": "Jane",
      "2": "ORD20260714"
    }
  }
}

Media header (IMAGE, VIDEO or DOCUMENT — no header_variables needed, the media is resolved from the template configuration):

{
  "template": {
    "name": "video_header_reply",
    "language": "en_US",
    "variables": {
      "1": "Tom",
      "2": "meeting"
    }
  }
}

Buttons (dynamic value for a URL button):

{
  "template": {
    "name": "promotion_offer",
    "language": "en",
    "variables": {
      "1": "Jane"
    },
    "buttons": [
      { "suffix": "579852585149360" }
    ]
  }
}

Carousel template (one entry per card, in card order):

{
  "template": {
    "name": "product_carousel",
    "language": "en",
    "variables": {
      "1": "Jane"
    },
    "carousel": [
      { "variables": { "1": "Giraffe plush", "2": "$29.99" } },
      { "variables": { "1": "Zebra plush", "2": "$19.99" } }
    ]
  }
}

Authentication template (COPY_CODE button, uses buttons[].suffix for the one-time code):

{
  "template": {
    "name": "auth_verification_code",
    "language": "en",
    "variables": {
      "1": "482913"
    },
    "buttons": [
      { "suffix": "482913" }
    ]
  }
}

WhatsApp example request

{
  "channel": "WHATSAPP",
  "sender": "+123456789",
  "messages": [
    {
      "destinations": [
        {
          "to": "+987654321",
          "message_id": "client-msg-1"
        },
        {
          "to": "+5551234567"
        }
      ],
      "template": {
        "name": "welcome_message",
        "language": "en",
        "variables": {
          "1": "Talkdesk",
          "2": "Support Team"
        }
      }
    }
  ],
  "options": {
    "bulk_id": "bulk-123",
    "group_id": "campaign-42",
    "group_name": "Spring promo",
    "group_info": {
      "source": "crm",
      "segment": "vip"
    },
    "bind_conversation": {
      "enabled": true,
      "ttl_in_minutes": 1440
    }
  }
}

SMS message format

When channel is SMS, each item in messages[] must include a body field with the plain text content:

FieldTypeRequiredDescription
destinationsarrayYesRecipient list. See destinations[] above.
bodystringYesThe text content of the SMS message. Must not be empty.

SMS does not support content or template fields. Use body only.

SMS example request

{
  "channel": "SMS",
  "sender": "+123456789",
  "messages": [
    {
      "destinations": [
        {
          "to": "+987654321",
          "message_id": "sms-msg-1"
        }
      ],
      "body": "Your order #12345 has been shipped. Track at: https://example.com/track/12345"
    }
  ],
  "options": {
    "bulk_id": "sms-bulk-456",
    "group_id": "shipping-notifications",
    "group_name": "Order updates"
  }
}

Request options

The optional options object applies settings to the whole request:

FieldTypeRequiredDescription
bulk_idstringNoOptional bulk identifier. If omitted, the service generates a UUID.
group_idstringNoOptional logical group identifier. If omitted, bulk_id is used.
group_namestringNoOptional logical group name.
group_infoobject<string, string>NoOptional metadata map for the group.
bind_conversationobjectNoOptional conversation binding settings (WhatsApp only). Has no effect for SMS channel.

options.bind_conversation

FieldTypeRequiredDescription
enabledbooleanNoWhether sent messages should be bound to conversations. Default: false (WhatsApp only).
ttl_in_minutesintegerNoTime-to-live for the conversation binding, in minutes. Valid range: 30–21600 (30 minutes to 15 days). Only applicable when enabled is true (WhatsApp only).

Success response

Status code:

  • 202 Accepted

Response schema:

FieldTypeRequiredDescription
bulk_idstringYesUnique bulk identifier for the accepted request.
messagesarrayYesPer-destination acceptance results.

messages[] in the response

FieldTypeDescription
message_idstringUnique provider message identifier.
destinationstringDestination that the message was accepted for.
statusstringInitial message status. Current documented value: PENDING.

Example:

{
  "bulk_id": "0f0d3c86-2355-4409-9968-ac871cdf88d0",
  "messages": [
    {
      "message_id": "infobip-msg-id-123",
      "destination": "+987654321",
      "status": "PENDING"
    }
  ]
}

Error responses

StatusMeaningExample body
400Bad Request{"code":"2140001","message":"Bad Request"}
401Unauthorized{"code":"2140002","message":"Unauthorized"}
403Forbidden{"code":"2140003","message":"Forbidden"}
500Internal Server Error{"code":"2140007","message":"Internal Server Error"}

Notes

  • The request is batch-oriented: one call can submit up to 500 messages.
  • The response confirms acceptance, not final delivery.
  • A destination can include a client-side message_id for correlation.
  • Message grouping and conversation binding are controlled at the request level through options.
  • WhatsApp messages are delivered via the Infobip provider. SMS messages are delivered via the Twilio provider.
  • SMS does not support template-based messages or direct content messages (content). Use the body field for SMS.
  • The bind_conversation option only applies to WhatsApp. It has no effect for SMS.

Did this page help you?