# Telnyx Messaging: WhatsApp — Full Documentation
> Complete page content for WhatsApp (Messaging section) of the Telnyx developer docs (https://developers.telnyx.com).
> This file: https://developers.telnyx.com/docs/development/llms/messaging-whatsapp-llms-full-txt.md · Root index: https://developers.telnyx.com/llms.txt
## Getting Started
### Quickstart
> Source: https://developers.telnyx.com/docs/messaging/whatsapp/quickstart.md
# Send Your First WhatsApp Message
Get started with WhatsApp Business messaging via Telnyx in minutes. This guide covers account setup, template creation, and sending your first message with delivery confirmation.
## Prerequisites
Before sending WhatsApp messages, ensure you have:
- **Telnyx Account** — [Sign up](https://telnyx.com/sign-up) and verify your account
- **Meta Business Manager Account** — Required for WhatsApp Business Platform access
- **WhatsApp Business Account (WABA)** — Connected via Telnyx's Embedded Signup
- **Verified phone number** — Added to your WABA and verified with Meta
WhatsApp Business Platform requires business verification through Meta's process. Personal WhatsApp accounts cannot send template messages via the API.
1. Create a [Telnyx account](https://telnyx.com/sign-up) and verify your email
2. Navigate to the [Portal](https://portal.telnyx.com) and complete account verification
3. Add billing information to enable message sending
4. Generate an API key from **Developer Center → API Keys → Create API Key**
Store your API key securely — you'll need it for all API requests.
Complete the WhatsApp Embedded Signup to connect your Meta Business Manager:
1. Navigate to **Messaging → WhatsApp** in the Telnyx Portal
2. Click **Connect WhatsApp Business Account**
3. Sign in with your Facebook Business Manager credentials
4. Select the Business Manager account to connect
5. Follow Meta's prompts to create or select a WhatsApp Business Account
6. Verify your business phone number when prompted
Use a Telnyx number with an active messaging profile that you haven't used with personal WhatsApp. The embedded signup flow currently requires Telnyx-owned numbers — bring-your-own-number is not yet supported through the portal.
If you're registering a landline number, choose **phone call verification** instead of SMS when prompted. SMS delivery to landline numbers can be unreliable — call verification is more consistent.
WhatsApp requires pre-approved templates for outbound marketing and notifications:
Set a display name for the phone number before submitting templates. Templates submitted from numbers without an approved display name are rejected by Meta.
When a template contains parameters (e.g., `\{\{1\}\}`), provide sample values in the `example` field. Meta reviewers use these to evaluate the template. Without sample values, templates are typically rejected.
Complete the business profile (website, description, industry category) before submitting templates. Incomplete profiles increase rejection rates, especially for new WhatsApp Business Accounts.
Create a message template using the API:
```bash cURL
curl -X POST "https://api.telnyx.com/v2/whatsapp/message_templates" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "welcome_message",
"category": "MARKETING",
"language": "en_US",
"waba_id": "YOUR_WABA_ID",
"components": [
{
"type": "BODY",
"text": "Hello {{1}}! Welcome to our WhatsApp updates.",
"example": {
"body_text": [["John"]]
}
}
]
}'
```
```javascript JavaScript
import Telnyx from 'telnyx';
const client = new Telnyx({apiKey: 'YOUR_API_KEY'});
const template = await client.whatsapp.templates.create({
name: 'welcome_message',
category: 'MARKETING',
language: 'en_US',
waba_id: 'YOUR_WABA_ID',
components: [
{
type: 'BODY',
text: 'Hello {{1}}! Welcome to our WhatsApp updates.',
example: {
body_text: [['John']]
}
}
]
});
```
```python Python
from telnyx import Telnyx
client = Telnyx(api_key='YOUR_API_KEY')
template = client.whatsapp.templates.create(
name='welcome_message',
category='MARKETING',
language='en_US',
waba_id='YOUR_WABA_ID',
components=[
{
'type': 'BODY',
'text': 'Hello {{1}}! Welcome to our WhatsApp updates.',
'example': {
'body_text': [['John']]
}
}
]
)
```
```ruby Ruby
require 'telnyx'
telnyx.whatsapp.templates.create(
name: 'welcome_message',
category: 'MARKETING',
language: 'en_US',
waba_id: 'YOUR_WABA_ID',
components: [
{
type: 'BODY',
text: 'Hello {{1}}! Welcome to our WhatsApp updates.',
example: {
body_text: [['John']]
}
}
]
)
```
Meta typically reviews templates within 24-48 hours. You'll receive an email when approved.
Start with simple templates for faster approval. Avoid promotional language or special characters in your first template.
Once your template is approved, send your first message:
```bash cURL
curl -X POST "https://api.telnyx.com/v2/messages/whatsapp" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "+15551234567",
"to": "+15557654321",
"whatsapp_message": {
"type": "template",
"template": {
"name": "welcome_message",
"language": {
"policy": "deterministic",
"code": "en_US"
},
"components": [
{
"type": "body",
"parameters": [
{
"type": "text",
"text": "John"
}
]
}
]
}
}
}'
```
```python Python
from telnyx import Telnyx
client = Telnyx(api_key='YOUR_API_KEY')
response = client.messages.send_whatsapp(
from_="+15551234567",
to="+15557654321",
whatsapp_message={
"type": "template",
"template": {
"name": "welcome_message",
"language": {
"policy": "deterministic",
"code": "en_US"
},
"components": [
{
"type": "body",
"parameters": [
{
"type": "text",
"text": "John"
}
]
}
]
}
}
)
print(f"Message ID: {response.data.id}")
print(f"Status: {response.data.to[0].status}")
```
```javascript Node.js
import Telnyx from 'telnyx';
const client = new Telnyx({apiKey: 'YOUR_API_KEY'});
const message = await client.messages.sendWhatsapp({
from: '+15551234567',
to: '+15557654321',
whatsapp_message: {
type: 'template',
template: {
name: 'welcome_message',
language: {
policy: 'deterministic',
code: 'en_US'
},
components: [
{
type: 'body',
parameters: [
{
type: 'text',
text: 'John'
}
]
}
]
}
}
});
console.log(`Message ID: ${message.data.id}`);
console.log(`Status: ${message.data.to[0].status}`);
```
```ruby Ruby
require 'telnyx'
response = telnyx.messages.send_whatsapp(
from: '+15551234567',
to: '+15557654321',
whatsapp_message: {
type: 'template',
template: {
name: 'welcome_message',
language: {
policy: 'deterministic',
code: 'en_US'
},
components: [
{
type: 'body',
parameters: [
{
type: 'text',
text: 'John'
}
]
}
]
}
}
)
puts "Message ID: #{response.data.id}"
puts "Status: #{response.data.to[0].status}"
```
```go Go
package main
import (
"context"
"fmt"
"github.com/team-telnyx/telnyx-go/v2"
)
func main() {
client := telnyx.NewAPIClient(telnyx.NewConfiguration())
client.GetConfig().AddDefaultHeader("Authorization", "Bearer YOUR_API_KEY")
parameters := []telnyx.TemplateParameter{
{
Type: telnyx.PtrString("text"),
Text: telnyx.PtrString("John"),
},
}
components := []telnyx.TemplateComponent{
{
Type: telnyx.PtrString("body"),
Parameters: parameters,
},
}
template := telnyx.WhatsAppTemplate{
Name: telnyx.PtrString("welcome_message"),
Language: &telnyx.TemplateLanguage{
Policy: telnyx.PtrString("deterministic"),
Code: telnyx.PtrString("en_US"),
},
Components: components,
}
whatsappMessage := telnyx.WhatsAppMessageContent{
Type: telnyx.PtrString("template"),
Template: &template,
}
params := telnyx.MessageSendWhatsappParams{
From: "+15551234567",
To: "+15557654321",
WhatsappMessage: whatsappMessage,
}
response, err := client.Messages.SendWhatsapp(context.TODO(), params)
if err != nil {
panic(err)
}
fmt.Printf("Message ID: %s\n", response.Data.Id)
fmt.Printf("Status: %s\n", response.Data.To[0].Status)
}
```
```java Java
import com.telnyx.sdk.ApiClient;
import com.telnyx.sdk.ApiException;
import com.telnyx.sdk.Configuration;
import com.telnyx.sdk.auth.HttpBearerAuth;
import com.telnyx.sdk.api.MessagesApi;
import com.telnyx.sdk.model.*;
import java.util.Arrays;
public class WhatsAppQuickstart {
public static void main(String[] args) {
ApiClient defaultClient = Configuration.getDefaultApiClient();
HttpBearerAuth bearerAuth = (HttpBearerAuth) defaultClient.getAuthentication("bearerAuth");
bearerAuth.setBearerToken("YOUR_API_KEY");
MessagesApi apiInstance = new MessagesApi(defaultClient);
TemplateParameter parameter = new TemplateParameter()
.type("text")
.text("John");
TemplateComponent component = new TemplateComponent()
.type("body")
.parameters(Arrays.asList(parameter));
TemplateLanguage language = new TemplateLanguage()
.policy("deterministic")
.code("en_US");
WhatsAppTemplate template = new WhatsAppTemplate()
.name("welcome_message")
.language(language)
.components(Arrays.asList(component));
WhatsAppMessageContent whatsappMessage = new WhatsAppMessageContent()
.type("template")
.template(template);
MessageSendWhatsappRequest request = new MessageSendWhatsappRequest()
.from("+15551234567")
.to("+15557654321")
.whatsappMessage(whatsappMessage);
try {
var result = apiInstance.sendWhatsapp(request);
System.out.println("Message ID: " + result.getData().getId());
System.out.println("Status: " + result.getData().getTo().get(0).getStatus());
} catch (ApiException e) {
System.err.println("Exception: " + e.getResponseBody());
}
}
}
```
The messaging profile is automatically resolved from your WhatsApp-enabled phone number specified in the `from` field.
Configure webhooks to receive real-time delivery status updates:
1. In the Telnyx Portal, navigate to **Messaging → Messaging Profiles**
2. Select your messaging profile
3. Set **Webhook URL** to your endpoint (e.g., `https://yourapp.com/webhooks/telnyx`)
4. Enable **Failover URL** for redundancy (optional)
5. Save the configuration
Your webhook endpoint will receive delivery reports and inbound message notifications.
```json
{
"data": {
"event_type": "message.sent",
"id": "msg_123abc",
"occurred_at": "2023-01-01T12:00:00.000Z",
"payload": {
"id": "msg_123abc",
"type": "whatsapp",
"to": "+15557654321",
"from": "+15551234567",
"text": "Hello John! Welcome to our WhatsApp updates.",
"direction": "outbound",
"parts": 1,
"tags": [],
"messaging_profile_id": "your_messaging_profile_id",
"billing_type": "whatsapp_marketing",
"valid_until": "2023-01-01T12:30:00.000Z"
}
}
}
```
Implement webhook handling to track message status and respond to inbound messages:
```python Python
from flask import Flask, request, jsonify
import hmac
import hashlib
app = Flask(__name__)
@app.route('/webhooks/telnyx', methods=['POST'])
def handle_webhook():
webhook_data = request.json
event_type = webhook_data['data']['event_type']
payload = webhook_data['data']['payload']
if event_type == 'message.sent':
print(f"WhatsApp message sent: {payload['id']}")
print(f"Status: {payload.get('to', [{}])[0].get('status', 'unknown')}")
elif event_type == 'message.received':
print(f"WhatsApp message received: {payload['text']}")
print(f"From: {payload['from']}")
# Auto-reply during 24-hour window
reply_to_customer(payload['from'], payload['to'])
return '', 200
def reply_to_customer(customer_number, business_number):
from telnyx import Telnyx
client = Telnyx(api_key="YOUR_API_KEY")
# Send free-form message (no template required in 24hr window)
client.messages.send_whatsapp(
from_=business_number,
to=customer_number,
whatsapp_message={
"type": "text",
"text": {
"body": "Thanks for your message! We'll get back to you soon.",
"preview_url": False
}
}
)
if __name__ == '__main__':
app.run(debug=True)
```
```javascript Node.js
const express = require('express');
import Telnyx from 'telnyx';
const client = new Telnyx({apiKey: 'YOUR_API_KEY'});
const app = express();
app.use(express.json());
app.post('/webhooks/telnyx', async (req, res) => {
const { data } = req.body;
const { event_type, payload } = data;
if (event_type === 'message.sent') {
console.log(`WhatsApp message sent: ${payload.id}`);
console.log(`Status: ${payload.to[0]?.status || 'unknown'}`);
} else if (event_type === 'message.received') {
console.log(`WhatsApp message received: ${payload.text}`);
console.log(`From: ${payload.from}`);
// Auto-reply during 24-hour window
await replyToCustomer(payload.from, payload.to);
}
res.status(200).send();
});
async function replyToCustomer(customerNumber, businessNumber) {
try {
await client.messages.sendWhatsapp({
from: businessNumber,
to: customerNumber,
whatsapp_message: {
type: 'text',
text: {
body: "Thanks for your message! We'll get back to you soon.",
preview_url: false
}
}
});
} catch (error) {
console.error('Error sending reply:', error);
}
}
app.listen(3000, () => {
console.log('Webhook server listening on port 3000');
});
```
## Verify Message Delivery
Check message delivery through multiple channels:
### Portal Dashboard
1. Navigate to **Messaging → Message Logs** in the Telnyx Portal
2. Filter by **Channel: WhatsApp** and **Date Range**
3. View delivery status, timestamps, and any error codes
4. Click individual messages for detailed delivery information
### Webhook Events
Monitor these key webhook events:
- `message.sent` — Message successfully submitted to WhatsApp
- `message.delivered` — Message delivered to recipient's device
- `message.read` — Recipient opened and read the message (when enabled by recipient)
- `message.failed` — Message delivery failed (with error details)
### API Response
The initial API response includes:
```json
{
"data": {
"id": "msg_123abc",
"to": [
{
"phone_number": "+15557654321",
"status": "queued",
"carrier": "WhatsApp"
}
]
}
}
```
## Common Issues
**Symptoms:** API returns a `40008` error indicating the template was not found or not approved
**Solutions:**
- Verify template status in Portal under **Messaging → WhatsApp → Send Messages**
- Ensure template name matches exactly (case-sensitive)
- Wait for Meta's approval (typically 24-48 hours for first templates)
- Review Meta's template guidelines for approval requirements
**Symptoms:** API returns a `40008` error indicating the sender phone number is not registered with WhatsApp
**Solutions:**
- Complete phone number verification in the Telnyx Portal
- Ensure number is added to your WhatsApp Business Account
- Verify the number through Meta's verification process
- Check that the number hasn't been used with personal WhatsApp
**Symptoms:** Free-form (session) message fails with a `40008` error. WhatsApp requires a template to initiate conversations outside the 24-hour window
**Solutions:**
- Use approved message templates for outbound messaging
- Only send free-form messages within 24 hours of customer's last message
- Check conversation window status via webhook events
- Consider switching to template-based messaging for customer re-engagement
**Symptoms:** Message status webhook returns `undeliverable` with Meta API error details in the response
**Solutions:**
- Verify recipient has WhatsApp installed and active
- Ensure phone number format includes country code (+1...)
- Check that recipient hasn't blocked your business number
- Confirm recipient's WhatsApp account is not banned or restricted
## Next Steps
Send templates, text, media, and interactive messages
Set up your WhatsApp Business Account and verify your number
Handle inbound messages and delivery status callbacks
---
### Embedded Signup
> Source: https://developers.telnyx.com/docs/messaging/whatsapp/embedded-signup.md
# WhatsApp Embedded Signup
WhatsApp Embedded Signup enables businesses to connect their Facebook Business Manager account to Telnyx and provision WhatsApp Business Account (WABA) resources through a streamlined browser-based workflow.
## Prerequisites
Before starting the embedded signup process:
**Required account status:**
- Active Telnyx account with messaging enabled
- Valid payment method configured
- Account in good standing with no billing issues
**Portal access:**
- Log in to [Telnyx Portal](https://portal.telnyx.com)
- Navigate to **Messaging** → **WhatsApp**
- Ensure you have admin permissions for your organization
**Business Manager requirements:**
- Facebook Business Manager account ([business.facebook.com](https://business.facebook.com))
- Admin access to the Business Manager account
- Business verification completed (recommended for production use)
**Important limitations:**
- Each phone number can only be associated with one Business Manager
- Business Manager must have appropriate permissions for WhatsApp Business API
- Account must comply with Facebook Business policies
Ensure your Facebook Business Manager is fully set up and verified before starting embedded signup. Incomplete Business Manager setup can cause signup failures that require manual intervention.
## Signup Flow Overview
The embedded signup process follows a multi-step finite state machine (FSM) that progresses through these states:
```mermaid
graph LR
A[initiated] --> B[facebook_auth]
B --> C[waba_created]
C --> D[phone_registered]
D --> E[verified]
B --> F[failed]
C --> F
D --> F
E --> G[active]
style A fill:#e1f5fe
style E fill:#c8e6c9
style F fill:#ffcdd2
style G fill:#4caf50,color:#fff
```
Each state represents a checkpoint in the signup process with specific completion criteria and potential failure points.
## Step-by-Step Signup Process
**From Telnyx Portal:**
1. Navigate to **Messaging** → **WhatsApp** → **Getting Started**
2. Click **Connect WhatsApp Business**
3. Review the permissions and requirements displayed
4. Click **Begin Setup** to start the embedded signup flow
**What happens:**
- Telnyx creates a signup session with state `initiated`
- Portal generates a secure OAuth URL for Facebook authorization
- Session tracking begins for completion monitoring
**Verification:**
Signup session monitoring is handled automatically by the portal. API-based signup tracking may not be available in all configurations.
```bash
# Check signup session status via API
curl -X GET "https://api.telnyx.com/v2/whatsapp/signup/{signup_id}/status" \
-H "Authorization: Bearer YOUR_API_KEY"
# Response
{
"data": {
"id": "signup_123abc",
"state": "initiated",
"created_at": "2024-01-15T10:30:00Z"
}
}
```
**Facebook authorization flow:**
1. Browser redirects to Facebook Business Manager OAuth consent screen
2. Review the requested permissions:
- **WhatsApp Business Management** — Create and manage WABA
- **Business Asset Management** — Associate phone numbers and templates
- **Webhook Management** — Configure message and status webhooks
3. Click **Continue** to grant permissions
4. Select target Business Manager if you have multiple
**What happens:**
- Facebook validates your Business Manager admin status
- OAuth token is generated and securely transmitted to Telnyx
- Signup state advances to `facebook_auth`
**Common issues:**
- **Permission denied:** Ensure you have admin access to Business Manager
- **Business not verified:** Some features require verified Business Manager
- **Already connected:** Phone number may be connected to another provider
**Verification:**
The Portal will show "Connected to Facebook" with Business Manager details when successful.
**WABA provisioning:**
Telnyx automatically creates your WhatsApp Business Account using the connected Business Manager:
1. WABA is created under your Business Manager
2. Telnyx is granted the necessary permissions as a solution partner
3. Initial configuration is applied (timezone, business category)
4. Webhook endpoints are pre-configured for Telnyx integration
**What happens:**
- Facebook creates the WABA resource
- Telnyx receives WABA credentials and configuration details
- Signup state advances to `waba_created`
- WABA settings are synced to Telnyx systems
**WABA configuration:**
- **Business category:** Inherited from Business Manager
- **Webhooks:** Configured via your messaging profile webhook settings
**Verification:**
```bash
# List WABAs for your account
curl -X GET "https://api.telnyx.com/v2/whatsapp/business_accounts" \
-H "Authorization: Bearer YOUR_API_KEY"
# Response
{
"data": [
{
"id": "waba_456def",
"name": "Your Business Name",
"status": "APPROVED",
"waba_id": "2019979452207634"
}
]
}
```
**Number selection and registration:**
1. Portal displays available phone numbers from your Telnyx inventory
2. Select the phone number to register for WhatsApp
3. Choose the WABA to associate with the number
4. Confirm the registration request
**Phone number requirements:**
- Must be a Telnyx number with an active messaging profile assigned
- Cannot be currently registered with another WhatsApp provider
- Can be used alongside SMS/voice on the same number — WhatsApp uses a separate API path
The embedded signup flow currently requires a Telnyx-owned number with a messaging profile. Bring-your-own-number (non-Telnyx numbers) is not yet supported through the portal signup flow. If you need to register an external number, contact support for assistance.
**What happens:**
- Phone number is submitted to Facebook for WhatsApp registration
- Facebook begins the verification process
- Signup state advances to `phone_registered`
- Number status changes to "pending verification"
**Registration details:**
- **Number format:** E.164 format (+1234567890)
- **Verification method:** Automatically determined by Facebook
- **Processing time:** Usually 1-5 minutes for verification
**Verification:**
```bash
# Check phone number registration status
curl -X GET "https://api.telnyx.com/v2/whatsapp/phone_numbers" \
-H "Authorization: Bearer YOUR_API_KEY"
# Response
{
"data": [
{
"phone_number": "+15551234567",
"business_account_id": "waba_456def",
"status": "pending_verification",
"registered_at": "2024-01-15T11:15:00Z"
}
]
}
```
**Facebook verification process:**
Facebook automatically verifies phone numbers using multiple methods:
1. **Carrier validation:** Facebook verifies number ownership with telecom provider
2. **SMS verification:** Test SMS may be sent to validate delivery capability
3. **API validation:** Facebook tests webhook delivery and response handling
**Verification timeline:**
- **Typical duration:** 1-15 minutes
- **Complex cases:** Up to 24 hours for carrier validation
- **Failed attempts:** May require manual review or different number
**What happens:**
- Facebook completes all verification checks
- Number status updates to "verified" in Facebook systems
- Signup state advances to `verified`
- Number becomes available for sending messages
**Verification methods Facebook may use:**
Automated voice call to verify number is operational and accessible.
**Duration:** 30 seconds
**Requirements:** Number must accept incoming calls
Test SMS sent to verify message delivery capability.
**Message:** "Facebook verification code: [CODE]"
**Requirements:** Number must receive SMS messages
Direct verification with mobile carrier for number ownership.
**Duration:** Instant to 24 hours
**Requirements:** Carrier must support Facebook verification API
**Verification completion:**
```bash
# Final verification status
curl -X GET "https://api.telnyx.com/v2/whatsapp/phone_numbers/+15551234567" \
-H "Authorization: Bearer YOUR_API_KEY"
# Response
{
"data": {
"phone_number": "+15551234567",
"business_account_id": "waba_456def",
"status": "verified",
"verified_at": "2024-01-15T11:20:00Z",
"enabled": true,
"calling_enabled": false
}
}
```
## Signup Completion
When verification succeeds, your WhatsApp integration is ready:
### Account Status
- **WABA Status:** Active and ready for messaging
- **Phone Number:** Verified and enabled for sending/receiving
- **Webhooks:** Configured and receiving events
- **Templates:** Ready for submission and approval
### Next Steps After Signup
Send templates, text, media, and interactive messages
Send your first WhatsApp message end-to-end
Handle inbound messages and delivery status callbacks
## Troubleshooting Common Issues
**Error:** "You don't have permission to complete this action"
**Causes:**
- Not admin of Business Manager account
- Business Manager doesn't have WhatsApp permissions
- Account suspended or restricted
**Solutions:**
1. Verify admin access in Business Manager
2. Contact Facebook Business Support if account restricted
3. Use different Business Manager account
4. Check account verification status
**Error:** "Unable to create WhatsApp Business Account"
**Causes:**
- Business Manager doesn't meet Facebook requirements
- Too many existing WABAs on Business Manager
- Business policy violations
**Solutions:**
1. Complete Business Manager verification
2. Review and resolve any policy violations
3. Remove unused WABAs from Business Manager
4. Contact Telnyx support with signup session ID
**Error:** "This phone number is already connected to WhatsApp Business API"
**Causes:**
- Number registered with another Business Service Provider
- Number previously registered but not properly disconnected
- Number registered to different WABA
**Solutions:**
1. Disconnect number from previous provider
2. Contact previous provider to release number
3. Use different phone number for registration
4. Contact Facebook Business Support for assistance
**Error:** "Phone number verification failed" or timeout
**Causes:**
- Number doesn't support voice calls or SMS
- Carrier blocking verification attempts
- Number routing issues
**Solutions:**
1. Verify number accepts incoming calls and SMS
2. Try different phone number if possible
3. Contact carrier to check for blocks
4. Wait and retry verification process
5. Contact Telnyx support with verification details
**Error:** Webhooks not receiving events after successful signup
**Causes:**
- Webhook URL not properly configured
- Firewall blocking webhook delivery
- Invalid webhook signature verification
**Solutions:**
1. Verify webhook URL accessibility from Facebook servers
2. Check webhook signature verification implementation
3. Review webhook configuration in Portal
4. Test webhook endpoint with manual POST requests
5. Check logs for delivery attempts and errors
**Symptom:** Embedded signup popup fails to load, shows a blank page, or gets stuck during the Facebook OAuth step.
**Causes:**
- Ad blockers (uBlock Origin, Adblock Plus, etc.) blocking Facebook/Meta domains
- Privacy extensions (Privacy Badger, Ghostery) blocking third-party scripts
- Browser security settings blocking cross-origin popups
**Solutions:**
1. Temporarily disable ad blockers and privacy extensions for the signup flow
2. Add `facebook.com` and `meta.com` domains to your extension's allowlist
3. Try using a different browser profile without extensions
4. Use Chrome Incognito mode (extensions are typically disabled by default)
5. Ensure popup blockers allow popups from the Telnyx Portal domain
**Note:** The WhatsApp embedded signup flow is powered by Meta/Facebook. The OAuth consent screen and business verification steps are hosted on Facebook's servers, which means browser extensions that block Facebook domains will prevent the signup from completing.
## API Integration
### Signup Session Monitoring
Monitor signup progress programmatically using the Signup API:
```bash cURL
curl -X GET "https://api.telnyx.com/v2/whatsapp/signup/{signup_id}/status" \
-H "Authorization: Bearer YOUR_API_KEY"
```
### Webhook Events
Receive real-time signup progress updates:
```json
{
"data": {
"event_type": "whatsapp.signup.state_updated",
"payload": {
"signup_id": "signup_123abc",
"state": "verified",
"previous_state": "phone_registered",
"waba_id": "waba_456def",
"phone_number": "+15551234567",
"occurred_at": "2024-01-15T11:20:00Z"
}
}
}
```
---
### Tech Provider Embedded Signup
> Source: https://developers.telnyx.com/docs/messaging/whatsapp/embedded-signup/tech-provider.md
WhatsApp Tech Provider Embedded Signup lets ISVs and SaaS platforms embed Meta's WhatsApp onboarding flow directly into their own portal. Your end-customers can create and register a WhatsApp Business Account (WABA), claim a phone number, and begin messaging — all without leaving your application.
Unlike the [standard embedded signup flow](/docs/messaging/whatsapp/embedded-signup), which is designed for direct Telnyx customers, the Tech Provider flow is built for partners who manage multiple end-customers and need programmatic control over WABA provisioning.
## Overview
As a Tech Provider, you build the onboarding experience into your own product. The end-customer clicks a button in your portal, completes Meta's embedded signup flow, and your backend receives the resulting WABA ID and phone number ID. You then register the WABA with Telnyx so that it can use Telnyx's messaging infrastructure.
Telnyx offers two integration paths: a **hosted signup** option where Telnyx manages the entire signup UI and backend processing (recommended for most Tech Providers), and a **custom integration** option where you embed Meta's Facebook SDK directly into your own portal for full control over the experience. See [Step 3](#step-3-choose-your-integration-path) for a comparison.
```mermaid
sequenceDiagram
participant EndCustomer as End Customer
participant PartnerPortal as Your Portal
participant Meta as Meta
participant Telnyx as Telnyx API
EndCustomer->>PartnerPortal: Clicks "Connect WhatsApp"
PartnerPortal->>Meta: Launches embedded signup (FB.login)
Meta->>EndCustomer: Shows signup & business verification
EndCustomer->>Meta: Completes signup
Meta-->>PartnerPortal: Returns WABA ID + Phone Number ID
PartnerPortal->>Telnyx: POST /whatsapp/business_accounts/tech_provider
Telnyx-->>PartnerPortal: 200 OK — WABA registered
Telnyx->>PartnerPortal: Credit line applied, number ready
PartnerPortal->>EndCustomer: WhatsApp connected ✅
```
### Tech Provider vs. Direct Customer
| | Tech Provider | Direct Customer |
|---|---|---|
| **Who uses this?** | ISVs, SaaS platforms, resellers | Individual businesses |
| **Onboarding** | Embedded in your portal | Via Telnyx portal or API |
| **WABA ownership** | Your end-customers own their WABAs | You own your WABA |
| **API calls** | You call Telnyx on behalf of customers | You call Telnyx directly |
| **Scale** | Many WABAs under one integration | One WABA per integration |
## Prerequisites
Before you begin, make sure you have:
- A [Meta Business Account](https://business.facebook.com/) with admin access
- A **Meta Tech Provider App** that has been approved by Meta with the following permissions:
- `whatsapp_business_messaging`
- `whatsapp_business_management`
- The Tech Provider onboarding process completed in [Meta App Dashboard](https://developers.facebook.com/apps/)
- A [Telnyx account](https://telnyx.com/sign-up) with an API key
All links to Meta documentation in this guide require that you are logged in to a Meta Business account. If you don't have one, create one at [business.facebook.com](https://business.facebook.com/) before proceeding.
## Step 1: Create and configure your Meta Tech Provider App
Go to [Meta App Dashboard](https://developers.facebook.com/apps/) and create a new app. Select **Business** as the app type.
In your app's dashboard, add the **WhatsApp** product. This will generate the permissions you need.
Under **App Review > Permissions and Features**, request the following permissions:
| Permission | Purpose |
|---|---|
| `whatsapp_business_messaging` | Send and receive WhatsApp messages on behalf of your customers |
| `whatsapp_business_management` | Manage WhatsApp Business Accounts and phone numbers |
Both permissions require **Advanced Access** for production use.
Follow Meta's [Tech Provider onboarding guide](https://developers.facebook.com/docs/development/create-an-app/business-onboarding) to complete the Tech Provider registration process. This includes business verification and agreeing to Meta's Tech Provider terms.
Submit your app for Meta's App Review. Meta will evaluate your use case and grant (or deny) the requested permissions. This process typically takes several business days.
While waiting for App Review approval, you can test in **Development Mode** with your own test users. Production use requires **Live Mode** and Advanced Access permissions.
## Step 2: Link your Meta App to Telnyx
Once your Meta App is configured, you need to link it to Telnyx so that WABAs created through your embedded signup flow are registered on Telnyx's infrastructure.
In the [Meta App Dashboard](https://developers.facebook.com/apps/), change your app mode from **Development** to **Live**. This is required for Telnyx to initiate the partner invitation.
Reach out to your Telnyx representative or contact [support](https://support.telnyx.com) and provide:
- Your **Meta App ID** (found in your app's dashboard)
- Your **business name** as registered with Meta
Within 1–2 business days, you'll receive an email from Meta containing a partner invitation link. Click the link and accept the invitation to link your app with Telnyx.
After accepting the invitation, you can switch your app back to **Development** mode for testing. The link persists regardless of the app mode.
You must switch your app to **Live mode** before Telnyx can send the partner invitation. The invitation will fail if your app is in Development mode. After accepting the invite, you can switch back to Development mode for testing.
## Step 3: Choose your integration path
After your Meta App is linked to Telnyx, you have two ways to onboard your end-customers' WABAs. Both paths complete the same Meta embedded signup — the difference is **where the signup UI lives** and **how much you build**.
| | Option A: Hosted signup (recommended) | Option B: Custom integration |
|---|---|---|
| **Who it's for** | Most Tech Providers — fastest to ship | ISVs who want full control over the UX |
| **What you build** | One API call to generate a shareable URL | Facebook SDK integration in your own frontend |
| **Signup UI** | Telnyx-hosted page at `acct.fyi` | Embedded directly in your portal |
| **End-customer experience** | Clicks a link → completes Meta signup → done | Clicks a button in your app → Meta popup → you handle the response |
| **Backend code exchange** | Telnyx handles it automatically | You exchange the code with Meta's Graph API |
| **WABA registration** | Telnyx handles it automatically | You call Telnyx's registration API |
With the hosted signup flow, Telnyx hosts the embedded signup page. You generate a time-limited onboarding URL via API and share it with your end-customer. The customer visits the URL, completes Meta's signup, and Telnyx handles the rest — code exchange, webhook subscription, credit line sharing, and phone number registration. No Facebook SDK, no custom JavaScript.
```mermaid
sequenceDiagram
participant TechProvider as Tech Provider
participant Telnyx as Telnyx API
participant EndCustomer as End Customer
participant HostedPage as Telnyx hosted page
participant Meta as Meta
TechProvider->>Telnyx: POST /v2/whatsapp/hosted_signups
Telnyx-->>TechProvider: Returns onboarding URL (acct.fyi?token=…)
TechProvider->>EndCustomer: Shares URL via email/SMS/embed
EndCustomer->>HostedPage: Visits URL
HostedPage->>Meta: Launches Meta embedded signup
Meta->>EndCustomer: Shows signup & business verification
EndCustomer->>Meta: Completes signup
Meta-->>HostedPage: Returns credentials
HostedPage->>Telnyx: Registers WABA, applies credit line, subscribes webhooks
Telnyx-->>TechProvider: WABA registered & ready ✅
```
### Step 3A.1: Generate an onboarding URL
Call the Telnyx API to create a JWT-authenticated onboarding URL for your end-customer. The URL is valid for up to 3 days.
```bash
curl -X POST https://api.telnyx.com/v2/whatsapp/hosted_signups \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"app_id": "123456789012345"
}'
```
#### Request body parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| `app_id` | string | Yes | Your Meta App ID (the same one linked to Telnyx in Step 2) |
| `expires_at` | string (RFC 3339) | No | When the URL expires. Must be at most 3 days in the future. Defaults to 24 hours. |
This endpoint requires authentication with a Telnyx API key. You can create one in the [API Keys](https://portal.telnyx.com/#/app/api-keys) page.
### Response
```json
{
"data": {
"id": "0192345a-7b8c-7d9e-0f12-3456789abcde",
"record_type": "whatsapp_jwt",
"app_id": "123456789012345",
"created_at": "2026-07-08T12:00:00Z",
"expires_at": "2026-07-09T12:00:00Z",
"jwt": "eyJhbGciOiJSUzI1NiIs...",
"url": "https://acct.fyi?token=eyJhbGciOiJSUzI1NiIs..."
}
}
```
| Field | Description |
|---|---|
| `url` | The hosted onboarding URL to share with your end-customer |
| `jwt` | The raw JWT token (also embedded in the URL) |
| `expires_at` | When the URL expires (max 3 days) |
| `id` | Unique identifier for this signup session |
### Step 3A.2: Share the URL with your end-customer
Send the `url` to your end-customer via email, SMS, or embed it as a link in your own portal. When the customer visits the URL:
1. Telnyx validates the JWT and renders a signup page branded with your app's Meta configuration
2. The customer clicks **Get Started** to launch Meta's embedded signup popup
3. The customer signs in to Facebook, creates or selects a WABA, and verifies their phone number
4. On completion, Telnyx automatically handles the backend: code exchange, webhook subscription, credit line sharing, and phone number registration
You can poll the signup status via `GET /v2/whatsapp/signup/{session_id}/status` to track progress and surface it in your own dashboard.
### Step 3A.3: Check signup status (optional)
```bash
curl -X GET "https://api.telnyx.com/v2/whatsapp/signup/019f4253-e09a-7622-bc6f-625378711d78/status" \
-H "Authorization: Bearer YOUR_API_KEY"
```
Returns the signup session record with `status`, `state`, `waba_id`, and any errors. Use this to build a progress indicator in your portal or trigger downstream workflows when onboarding completes.
### What happens after signup
When the end-customer completes the hosted signup:
1. **Credit line is applied** — The WABA is associated with your Telnyx billing account
2. **WABA is registered** — The WhatsApp Business Account is linked to Telnyx's messaging infrastructure
3. **Webhooks are subscribed** — Telnyx subscribes to Meta webhook events on the WABA's behalf
4. **Number is ready for messaging** — The phone number can send and receive WhatsApp messages through Telnyx
If you prefer to embed Meta's signup flow directly into your own portal and handle the code exchange yourself, follow the steps below. This gives you full control over the UX but requires integrating the Facebook JavaScript SDK and calling Meta's Graph API.
### Step 3B.1: Implement the frontend embedded signup
Meta's embedded signup flow is triggered from your web application using the Facebook JavaScript SDK. Your frontend launches the signup dialog, the end-customer completes it, and you receive the resulting credentials.
Add the Facebook SDK to your web application:
```html
```
Call `FB.login()` with the `config_id` of your WhatsApp Business Configuration. This opens Meta's embedded signup dialog for your end-customer.
```javascript
function launchWhatsAppSignup() {
// The response_type must include 'code' and 'setup_token'
FB.login(
function (response) {
if (response.authResponse) {
const code = response.authResponse.code;
// Send the code to your backend to exchange for credentials
sendCodeToBackend(code);
} else {
console.error('User cancelled login or did not fully authorize.');
}
},
{
config_id: 'YOUR_CONFIG_ID',
response_type: 'code',
override_default_response_type: true,
extras: {
setup: {},
featureType: '',
sessionInfoVersion: '3',
},
}
);
}
```
After the user completes the signup, Meta returns an authorization code. Exchange this code using Meta's API to obtain the WABA ID and phone number ID.
```bash
curl -X GET \
"https://graph.facebook.com/v19.0/oauth/access_token?\
client_id=YOUR_APP_ID\
&client_secret=YOUR_APP_SECRET\
&code=AUTHORIZATION_CODE"
```
The response contains access token information. Use this access token to retrieve the WABA ID and phone number ID from the signed request or the response payload:
```json
{
"access_token": "EAAJc...",
"token_type": "bearer",
"expires_in": 5183814
}
```
From the embedded signup response, extract the two critical identifiers:
| Field | Description |
|---|---|
| `waba_id` | The WhatsApp Business Account ID (e.g., `123456789012345`) |
| `phone_number_id` | The phone number ID within that WABA (e.g., `987654321098765`) |
Refer to Meta's [embedded signup documentation](https://developers.facebook.com/documentation/business-messaging/whatsapp/embedded-signup/implementation) for full details on parsing the response. You only need the **frontend (web) portion** of Meta's guide — the backend registration is handled by Telnyx in the next step.
### Step 3B.2: Register the WABA with Telnyx
Once you have the `waba_id` and `phone_number_id` from the embedded signup flow, send them to Telnyx to register the WABA and activate messaging.
#### Request
```bash
curl -X POST https://api.telnyx.com/v2/whatsapp/business_accounts/tech_provider \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"waba_id": "123456789012345",
"phone_number_id": "987654321098765",
"app_id": "123456789012345",
"customer_id": "acme-corp-42"
}'
```
#### Request body parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| `waba_id` | string | Yes | The WABA ID returned by Meta's embedded signup flow |
| `phone_number_id` | string | Yes | The phone number ID returned by Meta's embedded signup flow |
| `app_id` | string | Yes | Your Meta App ID |
| `customer_id` | string | No | An optional identifier you assign to track this customer (e.g., your internal customer ID) |
This endpoint requires authentication with a Telnyx API key via the `Authorization: Bearer` header. Use an API key from your Telnyx account — you can create one in the [API Keys](https://portal.telnyx.com/#/app/api-keys) page.
#### Response
A successful response confirms that the WABA has been registered with Telnyx:
```json
{
"data": {
"waba_id": "123456789012345",
"phone_number_id": "987654321098765",
"status": "registered",
"customer_id": "acme-corp-42"
}
}
```
#### What happens after registration
When the Telnyx API returns a successful response:
1. **Credit line is applied** — The WABA is associated with your Telnyx billing account
2. **WABA is registered** — The WhatsApp Business Account is linked to Telnyx's messaging infrastructure
3. **Number is ready for messaging** — The phone number can send and receive WhatsApp messages through Telnyx
## Troubleshooting
- Verify that your app was in **Live mode** when you contacted Telnyx
- Check your spam and junk folders
- Ensure the email associated with your Meta Business account is correct
- Confirm with your Telnyx representative that they initiated the invitation
- The invitation typically arrives within 1–2 business days
- Review Meta's rejection reasons carefully in the App Review section of your dashboard
- Common reasons include: insufficient permissions justification, unclear use case description, or missing screencast
- Update your submission with clearer documentation and resubmit
- Ensure your app is functional and testable during the review period
- Confirm the Facebook SDK is loaded before calling `FB.login()`
- Check that your `config_id` is correct and matches a WhatsApp Business Configuration in your app
- Ensure your app has the `whatsapp_business_messaging` and `whatsapp_business_management` permissions
- Open your browser's developer console for error messages from the SDK
- Verify you are using a valid Telnyx API key
- Ensure the `Authorization: Bearer YOUR_API_KEY` header is included in your request
- Check that your API key has not expired or been revoked
- Ensure the `response_type` parameter includes `code`
- Check that `override_default_response_type` is set to `true`
- Verify the user completed all steps in the Meta signup flow (business verification, phone number selection)
- Inspect the full response object in your `FB.login()` callback for debug information
- Ensure you're using the full URL returned by `POST /v2/whatsapp_hosted_signups`, including the `?token=` query parameter
- Check that the JWT hasn't expired — tokens are valid for a maximum of 3 days from creation
- If the token has expired, generate a new one via the API
- Verify the phone number entered by the end-customer is correct and can receive SMS
- Check that the phone number is not already registered with another WhatsApp account
- Try requesting the verification code via phone call instead of SMS
- Ensure the end-customer's phone carrier is not blocking Meta's verification messages
## Next steps
Send your first WhatsApp message with Telnyx
Direct customer embedded signup flow
Explore WhatsApp API endpoints
Send messages across all channels
---
## Sending Messages
### Send Messages
> Source: https://developers.telnyx.com/docs/messaging/whatsapp/send-messages.md
Send WhatsApp messages using `POST /v2/messages/whatsapp`. All message types use the same endpoint — the `whatsapp_message` object determines the message type.
```
POST https://api.telnyx.com/v2/messages/whatsapp
```
### Request Structure
Every request requires these fields:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `from` | string | Yes | Your WhatsApp-enabled phone number (E.164) |
| `to` | string | Yes | Recipient phone number (E.164) |
| `whatsapp_message` | object | Yes | Message content — structure varies by type |
| `webhook_url` | string | No | URL for delivery status callbacks |
The messaging profile is automatically resolved from the `from` number. You do not need to pass `messaging_profile_id`.
The `whatsapp_message` object must include a `type` field and the corresponding content object. Supported types: `text`, `template`, `image`, `video`, `document`, `audio`, `sticker`, `location`, `contacts`, `interactive`, `reaction`.
---
## Template Messages
Template messages are required to start conversations outside the 24-hour window. Templates must be pre-approved by Meta.
Error code `40008` indicates the template could not be used for sending. Possible causes include: the template is still pending review, was rejected by Meta, has been paused due to quality issues, or was disabled. Check template status in the Telnyx Portal or via `GET /v2/whatsapp/message_templates`.
Text, media, and interactive messages can only be sent within a 24-hour conversation window. The window opens when the recipient sends a message to the business number. Outside this window, use an approved template message to initiate the conversation.
For comprehensive template creation guidance, see the [Manage Templates guide](/docs/messaging/whatsapp/manage-templates).
```bash cURL
curl -X POST https://api.telnyx.com/v2/messages/whatsapp \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "+15551234567",
"to": "+15557654321",
"whatsapp_message": {
"type": "template",
"template": {
"name": "order_confirmation",
"language": {
"policy": "deterministic",
"code": "en_US"
},
"components": [
{
"type": "body",
"parameters": [
{"type": "text", "text": "John"},
{"type": "text", "text": "ORD-12345"}
]
}
]
}
}
}'
```
```python Python
from telnyx import Telnyx
client = Telnyx(api_key="YOUR_API_KEY")
client.messages.send_whatsapp(
from_="+15551234567",
to="+15557654321",
whatsapp_message={
"type": "template",
"template": {
"name": "order_confirmation",
"language": {"policy": "deterministic", "code": "en_US"},
"components": [
{
"type": "body",
"parameters": [
{"type": "text", "text": "John"},
{"type": "text", "text": "ORD-12345"}
]
}
]
}
}
)
```
```javascript Node.js
import Telnyx from 'telnyx';
const client = new Telnyx({apiKey: 'YOUR_API_KEY'});
const message = await client.messages.sendWhatsapp({
from: '+15551234567',
to: '+15557654321',
whatsapp_message: {
type: 'template',
template: {
name: 'order_confirmation',
language: { policy: 'deterministic', code: 'en_US' },
components: [
{
type: 'body',
parameters: [
{ type: 'text', text: 'John' },
{ type: 'text', text: 'ORD-12345' }
]
}
]
}
}
});
```
### Sending by Template ID
Instead of specifying `name` and `language`, you can reference a template by its Telnyx UUID (`template_id`). The name and language are resolved automatically from the database.
```bash cURL
curl -X POST https://api.telnyx.com/v2/messages/whatsapp \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "+15551234567",
"to": "+15557654321",
"whatsapp_message": {
"type": "template",
"template": {
"template_id": "019cd44b-3a1c-781b-956e-bd33e9fd2ac6",
"components": [
{
"type": "body",
"parameters": [
{"type": "text", "text": "John"},
{"type": "text", "text": "ORD-12345"}
]
}
]
}
}
}'
```
You can find a template's UUID by listing templates via `GET /v2/whatsapp/message_templates`. The `id` field in the response is the `template_id` you can use when sending.
### Template Components
Templates use `components` to pass dynamic content into header, body, and button slots:
| Component `type` | `sub_type` | Use |
|-------------------|-----------|-----|
| `header` | — | Media or text for template header |
| `body` | — | Variable substitution in body text |
| `button` | `quick_reply` | Quick reply button payload |
| `button` | `url` | Dynamic URL suffix for CTA buttons |
### Media Header Template
To send a template with an image header:
```json
{
"from": "+15551234567",
"to": "+15557654321",
"whatsapp_message": {
"type": "template",
"template": {
"name": "promo_with_image",
"language": {"policy": "deterministic", "code": "en_US"},
"components": [
{
"type": "header",
"parameters": [
{"type": "image", "image": {"link": "https://example.com/promo.jpg"}}
]
},
{
"type": "body",
"parameters": [
{"type": "text", "text": "20%"}
]
}
]
}
}
}
```
Header parameters also support `document` and `video` types with the same `{link, caption, filename}` structure.
---
## Text Messages
Send plain text within the 24-hour conversation window. Body must be 1–4096 bytes.
```bash cURL
curl -X POST https://api.telnyx.com/v2/messages/whatsapp \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "+15551234567",
"to": "+15557654321",
"whatsapp_message": {
"type": "text",
"text": {
"body": "Thanks for reaching out! How can we help?",
"preview_url": false
}
}
}'
```
```python Python
from telnyx import Telnyx
client = Telnyx(api_key="YOUR_API_KEY")
client.messages.send_whatsapp(
from_="+15551234567",
to="+15557654321",
whatsapp_message={
"type": "text",
"text": {
"body": "Thanks for reaching out! How can we help?",
"preview_url": False
}
}
)
```
```javascript Node.js
import Telnyx from 'telnyx';
const client = new Telnyx({apiKey: 'YOUR_API_KEY'});
const message = await client.messages.sendWhatsapp({
from: '+15551234567',
to: '+15557654321',
whatsapp_message: {
type: 'text',
text: {
body: 'Thanks for reaching out! How can we help?',
preview_url: false
}
}
});
```
Set `preview_url: true` to render link previews when the message body contains a URL.
---
## Media Messages
Send images, videos, documents, audio, and stickers. Each media object requires exactly one of `link` (URL) or `id` (Meta media ID). Captions are optional and limited to 1024 bytes.
### Image
```json
{
"from": "+15551234567",
"to": "+15557654321",
"whatsapp_message": {
"type": "image",
"image": {
"link": "https://example.com/receipt.png",
"caption": "Your receipt for order #12345"
}
}
}
```
### Document
```json
{
"from": "+15551234567",
"to": "+15557654321",
"whatsapp_message": {
"type": "document",
"document": {
"link": "https://example.com/invoice.pdf",
"filename": "invoice_12345.pdf",
"caption": "Invoice for March 2026"
}
}
}
```
### Video
```json
{
"from": "+15551234567",
"to": "+15557654321",
"whatsapp_message": {
"type": "video",
"video": {
"link": "https://example.com/tutorial.mp4",
"caption": "Setup walkthrough"
}
}
}
```
### Audio
```json
{
"from": "+15551234567",
"to": "+15557654321",
"whatsapp_message": {
"type": "audio",
"audio": {
"link": "https://example.com/voicenote.ogg"
}
}
}
```
### Sticker
```json
{
"from": "+15551234567",
"to": "+15557654321",
"whatsapp_message": {
"type": "sticker",
"sticker": {
"link": "https://example.com/sticker.webp"
}
}
}
```
Stickers do not support captions. Audio does not support captions. Only one media type per message.
---
## Location Messages
Share a location pin. Latitude and longitude are passed as **strings** (decimal format).
```json
{
"from": "+15551234567",
"to": "+15557654321",
"whatsapp_message": {
"type": "location",
"location": {
"latitude": "40.7128",
"longitude": "-74.0060",
"name": "Telnyx HQ",
"address": "311 W 43rd St, New York, NY"
}
}
}
```
Latitude must be between -90 and 90. Longitude must be between -180 and 180.
---
## Contact Messages
Share one or more contact cards (1–257 contacts per message).
```json
{
"from": "+15551234567",
"to": "+15557654321",
"whatsapp_message": {
"type": "contacts",
"contacts": [
{
"name": {
"formatted_name": "Jane Smith",
"first_name": "Jane",
"last_name": "Smith"
},
"phones": [
{"phone": "+15559876543", "type": "WORK"}
],
"emails": [
{"email": "jane@example.com", "type": "WORK"}
]
}
]
}
}
```
---
## Interactive Messages
Interactive messages let recipients tap buttons, select from lists, or open URLs. Supported `interactive.type` values:
| Type | Description |
|------|-------------|
| `button` | Up to 3 quick reply buttons |
| `cta_url` | Call-to-action URL button |
| `list` | Selectable list with sections and rows |
| `location_request_message` | Request the recipient's location |
| `carousel` | Scrollable cards with media and buttons |
### Quick Reply Buttons
```json
{
"from": "+15551234567",
"to": "+15557654321",
"whatsapp_message": {
"type": "interactive",
"interactive": {
"type": "button",
"body": {"text": "Would you like to schedule a callback?"},
"action": {
"buttons": [
{"type": "reply", "reply": {"id": "yes_callback", "title": "Yes, call me"}},
{"type": "reply", "reply": {"id": "no_thanks", "title": "No thanks"}}
]
}
}
}
}
```
When a recipient taps a button, you receive an inbound webhook with the button's `id` in the payload.
### CTA URL Button
```json
{
"from": "+15551234567",
"to": "+15557654321",
"whatsapp_message": {
"type": "interactive",
"interactive": {
"type": "cta_url",
"body": {"text": "Track your shipment"},
"action": {
"name": "cta_url",
"parameters": {
"display_text": "Track Order",
"url": "https://example.com/track/12345"
}
}
}
}
}
```
### List Messages
```json
{
"from": "+15551234567",
"to": "+15557654321",
"whatsapp_message": {
"type": "interactive",
"interactive": {
"type": "list",
"body": {"text": "Select a support topic:"},
"action": {
"button": "Choose topic",
"sections": [
{
"title": "Account",
"rows": [
{"id": "billing", "title": "Billing", "description": "Payment and invoice questions"},
{"id": "access", "title": "Account Access", "description": "Login and permissions"}
]
},
{
"title": "Technical",
"rows": [
{"id": "api", "title": "API Issues", "description": "Integration and endpoint help"},
{"id": "webhooks", "title": "Webhooks", "description": "Delivery and configuration"}
]
}
]
}
}
}
}
```
### Location Request
```json
{
"from": "+15551234567",
"to": "+15557654321",
"whatsapp_message": {
"type": "interactive",
"interactive": {
"type": "location_request_message",
"body": {"text": "Share your location so we can find the nearest store."},
"action": {"name": "send_location"}
}
}
}
```
---
## Reactions
React to a received message with an emoji.
```json
{
"from": "+15551234567",
"to": "+15557654321",
"whatsapp_message": {
"type": "reaction",
"reaction": {
"message_id": "wamid.ABGGFlA5FpafAgo6tHcNmNjXhvRm",
"emoji": "👍"
}
}
}
```
---
## Reply Context
Reply to a specific message by including `context.message_id`:
```json
{
"from": "+15551234567",
"to": "+15557654321",
"whatsapp_message": {
"type": "text",
"context": {
"message_id": "wamid.ABGGFlA5FpafAgo6tHcNmNjXhvRm"
},
"text": {
"body": "Thanks for your order! It will ship tomorrow."
}
}
}
```
---
## Callback Tracking
Use `biz_opaque_callback_data` to attach tracking data that will be returned in delivery webhooks:
```json
{
"from": "+15551234567",
"to": "+15557654321",
"whatsapp_message": {
"type": "text",
"biz_opaque_callback_data": "order_12345_confirmation",
"text": {
"body": "Your order has been confirmed."
}
}
}
```
---
## API Response
All message types return the same response structure:
```json
{
"data": {
"record_type": "message",
"direction": "outbound",
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"type": "WHATSAPP",
"from": {"phone_number": "+15551234567"},
"to": [{"phone_number": "+15557654321", "status": "queued"}],
"webhook_url": "https://example.com/webhooks"
}
}
```
---
## Validation Rules
| Constraint | Limit |
|-----------|-------|
| Text body | 1–4096 bytes |
| Media caption | Max 1024 bytes |
| Header text | Max 1024 bytes |
| Contacts per message | 1–257 |
| Location latitude | -90 to 90 (string) |
| Location longitude | -180 to 180 (string) |
| Media per message | Exactly 1 |
| Media source | Exactly one of `link` or `id` |
---
## Error Handling
Common WhatsApp errors return error code `40008`. This is a catch-all code covering template issues (pending, rejected, paused, disabled) and delivery failures. For general API errors, see the [Error Codes Reference](/docs/development/api-fundamentals/api-errors).
Template, text, media, and interactive messages all use the same endpoint. The `type` field inside `whatsapp_message` determines which content object is required.
---
## Next Steps
Send your first WhatsApp message end-to-end
Set up your WhatsApp Business Account and verify your number
Handle inbound messages and delivery status callbacks
---
### Manage Templates
> Source: https://developers.telnyx.com/docs/messaging/whatsapp/manage-templates.md
# Manage WhatsApp Message Templates
WhatsApp requires pre-approved message templates for business-initiated conversations. Use the Telnyx Management API to create, review, and manage templates programmatically.
For template best practices and approval tips, see the [Approval Tips](/docs/messaging/whatsapp/manage-templates#approval-tips) guide.
## Template Lifecycle
```mermaid
graph LR
A[Create] --> B[PENDING]
B --> C[APPROVED]
B --> D[REJECTED]
C --> E[PAUSED]
E --> C
C --> F[DISABLED]
```
Templates must be approved by Meta before they can be used. Review typically takes 24-48 hours.
## List Templates
Retrieve all templates for your WhatsApp Business Account.
```bash cURL
curl -X GET "https://api.telnyx.com/v2/whatsapp/message_templates" \
-H "Authorization: Bearer YOUR_API_KEY"
```
```python Python
from telnyx import Telnyx
client = Telnyx(api_key="YOUR_API_KEY")
templates = client.whatsapp.templates.list()
for template in templates.data:
print(f"{template.name} ({template.category}) - {template.status}")
```
```javascript Node.js
import Telnyx from 'telnyx';
const client = new Telnyx({apiKey: 'YOUR_API_KEY'});
const { data } = await client.whatsapp.templates.list();
data.forEach(t => console.log(`${t.name} (${t.category}) - ${t.status}`));
```
### Filter by Status
```bash
# List only approved templates
curl -X GET "https://api.telnyx.com/v2/whatsapp/message_templates?filter[status]=APPROVED" \
-H "Authorization: Bearer YOUR_API_KEY"
# Search by name
curl -X GET "https://api.telnyx.com/v2/whatsapp/message_templates?filter[search]=welcome" \
-H "Authorization: Bearer YOUR_API_KEY"
```
### Response
```json
{
"data": [
{
"id": "019cd44b-3a1c-781b-956e-bd33e9fd2ac6",
"record_type": "whatsapp_message_template",
"name": "welcome_message",
"category": "MARKETING",
"language": "en_US",
"status": "APPROVED",
"components": [
{
"type": "BODY",
"text": "Hello {{1}}! Welcome to our WhatsApp updates.",
"example": {
"body_text": [["John"]]
}
}
],
"quality_rating": "HIGH",
"created_at": "2026-03-15T12:00:00.000Z",
"updated_at": "2026-03-15T14:30:00.000Z"
}
],
"meta": {
"page_number": 1,
"page_size": 20,
"total_pages": 1,
"total_results": 1
}
}
```
## Create a Template
Submit a new template for Meta review.
Set a display name for the phone number before submitting templates. Templates submitted from numbers without an approved display name are rejected by Meta.
Always include sample values in the `example` field when your template contains parameters (`\{\{1\}\}`, `\{\{2\}\}`). Templates without examples are typically rejected.
### Authentication Template
Authentication templates include an OTP code with a copy-code button.
```bash cURL
curl -X POST "https://api.telnyx.com/v2/whatsapp/message_templates" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "login_verification",
"category": "AUTHENTICATION",
"language": "en_US",
"components": [
{
"type": "BODY",
"text": "Your verification code is {{1}}. Do not share this code.",
"example": {
"body_text": [["123456"]]
}
},
{
"type": "BUTTONS",
"buttons": [
{
"type": "OTP",
"otp_type": "COPY_CODE",
"text": "Copy Code"
}
]
}
]
}'
```
```python Python
from telnyx import Telnyx
client = Telnyx(api_key="YOUR_API_KEY")
template = client.whatsapp.templates.create(
name="login_verification",
category="AUTHENTICATION",
language="en_US",
waba_id="YOUR_WABA_ID",
components=[
{
"type": "BODY",
"text": "Your verification code is {{1}}. Do not share this code.",
"example": {"body_text": [["123456"]]}
},
{
"type": "BUTTONS",
"buttons": [{"type": "OTP", "otp_type": "COPY_CODE", "text": "Copy Code"}]
}
]
)
print(f"Template ID: {template.id}, Status: {template.status}")
```
```javascript Node.js
import Telnyx from 'telnyx';
const client = new Telnyx({apiKey: 'YOUR_API_KEY'});
const template = await client.whatsapp.templates.create({
name: 'login_verification',
category: 'AUTHENTICATION',
language: 'en_US',
waba_id: 'YOUR_WABA_ID',
components: [
{
type: 'BODY',
text: 'Your verification code is {{1}}. Do not share this code.',
example: { body_text: [['123456']] }
},
{
type: 'BUTTONS',
buttons: [{ type: 'OTP', otp_type: 'COPY_CODE', text: 'Copy Code' }]
}
]
});
console.log(`Template ID: ${template.data.id}`);
```
### Marketing Template
Marketing templates support rich media headers, body text with parameters, and call-to-action buttons.
```bash
curl -X POST "https://api.telnyx.com/v2/whatsapp/message_templates" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "spring_promotion",
"category": "MARKETING",
"language": "en_US",
"components": [
{
"type": "HEADER",
"format": "TEXT",
"text": "Spring Sale!"
},
{
"type": "BODY",
"text": "Hi {{1}}, enjoy {{2}}% off your next order with code {{3}}. Offer ends soon!",
"example": {
"body_text": [["Sarah", "25", "SPRING25"]]
}
},
{
"type": "FOOTER",
"text": "Reply STOP to opt out"
},
{
"type": "BUTTONS",
"buttons": [
{
"type": "URL",
"text": "Shop Now",
"url": "https://example.com/shop?promo={{1}}",
"example": ["SPRING25"]
}
]
}
]
}'
```
### Utility Template
Utility templates are for transactional updates like order confirmations, shipping notifications, and account alerts.
```bash
curl -X POST "https://api.telnyx.com/v2/whatsapp/message_templates" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "order_shipped",
"category": "UTILITY",
"language": "en_US",
"components": [
{
"type": "BODY",
"text": "Your order {{1}} has shipped! Expected delivery: {{2}}. Track your package here.",
"example": {
"body_text": [["ORD-12345", "March 20, 2026"]]
}
}
]
}'
```
## Get a Template
Retrieve details of a specific template by ID.
```bash
curl -X GET "https://api.telnyx.com/v2/whatsapp/message_templates/{template_id}" \
-H "Authorization: Bearer YOUR_API_KEY"
```
## Update a Template
Edit a template's content. Only templates in `APPROVED` or `REJECTED` status can be updated. Updated templates are re-submitted for Meta review.
Editing an approved template resets its status to `PENDING` while Meta reviews the changes. Your template will be temporarily unavailable for sending.
```bash
curl -X PATCH "https://api.telnyx.com/v2/whatsapp/message_templates/{template_id}" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"components": [
{
"type": "BODY",
"text": "Your order {{1}} has shipped! Estimated arrival: {{2}}.",
"example": {
"body_text": [["ORD-12345", "March 22, 2026"]]
}
}
]
}'
```
Edit and resubmit rejected templates rather than creating new ones. Meta enforces a 30-day restriction on reusing template names.
## Delete a Template
Remove a template permanently. This action cannot be undone.
```bash
curl -X DELETE "https://api.telnyx.com/v2/whatsapp/message_templates/{template_id}" \
-H "Authorization: Bearer YOUR_API_KEY"
```
## Template Categories
| Category | Use Case | Requires Opt-in | Pricing Tier |
|----------|----------|-----------------|-------------|
| **AUTHENTICATION** | OTP codes, login verification | No | Lowest |
| **UTILITY** | Order updates, shipping, account alerts | Yes | Medium |
| **MARKETING** | Promotions, newsletters, product launches | Yes | Highest |
Choose the most specific category. Meta may reclassify templates that don't match their declared category, which can affect pricing and delivery.
### Authentication Rules
- Must contain a one-time code or password
- Must include a copy-code or one-tap button
- Cannot include URLs or media (except the OTP button)
- Limited to one code parameter
### Naming Rules
- Lowercase letters, numbers, and underscores only
- Maximum 512 characters
- Must be unique within your WABA for each language
- Avoid words like `test`, `sample`, `demo` — Meta flags these for extra review
### Approval Tips
- **Always include sample values** — Templates with parameters but no `example` field are almost always rejected
- **Set a display name first** — Templates submitted from numbers without an approved display name get rejected
- **Complete your business profile** — Add website, description, and category before submitting. Incomplete profiles increase rejection rates
- **Edit rejected templates, don't recreate** — Meta enforces a 30-day restriction on reusing template names
- **Match category to content** — Meta may reclassify miscategorized templates, affecting pricing and delivery
For detailed best practices and troubleshooting, see our [WhatsApp Message Templates Guide](https://support.telnyx.com/en/articles/13986483) on the support center.
## Multi-Language Templates
Create the same template in multiple languages. Each language variant is reviewed independently.
```bash
# English version
curl -X POST "https://api.telnyx.com/v2/whatsapp/message_templates" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "order_confirmation",
"category": "UTILITY",
"language": "en_US",
"components": [
{
"type": "BODY",
"text": "Order {{1}} confirmed. Delivery by {{2}}.",
"example": {"body_text": [["ORD-789", "March 20"]]}
}
]
}'
# Spanish version
curl -X POST "https://api.telnyx.com/v2/whatsapp/message_templates" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "order_confirmation",
"category": "UTILITY",
"language": "es",
"components": [
{
"type": "BODY",
"text": "Pedido {{1}} confirmado. Entrega estimada: {{2}}.",
"example": {"body_text": [["ORD-789", "20 de marzo"]]}
}
]
}'
```
## Error Handling
| Error Code | Description | Resolution |
|-----------|-------------|------------|
| `40008` | Template operation failed (catch-all) | Check template status and Meta error details |
| `10004` | Missing required parameter | Ensure all required fields are included |
| `10032` | Invalid enumerated value | Check category and language codes |
Common issues:
- **Rejected templates**: Review [Template Best Practices](/docs/messaging/whatsapp/message-templates) for approval tips
- **Duplicate name**: Template names must be unique per language within a WABA
- **Invalid parameters**: Ensure `example` values match parameter count in template body
## Next Steps
- [Send Messages](/docs/messaging/whatsapp/send-messages) — Use approved templates to send messages
- [Approval Tips](/docs/messaging/whatsapp/manage-templates#approval-tips) — Tips for getting templates approved
- [Quickstart](/docs/messaging/whatsapp/quickstart) — End-to-end setup guide
---
## Calling
### Business Calling
> Source: https://developers.telnyx.com/docs/messaging/whatsapp/business-calling.md
WhatsApp Business Calling lets you receive and place voice calls over WhatsApp using your existing Telnyx phone numbers. Calls route through your configured Voice API, SIP, or TeXML connection — the same infrastructure you already use for programmable voice.
With over 2 billion WhatsApp users worldwide, business calling gives your customers a familiar way to reach you by voice without leaving the app.
## How it works
- **Inbound calls** — When a WhatsApp user calls your business number, the call routes through your existing voice connection (Voice API, SIP, TeXML, or AI agent).
- **Outbound calls** — Place calls to WhatsApp users using a SIP URI with the format `@whatsapp-.sip.telnyx.com`.
- **On-net routing** — All WhatsApp voice calls route through Meta's network. These are not PSTN calls.
- **Concurrent call limit** — Meta allows a maximum of 1,000 concurrent calls per business number.
Outbound WhatsApp calling is not available for numbers in the United States, Canada, Egypt, Vietnam, and Nigeria. This is a Meta platform restriction.
## Prerequisites
Before enabling WhatsApp calling, you need:
- A **Telnyx account** with an [API key](https://portal.telnyx.com).
- A **WhatsApp Business Account** connected via [Embedded Signup](/docs/messaging/whatsapp/embedded-signup).
- A **verified phone number** added to your WABA.
- A **voice connection** (Voice API, SIP, or TeXML) configured in the [Telnyx Portal](https://portal.telnyx.com).
- A **WABA daily messaging limit** of at least **2,000 unique recipients** — Meta requires this minimum before calling APIs can be enabled.
### Connect your WhatsApp Business Account
In the Telnyx Portal, navigate to **Messaging Suite → WhatsApp Messaging** to start the Embedded Signup flow. The page walks you through connecting your WhatsApp Business Account to Telnyx.
Click **Connect WhatsApp Business** to sign in with your Facebook account and authorize Telnyx to manage your WhatsApp Business Account.
## Enable WhatsApp calling
Verify whether calling is already enabled on your WhatsApp phone number.
```
GET https://api.telnyx.com/v2/whatsapp/phone_numbers/{phone_number}/calling_settings
```
```bash cURL
curl -X GET "https://api.telnyx.com/v2/whatsapp/phone_numbers/+15551234567/calling_settings" \
-H "Authorization: Bearer YOUR_API_KEY"
```
```python Python
from telnyx import Telnyx
client = Telnyx(api_key="YOUR_API_KEY")
calling_setting = client.whatsapp.phone_numbers.calling_settings.retrieve(
"+15551234567",
)
print(calling_setting.data)
```
```javascript Node.js
import Telnyx from 'telnyx';
const client = new Telnyx({ apiKey: 'YOUR_API_KEY' });
const callingSetting = await client.whatsapp.phoneNumbers.callingSettings.retrieve('+15551234567');
console.log(callingSetting.data);
```
```go Go
package main
import (
"context"
"fmt"
"github.com/team-telnyx/telnyx-go"
"github.com/team-telnyx/telnyx-go/option"
)
func main() {
client := telnyx.NewClient(
option.WithAPIKey("My API Key"),
)
callingSetting, err := client.Whatsapp.PhoneNumbers.CallingSettings.Get(context.TODO(), "+15551234567")
if err != nil {
panic(err.Error())
}
fmt.Printf("%+v\n", callingSetting.Data)
}
```
```java Java
package com.telnyx.sdk.example;
import com.telnyx.sdk.client.TelnyxClient;
import com.telnyx.sdk.client.okhttp.TelnyxOkHttpClient;
import com.telnyx.sdk.models.whatsapp.phonenumbers.callingsettings.CallingSettingRetrieveParams;
import com.telnyx.sdk.models.whatsapp.phonenumbers.callingsettings.CallingSettingRetrieveResponse;
public final class Main {
private Main() {}
public static void main(String[] args) {
TelnyxClient client = TelnyxOkHttpClient.fromEnv();
CallingSettingRetrieveParams params = CallingSettingRetrieveParams.builder()
.phoneNumber("+15551234567")
.build();
CallingSettingRetrieveResponse callingSetting = client.whatsapp().phoneNumbers().callingSettings().retrieve(params);
}
}
```
```ruby Ruby
require "telnyx"
telnyx = Telnyx::Client.new(api_key: "My API Key")
calling_setting = telnyx.whatsapp.phone_numbers.calling_settings.retrieve("+15551234567")
puts(calling_setting)
```
The response includes an `enabled` field — `false` means calling is not yet active.
```json
{
"data": {
"record_type": "whatsapp_calling_settings",
"phone_number": "+15551234567",
"enabled": false,
"updated_at": "2026-04-28T12:00:00Z"
}
}
```
Enable WhatsApp calling by setting `enabled` to `true`.
```
PATCH https://api.telnyx.com/v2/whatsapp/phone_numbers/{phone_number}/calling_settings
```
```bash cURL
curl -X PATCH "https://api.telnyx.com/v2/whatsapp/phone_numbers/+15551234567/calling_settings" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "enabled": true }'
```
```python Python
from telnyx import Telnyx
client = Telnyx(api_key="YOUR_API_KEY")
calling_setting = client.whatsapp.phone_numbers.calling_settings.update(
phone_number="+15551234567",
enabled=True,
)
print(calling_setting.data)
```
```javascript Node.js
import Telnyx from 'telnyx';
const client = new Telnyx({ apiKey: 'YOUR_API_KEY' });
const callingSetting = await client.whatsapp.phoneNumbers.callingSettings.update('+15551234567', {
enabled: true,
});
console.log(callingSetting.data);
```
```go Go
package main
import (
"context"
"fmt"
"github.com/team-telnyx/telnyx-go"
"github.com/team-telnyx/telnyx-go/option"
)
func main() {
client := telnyx.NewClient(
option.WithAPIKey("My API Key"),
)
callingSetting, err := client.Whatsapp.PhoneNumbers.CallingSettings.Update(
context.TODO(),
"+15551234567",
telnyx.WhatsappPhoneNumberCallingSettingUpdateParams{
Enabled: true,
},
)
if err != nil {
panic(err.Error())
}
fmt.Printf("%+v\n", callingSetting.Data)
}
```
```java Java
package com.telnyx.sdk.example;
import com.telnyx.sdk.client.TelnyxClient;
import com.telnyx.sdk.client.okhttp.TelnyxOkHttpClient;
import com.telnyx.sdk.models.whatsapp.phonenumbers.callingsettings.CallingSettingUpdateParams;
import com.telnyx.sdk.models.whatsapp.phonenumbers.callingsettings.CallingSettingUpdateResponse;
public final class Main {
private Main() {}
public static void main(String[] args) {
TelnyxClient client = TelnyxOkHttpClient.fromEnv();
CallingSettingUpdateParams params = CallingSettingUpdateParams.builder()
.phoneNumber("+15551234567")
.enabled(true)
.build();
CallingSettingUpdateResponse callingSetting = client.whatsapp().phoneNumbers().callingSettings().update(params);
}
}
```
```ruby Ruby
require "telnyx"
telnyx = Telnyx::Client.new(api_key: "My API Key")
calling_setting = telnyx.whatsapp.phone_numbers.calling_settings.update("+15551234567", enabled: true)
puts(calling_setting)
```
Inbound WhatsApp calls route through your voice connection. If you haven't set one up yet, configure one of the following:
- [Voice API](/docs/voice/programmable-voice) — Handle calls programmatically with webhooks.
- [SIP Trunking](/docs/sip-trunking) — Route calls to your SIP infrastructure.
- [TeXML](/docs/voice/texml) — Control calls with XML-based instructions.
## Make outbound calls
The WhatsApp user must grant calling permission before you can place an outbound call to them. Permission can be obtained in three ways:
- **Permission request message** — Send a calling permission request via WhatsApp message (rate-limited to 1 request per 24 hours and 2 requests per 7 days per user).
- **Callback permission** — The user calls your business first, which grants temporary permission for 7 days. This requires "Allow Callbacks" to be enabled in Meta Business Suite.
- **User grants via profile** — The user enables calling from your WhatsApp Business Profile settings, granting permanent permission.
Temporary permission (from callback or accepted request) lasts 7 days. Permission granted via profile settings is permanent until the user revokes it. After 2 consecutive unanswered outbound calls, WhatsApp sends the user a nudge notification. After 4 consecutive unanswered calls, permission is automatically revoked.
To place an outbound WhatsApp call, use the SIP URI format:
```
@whatsapp-.sip.telnyx.com
```
For example, to call `+442071234567` from your Telnyx number `+15551234567`:
```
+442071234567@whatsapp-15551234567.sip.telnyx.com
```
```bash cURL
curl -X POST https://api.telnyx.com/v2/calls \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"connection_id": "YOUR_CONNECTION_ID",
"to": "sip:+442071234567@whatsapp-15551234567.sip.telnyx.com",
"from": "+15551234567"
}'
```
Outbound calling is restricted for numbers in the US, Canada, Egypt, Vietnam, and Nigeria. Attempts from these countries return an error.
## Disable calling
To turn off WhatsApp calling, set `enabled` to `false`:
```bash
curl -X PATCH "https://api.telnyx.com/v2/whatsapp/phone_numbers/+15551234567/calling_settings" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "enabled": false }'
```
## Troubleshooting
Verify that your phone number has an active voice connection configured. Inbound WhatsApp calls route through the same connection used for regular voice calls. Check your connection settings in the [Telnyx Portal](https://portal.telnyx.com).
Outbound WhatsApp calling is not available for numbers registered in the US, Canada, Egypt, Vietnam, or Nigeria. This is a Meta platform restriction and cannot be overridden.
Ensure the phone number is verified and actively registered with your WhatsApp Business Account. Numbers that have not completed Meta's verification process cannot enable calling.
WhatsApp calls route through Meta's network, not the PSTN. Call quality depends on the end user's internet connection. This is consistent with standard WhatsApp voice call behavior.
Your WhatsApp Business Account must have a daily messaging limit of at least 2,000 unique recipients before Meta allows calling APIs to be enabled. Increase your messaging volume and quality rating to raise your limit.
Verify that the phone number is associated with the voice connection you are using in the API call. Also check the SIP URI format — the Telnyx number in the host portion must not include the leading `+` (e.g., `whatsapp-15551234567.sip.telnyx.com`, not `whatsapp-+15551234567.sip.telnyx.com`).
After 2 consecutive unanswered outbound calls, WhatsApp sends the user a nudge notification asking if they want to continue receiving calls. After 4 consecutive unanswered calls, calling permission is automatically revoked and you will need to obtain permission again.
## Next steps
Send text, media, and template messages over WhatsApp.
Connect your WhatsApp Business Account to Telnyx.
Build voice applications with the Telnyx Voice API.
---
## API Reference (WhatsApp)
### Whatsapp Business Accounts
- [List Whatsapp Business Accounts](https://developers.telnyx.com/api-reference/whatsapp-business-accounts/list-whatsapp-business-accounts.md): Retrieve a list of the WhatsApp Business Accounts (WABAs) connected to your Telnyx account.
- [Delete a Whatsapp Business Account](https://developers.telnyx.com/api-reference/whatsapp-business-accounts/delete-a-whatsapp-business-account.md): Delete a WhatsApp Business Account connection from your Telnyx account.
- [Get a single Whatsapp Business Account](https://developers.telnyx.com/api-reference/whatsapp-business-accounts/get-a-single-whatsapp-business-account.md): Retrieve the details of a specific WhatsApp Business Account.
- [List phone numbers for a WABA](https://developers.telnyx.com/api-reference/whatsapp-business-accounts/list-phone-numbers-for-a-waba.md): List the phone numbers associated with a WhatsApp Business Account.
- [Get WABA settings](https://developers.telnyx.com/api-reference/whatsapp-business-accounts/get-waba-settings.md): Retrieve the settings of a WhatsApp Business Account.
- [Update WABA settings](https://developers.telnyx.com/api-reference/whatsapp-business-accounts/update-waba-settings.md): Update the settings of a WhatsApp Business Account.
### Whatsapp Phone Numbers
- [Initialize Whatsapp phone number verification](https://developers.telnyx.com/api-reference/whatsapp-phone-numbers/initialize-whatsapp-phone-number-verification.md): Start the verification process to register a phone number with a WhatsApp Business Account.
- [List Whatsapp phone numbers](https://developers.telnyx.com/api-reference/whatsapp-phone-numbers/list-whatsapp-phone-numbers.md): Retrieve a list of the phone numbers registered for WhatsApp on your account.
- [Delete a Whatsapp phone number](https://developers.telnyx.com/api-reference/whatsapp-phone-numbers/delete-a-whatsapp-phone-number.md): Delete a phone number's WhatsApp registration from your account.
- [Get calling settings for a phone number](https://developers.telnyx.com/api-reference/whatsapp-phone-numbers/get-calling-settings-for-a-phone-number.md): Retrieve the WhatsApp calling settings for a phone number.
- [Enable or disable Whatsapp calling for a phone number](https://developers.telnyx.com/api-reference/whatsapp-phone-numbers/enable-or-disable-whatsapp-calling-for-a-phone-number.md): Enable or disable WhatsApp calling for a phone number and manage its calling configuration.
- [Get phone number business profile](https://developers.telnyx.com/api-reference/whatsapp-phone-numbers/get-phone-number-business-profile.md): Retrieve the WhatsApp business profile associated with a phone number.
- [Update phone number business profile](https://developers.telnyx.com/api-reference/whatsapp-phone-numbers/update-phone-number-business-profile.md): Update the WhatsApp business profile associated with a phone number.
- [Delete Whatsapp profile photo](https://developers.telnyx.com/api-reference/whatsapp-phone-numbers/delete-whatsapp-profile-photo.md): Delete the profile photo of a WhatsApp phone number.
- [Get Whatsapp profile photo](https://developers.telnyx.com/api-reference/whatsapp-phone-numbers/get-whatsapp-profile-photo.md): Retrieve the profile photo of a WhatsApp phone number.
- [Upload Whatsapp profile photo](https://developers.telnyx.com/api-reference/whatsapp-phone-numbers/upload-whatsapp-profile-photo.md): Upload a new profile photo for a WhatsApp phone number.
- [Resend verification code](https://developers.telnyx.com/api-reference/whatsapp-phone-numbers/resend-verification-code.md): Resend the verification code for a phone number that is being registered with WhatsApp.
- [Submit verification code for a phone number](https://developers.telnyx.com/api-reference/whatsapp-phone-numbers/submit-verification-code-for-a-phone-number.md): Submit the verification code to complete WhatsApp registration of a phone number.
- [Get conversation window status for a phone number](https://developers.telnyx.com/api-reference/whatsapp-phone-numbers/get-conversation-window-status-for-a-phone-number.md): Returns whether the 24-hour conversation window is currently open for a given source/destination pair. If window_active is false, only template messages may be…
- [Get phone number conversational components](https://developers.telnyx.com/api-reference/whatsapp-phone-numbers/get-phone-number-conversational-components.md): Retrieve the conversational components configuration for a WhatsApp phone number.
- [Update phone number conversational components](https://developers.telnyx.com/api-reference/whatsapp-phone-numbers/update-phone-number-conversational-components.md): Update the conversational components configuration, such as welcome messages and commands, for a WhatsApp phone number.
### Whatsapp Message Templates
- [List Whatsapp message templates](https://developers.telnyx.com/api-reference/whatsapp-message-templates/list-whatsapp-message-templates.md): Retrieve the WhatsApp message templates for your WhatsApp Business Accounts.
- [Create a Whatsapp message template](https://developers.telnyx.com/api-reference/whatsapp-message-templates/create-a-whatsapp-message-template.md): Create a new WhatsApp message template. Templates must be approved by WhatsApp before they can be used in messages.
- [Delete a Whatsapp message template](https://developers.telnyx.com/api-reference/whatsapp-message-templates/delete-a-whatsapp-message-template.md): Delete a WhatsApp message template.
- [Get a Whatsapp message template by ID](https://developers.telnyx.com/api-reference/whatsapp-message-templates/get-a-whatsapp-message-template-by-id.md): Retrieve a specific WhatsApp message template by its ID.
- [Update a Whatsapp message template](https://developers.telnyx.com/api-reference/whatsapp-message-templates/update-a-whatsapp-message-template.md): Update an existing WhatsApp message template.