Connect with Wexora
Connect your store and tools to WhatsApp through Wexora.
Quick start
Create an API key and save it; it is shown only once. Send it in the Authorization header from your server only.
Authorization: Bearer YOUR_WEXORA_KEY Content-Type: application/json
Rate limits: 60 requests per minute per key, and 180 per account.
Create a key in the dashboard after the website content review. New keys include all available public integration permissions. The key name is taken from the reviewed website; no manual name or permission selection is needed. Existing keys retain their original permissions. Sent messages and OTP codes use the authenticated key name as their source label; source headers are not required. Pausing a key blocks new requests until it is resumed. Deleting a key is permanent.
Send a message
Link your WhatsApp number in the Wexora dashboard and copy its Session ID.
POST /api/v1/messagesUse a connected device, the messages.send permission and an available message balance. Reuse the same Idempotency-Key when retrying to prevent duplicates; changing the payload with the same key returns 409.
curl -X POST 'https://wexora.pro/api/v1/messages' \
-H 'Authorization: Bearer YOUR_KEY' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: order-123-confirmation' \
-d '{"session_id":"SESSION_ID","to":"+201000000000","type":"text","body":"Hello {{name}}","variables":{"name":"Alex"}}'// Server-side JavaScript only
const response = await fetch(`${process.env.WEXORA_URL}/api/v1/messages`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.WEXORA_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': 'order-123-confirmation'
},
body: JSON.stringify({session_id:'SESSION_ID', to:'+201000000000',
type:'text', body:'Hello {{name}}', variables:{name:'Alex'}})
});
const data = await response.json();
if (!response.ok) throw new Error(data.error);<?php
$ch = curl_init(getenv('WEXORA_URL') . '/api/v1/messages');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 20,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('WEXORA_KEY'),
'Content-Type: application/json',
'Idempotency-Key: order-123-confirmation'
],
CURLOPT_POSTFIELDS => json_encode([
'session_id' => 'SESSION_ID', 'to' => '+201000000000',
'type' => 'text', 'body' => 'Hello {{name}}',
'variables' => ['name' => 'Alex']
], JSON_UNESCAPED_UNICODE)
]);
$result = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
if ($result === false || $status >= 400) throw new RuntimeException('Request failed');HTTP 202
{"id":"MESSAGE_ID","status":"queued"}For media, set type to image, video or document. Provide a public HTTPS link in url and an optional caption.
OTP verification
Send a six-digit WhatsApp code with a Copy code button, then verify it from your server. Use a key with otp.send and otp.verify; existing keys do not gain these permissions automatically. OTP uses your connected Wexora device and message balance.
Authorization: Bearer YOUR_KEY
Idempotency-Key: otp-order-123-attempt-1
Content-Type: application/json
{
"session_id": "SESSION_ID",
"to": "+201000000000",
"purpose": "confirm_order",
"reference": "order-123:customer-456",
"language": "en"
}HTTP 202
{"id":"OTP_ID","status":"pending","delivery_status":"queued","expires_at":"2026-10-17 12:05:00"}English is the default language. Change "language": "en" to "language": "ar" for Arabic, including the copy button. Wexora generates the code and never returns it through the API. Default expiry: 5 minutes; optional expires_in: 60–600 seconds. Reuse the same Idempotency-Key for retries. To request a new code, wait 60 seconds and use a new key; it replaces the pending code for the same purpose and reference. Limit: 3 sends per recipient per 15 minutes.
Authorization: Bearer YOUR_KEY
Content-Type: application/json
{"code":"123456"}HTTP 200
{"id":"OTP_ID","verified":true,"status":"verified","attempts_remaining":4}Allow the operation only after this verification returns verified: true. Bind OTP_ID to your authenticated customer and intended operation on your server. Each code can be verified once, with up to 5 attempts. Copying a code does not verify it.
Use otp.send to check delivery and expiry. Queued or sent does not mean delivered. This release supports Wexora linked devices; Meta Cloud API authentication templates require separate setup. Keep API keys on your server.
Endpoints & permissions
| Endpoint | Permission |
|---|---|
| GET /api/v1/messages | messages.read |
| POST /api/v1/messages | messages.send |
| GET /api/v1/sessions | sessions.read |
| POST /api/v1/otp | otp.send |
| GET /api/v1/otp/{id} | otp.send |
| POST /api/v1/otp/{id}/verify | otp.verify |
Receive WhatsApp events
Add a Webhook destination to receive JSON events. Verify the signature using its secret, reject timestamps older than 5 minutes, and use event.id to prevent duplicate processing.
X-Wexora-Timestamp: UNIX_SECONDS X-Wexora-Signature: sha256=HEX_HMAC signature = HMAC_SHA256(timestamp + "." + raw_body, webhook_secret)
Events: message.sent, message.delivered, message.failed, message.received, session.connected, session.disconnected and campaign.completed. Delivery is retried up to 5 times. Use a public HTTPS URL without redirects.
Errors
Check Subscription & billing for your balance and plan limits. Use these response codes to troubleshoot requests.
| 401 | Invalid API key or authentication required |
| 402 | Subscription expired or plan limit reached |
| 403 | Insufficient permissions |
| 404 | Resource not found or unavailable to your account |
| 409 | State or idempotency key conflict |
| 422 | Invalid request data |
| 429 | Rate limit exceeded; check Retry-After |
| 503 | Service temporarily unavailable |
Use the Wexora agent in n8n
Use a Wexora API key with ai.invoke. Enable the agent and external automation for your session. Replies use your plan balance; no separate AI provider key is needed.
Add your Production URL in Webhooks and select message.received. Verify the event, then call:
POST /api/v1/ai/responses
Authorization: Bearer YOUR_WEXORA_KEY
Idempotency-Key: agent-EVENT_ID
Content-Type: application/json
{"session_id":"SESSION_ID","to":"+201000000000","message":"Customer question"}Use session_id, data.sender and data.body from the event. For responded, send reply through POST /api/v1/messages with the same session and number and the key reply-EVENT_ID. For handoff, transfer to an employee; for failed, do not send. After a 202 response, check GET /api/v1/ai/responses/{id}.
Reuse the same Idempotency-Key when retrying to avoid duplicate usage.