Build on top of
Wa-Wexa.
Connect your website, CRM, or internal tools to the WhatsApp customer engagement platform your team already uses.
Authenticate with your API key.
Wa-Wexa provides a secure application API for workspace data, messaging, automations, flows, and webhooks. Official Meta WhatsApp Business services power message delivery behind the scenes.
Generate a key under Settings → API Keys, store it only on your application server, and send it in the Authorization: Bearer wawexa_live_...header. Each key is limited to its selected permissions.
Workspace data, contacts, conversations, automations, and flows.
Official WhatsApp text, template, media, and flow sends.
Requests and responses use JSON over HTTPS.
Send a WhatsApp message.
Send text, media, location, contact, or interactive messages through an existing conversation, or start a template conversation with an E.164 phone number.
/api/whatsapp/sendSends a message through the workspace WhatsApp number and records it in the conversation. Use phone for a first approved-template send.
fetch('/api/whatsapp/send', {
method: 'POST',
headers: {
'Authorization': 'Bearer wawexa_live_your_api_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
conversation_id: 'conversation-uuid',
message_type: 'text',
content_text: 'Hello from Wa-Wexa'
})
})Start with a phone number
For a first business-initiated message, send an E.164 phone instead of conversation_id. Wa-Wexa finds or creates the contact and its open conversation in the API key's workspace before sending the approved template. The optional name is used only when a new contact is created.
fetch('/api/whatsapp/send', {
method: 'POST',
headers: {
'Authorization': 'Bearer wawexa_live_your_api_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
phone: '+919876XXXX',
name: 'Aarav Sharma',
message_type: 'template',
template_name: 'welcome_message',
template_params: ['Aarav', 'Wa-Wexa']
})
})Get the conversation_id from the response
You do not create this UUID yourself. The conversation-uuid text in examples is only a placeholder. When the phone-first template request succeeds, the response contains the workspace-scoped conversation_id. Save that returned value for later messages to the same conversation.
const response = await fetch('/api/whatsapp/send', {
method: 'POST',
headers: {
'Authorization': 'Bearer wawexa_live_your_api_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
phone: '+919876XXXX',
name: 'Raki',
message_type: 'template',
template_name: 'welcome_message',
template_params: ['Aarav']
})
});
if (!response.ok) {
throw new Error(await response.text());
}
const result = await response.json();
const conversationId = result.conversation_id;
console.log('Save this ID for later messages:', conversationId);Send the next message to the same number
For a text reply, pass the saved conversation_id. For another approved template, you can pass that ID too, or send the same phone again; Wa-Wexa will find the existing contact and conversation in the same workspace. Phone-only sends are for templates, not free-form text. Replace conversation-uuid below with the actual ID from the first successful response.
{
"conversation_id": "conversation-uuid",
"message_type": "text",
"content_text": "Hello again"
}await fetch('https://wawexa.com/api/whatsapp/send', {
method: 'POST',
headers: {
'Authorization': 'Bearer wawexa_live_your_api_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
conversation_id: conversationId,
message_type: 'text',
content_text: 'Hello again'
})
})/api/whatsapp/conversationsAPI-key or session-authenticated shortcut that finds or creates a contact and conversation, then sends an approved template.
Required fields
conversation_id— existing conversation UUID, orphone— E.164 recipient numbermessage_type—text,image,video,audio,document,location, orcontactcontent_text— required for text messages
Response
{
"success": true,
"conversation_id": "conversation-uuid",
"contact_id": "contact-uuid",
"message_id": "message-uuid",
"whatsapp_message_id": "wamid..."
}conversation_id for replies and non-template messages in an existing thread. Use phone only with message_type: 'template'to start a conversation. Do not send both fields; all contact and conversation lookups remain scoped to the API key's workspace.What each ID means
conversation_idis Wa-Wexa's UUID for the customer thread; use it as the recipient context for later sends. message_id identifies the saved message row in Wa-Wexa. whatsapp_message_idis Meta's wamid for that individual WhatsApp message and is useful for matching delivery-status callbacks. Do not use either message ID as a conversation_id. For template sends, use the approved template_name; the template UUID is for template management.
Send conversation_id with template_name and the ordered template_params values.
fetch('/api/whatsapp/send', {
method: 'POST',
headers: {
'Authorization': 'Bearer wawexa_live_your_api_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
conversation_id: 'conversation-uuid',
message_type: 'template',
template_name: 'welcome_message',
template_params: ['Aarav']
})
})Send an E.164 phone with message_type: 'template'. Wa-Wexa finds or creates the contact and conversation.
fetch('/api/whatsapp/send', {
method: 'POST',
headers: {
'Authorization': 'Bearer wawexa_live_your_api_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
phone: '+919876XXXX',
name: 'Aarav Sharma',
message_type: 'template',
template_name: 'welcome_message',
template_params: ['Aarav', 'Wa-Wexa']
})
}) POST /api/whatsapp/templates/submit with { template_id }. For sending, use the approved template's template_name; do not replace it with the template UUID.// app/api/wawexa/request/route.ts
export async function POST(request: Request) {
const response = await fetch('https://wawexa.com/api/whatsapp/send', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.WAWEXA_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(await request.json()),
});
return Response.json(await response.json(), { status: response.status });
}Manage Marketing, Utility, and Authentication templates.
Create templates locally, submit them to Meta for review, synchronize approval status, and send approved templates using scoped API keys.
Use templates:read to list templates, templates:write to create, submit, or synchronize them, and messages:send to send an approved template.
/api/whatsapp/templatesLists Marketing, Utility, and Authentication templates. Optional query filters: category and status.
/api/whatsapp/templatesCreates a local Marketing, Utility, or Authentication template in Draft status.
/api/whatsapp/templates/submitSubmits a local template to Meta for review. Body: { template_id }.
/api/whatsapp/templates/syncSynchronizes templates and approval statuses from Meta into Wa-Wexa.
/api/whatsapp/sendSends an approved template with ordered values for {{1}}, {{2}}, and later placeholders. For phone-first sends, repeat the Idempotency-Key header after a timeout to receive the original result without sending twice.
Create a Utility template
const response = await fetch('/api/whatsapp/templates', {
method: 'POST',
headers: {
'Authorization': 'Bearer wawexa_live_your_api_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'order_update',
category: 'Utility',
language: 'en_US',
body_text: 'Order {{1}} will arrive on {{2}}.',
variable_samples: ['ORD-1001', '25 Sep 2026']
})
})
const { template, next_step } = await response.json(){{1}}, and send actual order, delivery, appointment, invoice, or account values later in template_params.Create an Authentication template
const response = await fetch('/api/whatsapp/templates', {
method: 'POST',
headers: {
'Authorization': 'Bearer wawexa_live_your_api_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'login_code',
category: 'Authentication',
language: 'en_US',
body_text: 'Your verification code is {{1}}.',
authentication: {
buttonType: 'copy_code',
addSecurityRecommendation: true,
codeExpirationMinutes: 10,
copyCodeText: 'Copy Code'
}
})
})
const { template } = await response.json()Authentication templates must contain exactly one {{1}} verification-code variable. Set buttonType to copy_code, one_tap, or none. One-tap also requires packageName and signatureHash.
Submit and synchronize
await fetch('/api/whatsapp/templates/submit', {
method: 'POST',
headers: {
'Authorization': 'Bearer wawexa_live_your_api_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({ template_id: 'template-uuid' })
})Submission returns Meta's template ID and review status. Call POST /api/whatsapp/templates/sync later to refresh Pending, Approved, or Rejected status.
Send an approved Utility template
fetch('/api/whatsapp/send', {
method: 'POST',
headers: {
'Authorization': 'Bearer wawexa_live_your_api_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
conversation_id: 'conversation-uuid',
message_type: 'template',
template_name: 'welcome_message',
template_params: ['Aarav', 'Wa-Wexa']
})
})Send an approved Authentication code
fetch('/api/whatsapp/send', {
method: 'POST',
headers: {
'Authorization': 'Bearer wawexa_live_your_api_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
conversation_id: 'conversation-uuid',
message_type: 'template',
template_name: 'login_code',
template_params: ['482913']
})
})Send a template from your framework
// app/api/wawexa/send/route.ts
export async function POST(request: Request) {
const { template_name, template_params = [] } = await request.json();
const response = await fetch(
'https://wawexa.com/api/whatsapp/send',
{
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.WAWEXA_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
phone: '+919876XXXX',
message_type: 'template',
template_name,
template_params,
}),
},
);
return Response.json(await response.json(), { status: response.status });
}template_paramscontains only the values for the approved template's body variables. Forlogin_code, [482913] replaces{{1}}. The recipient phone number is supplied in phonefor a first send, or is already stored on the conversation's contact when usingconversation_id.template_params replaces {{1}}, the second replaces {{2}}, and so on. The WhatsApp access token remains encrypted in the workspace configuration.// app/api/wawexa/request/route.ts
export async function POST(request: Request) {
const response = await fetch('https://wawexa.com/api/whatsapp/send', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.WAWEXA_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(await request.json()),
});
return Response.json(await response.json(), { status: response.status });
}Track delivery and read events.
Meta posts delivery lifecycle events to the webhook. Wa-Wexa mirrors them onto message and broadcast-recipient records.
/api/whatsapp/webhookReceives signed Meta status events such as sent, delivered, read, and failed.
Meta sends status events to the configured webhook. Your application reads the resulting status from Wa-Wexa records; there is no customer-facing Create, Update, or Delete request for a delivery event.
For application data, read the messages.status or broadcast_recipients.status fields through the authenticated Wa-Wexa API.
Keep your audience in sync.
Contacts are managed in your Wa-Wexa workspace. Use the authenticated Wa-Wexa API so workspace permissions remain in control of every read and write.
/api/contactsList contacts available to the authenticated workspace.
/api/contactsCreate a contact with a phone number and optional profile fields.
/api/contacts/:idUpdate a contact profile.
/api/contacts/:idDelete a contact permitted by workspace policy.
const response = await fetch('/api/contacts', {
headers: {
'Authorization': 'Bearer wawexa_live_your_api_key'
}
})
const { contacts } = await response.json()CRUD request examples
Choose a framework and operation. These examples use the Contacts API; the same authentication pattern applies to templates, automations, and flows.
// app/api/wawexa/contacts/route.ts
export async function POST(request: Request) {
const body = await request.json();
const response = await fetch('https://wawexa.com/api/contacts', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.WAWEXA_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
});
return Response.json(await response.json(), { status: response.status });
}process.env.WAWEXA_API_KEY.Trigger actions without extra glue.
Create and manage keyword, event, and time-based automation rules. Activation validates the trigger and step configuration.
/api/automationsList automations in the authenticated workspace.
/api/automationsCreate a draft or validated active automation.
/api/automations/:idFetch one automation and its step tree.
/api/automations/:idUpdate automation settings or steps.
/api/automations/:idDelete an automation.
fetch('/api/automations', {
method: 'POST',
headers: {
'Authorization': 'Bearer wawexa_live_your_api_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'New lead follow-up',
trigger_type: 'keyword',
trigger_config: { keyword: 'pricing' },
is_active: false,
steps: []
})
})// app/api/wawexa/request/route.ts
export async function POST(request: Request) {
const response = await fetch('https://wawexa.com/api/automations', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.WAWEXA_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(await request.json()),
});
return Response.json(await response.json(), { status: response.status });
}Trigger a personalized Utility automation
Create an automation with the External Eventtrigger and event name order.shipped. In its Send Template step, map {{1}} to {{vars.order_id}} and {{2}} to {{vars.delivery_date}}.
fetch('/api/automations/engine', {
method: 'POST',
headers: {
'Authorization': 'Bearer wawexa_live_your_api_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
event_name: 'order.shipped',
phone: '+919876XXXX',
contact_name: 'Aarav',
variables: {
order_id: 'ORD-8451',
delivery_date: '18 September 2026'
}
})
})Trigger an Authentication template
Create an External Event automation named auth.otp_requested, select the approved Authentication template, and map {{1}} to {{vars.otp_code}}. Generate, expire, and verify the OTP in your authentication server; Wa-Wexa handles delivery.
fetch('/api/automations/engine', {
method: 'POST',
headers: {
'Authorization': 'Bearer wawexa_live_your_api_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
event_name: 'auth.otp_requested',
phone: '+919876XXXX',
variables: {
otp_code: '482913'
}
})
})contact_id or an international phone. When phone is used, Wa-Wexa finds or creates the contact and conversation before running the automation.Build guided conversations.
Flows are structured conversation journeys with triggers and nodes. They can be created as drafts, updated, published, and deleted from the flow API.
/api/flowsList flows owned by the authenticated workspace.
/api/flowsCreate a draft flow or clone a flow template.
/api/flows/:idFetch a flow and its nodes.
/api/flows/:idReplace flow settings and its node graph.
/api/flows/:idDelete a flow and its related runs.
fetch('/api/flows', {
method: 'POST',
headers: {
'Authorization': 'Bearer wawexa_live_your_api_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'Lead qualification',
trigger_type: 'keyword',
trigger_config: { keyword: 'start' }
})
})// app/api/wawexa/request/route.ts
export async function POST(request: Request) {
const response = await fetch('https://wawexa.com/api/flows', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.WAWEXA_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(await request.json()),
});
return Response.json(await response.json(), { status: response.status });
}Receive events securely.
Configure Meta to send WhatsApp messages and status updates to this endpoint. Wa-Wexa verifies the HMAC signature before processing the event.
/api/whatsapp/webhookHandles Meta webhook verification using hub.mode, hub.verify_token, and hub.challenge.
/api/whatsapp/webhookAccepts signed Meta webhook payloads and returns { status: 'received' }.
POST https://your-wa-wexa-domain.com/api/whatsapp/webhook
Headers:
x-hub-signature-256: sha256=<meta-signature>
Content-Type: application/json