Docs Bridge

The WhatsApp API, documented.

REST to send and read, signed webhooks to receive, and an MCP server ready for your agent. Integrate WhatsApp into your product with line_id and API keys.

First steps

From zero to your first message in 3 steps.

1. Connect a line

In the console, scan the QR code with the WhatsApp of the number you want to use. You get a line_id.

2. Create an API key

In the console, generate an API key. It starts with wzb_live_ and is shown only once.

3. Call the API

Use your line_id and your API key to send the first message (example below).

curl -X POST https://www.wazion.com/api/bridge/v1/messages/send \
  -H "Authorization: Bearer TU_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: TU_OPERACION_UNICA" \
  -d '{"line_id":"TU_LINE_ID","to":"+34600000000","message":"Hello from WAzion Bridge"}'

The console is where you manage lines, API keys, and webhooks. The documentation describes the same API that you can test there.

Authentication

API base and authentication.

REST basehttps://www.wazion.com/api/bridge/v1
MCP serverhttps://www.wazion.com/api/bridge/mcp
HeaderAuthorization: Bearer wzb_live_...

All requests are authenticated with an API key in the Authorization header (it is also accepted X-Bridge-Key). API keys are created in the console and start with wzb_live_. Each response includes a header X-Request-Id tool for support and debugging. The API supports CORS (Access-Control-Allow-Origin: *).

Authorization: Bearer wzb_live_xxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json
Concepts

How Bridge is organized.

line_id

Identify a WhatsApp line connected by QR. Every send or read request uses a line_id.

API key

Credential wzb_live_ that authenticates your application. You can create, rotate, and revoke several in the console.

Webhook

You receive incoming events (messages, states) signed with HMAC at the URL you configure.

You always work with line_id and API keys. Bridge hides the internal WhatsApp session: you never expose or use the session_key.

Reference

REST endpoints.

ActionEndpoint
Account, plan, and limitsGET /v1/me
Period consumptionGET /v1/usage
List linesGET /v1/lines
Detail of a lineGET /v1/lines/{line_id}
Send textPOST /v1/messages/send
Send mediaPOST /v1/messages/send-media
Respond by quotingPOST /v1/messages/reply
Check the status of a shipmentGET /v1/messages/status
React with emojiPOST /v1/messages/react
Mark as readPOST /v1/messages/read
Archive chatPOST /v1/chats/archive
List chatsGET /v1/chats
Read messagesGET /v1/messages
List / create webhooksGET /v1/webhooks · POST /v1/webhooks
Test a webhookPOST /v1/webhooks/{id}/test

POST /v1/messages/send

ParameterTypeDescription
line_idstringmandatoryLine connected from which it is sent.
tostringmandatoryDestination phone in international format, e.g. +34600000000.
messagestringmandatoryMessage text.
archive_policyenumoptionalnever · always · preserve_if_previously_archived

The send, send-media, and reply requests require the Idempotency-Key header. The GET /v1/chats and GET /v1/messages readings limit the result to 500 and 200 respectively.

Examples

Send a message in your language.

curl -X POST https://www.wazion.com/api/bridge/v1/messages/send \
  -H "Authorization: Bearer wzb_live_xxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-1001" \
  -d '{"line_id":"line_xxx","to":"+34600000000","message":"Pedido confirmado"}'
// Node 18+ (fetch nativo)
const res = await fetch("https://www.wazion.com/api/bridge/v1/messages/send", {
  method: "POST",
  headers: {
    "Authorization": "Bearer wzb_live_xxx",
    "Content-Type": "application/json",
    "Idempotency-Key": "order-1001"
  },
  body: JSON.stringify({
    line_id: "line_xxx",
    to: "+34600000000",
    message: "Pedido confirmado"
  })
});
console.log(await res.json());
import requests

r = requests.post(
    "https://www.wazion.com/api/bridge/v1/messages/send",
    headers={
        "Authorization": "Bearer wzb_live_xxx",
        "Idempotency-Key": "order-1001",
    },
    json={
        "line_id": "line_xxx",
        "to": "+34600000000",
        "message": "Pedido confirmado",
    },
)
print(r.json())
<?php
$ch = curl_init("https://www.wazion.com/api/bridge/v1/messages/send");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer wzb_live_xxx",
        "Content-Type: application/json",
        "Idempotency-Key: order-1001",
    ],
    CURLOPT_POSTFIELDS => json_encode([
        "line_id" => "line_xxx",
        "to" => "+34600000000",
        "message" => "Pedido confirmado",
    ]),
]);
echo curl_exec($ch);
Multimedia

Send image, video, audio, or document.

Use media_type with one of these values: image, video, audio, document. The media_url field must be a public URL that the server can download.

ParameterTypeDescription
line_idstringmandatoryShipping line.
tostringmandatoryDestination phone.
media_urlstring (URL)mandatoryPublic URL of the file.
media_typeenumoptionalimage · video · audio · document (by default image)
captionstringoptionalText attached to the file.
curl -X POST https://www.wazion.com/api/bridge/v1/messages/send-media \
  -H "Authorization: Bearer wzb_live_xxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: media-1001" \
  -d '{"line_id":"line_xxx","to":"+34600000000","media_url":"https://tu-cdn.com/foto.jpg","media_type":"image","caption":"Hello"}'
Reliability

Idempotence.

The send, send-media, and reply shipments require the header. Idempotency-Key with a unique identifier for your operation. During an occurrence, repeating the same key with the same body returns the saved state without resending or consuming quota again. A completed key can initiate a new occurrence when its 24-hour retention expires; network retries of the active occurrence always retain their same internal identity.

-H "Idempotency-Key: pedido-1001"

The responses queued, processing, and sent_unconfirmed include status_url to query GET /v1/messages/status. Only sent with message_id confirms the sending; sent_unconfirmed requires reconciliation or manual review, and Bridge never resends it or automatically returns its quota. If you reuse the same active key with a different body, you receive 409 idempotency_conflict.

GET https://www.wazion.com/api/bridge/v1/messages/status?endpoint=messages%2Fsend&idempotency_key=pedido-1001
Webhooks

Receive signed events.

Create a webhook with a public HTTPS URL. Bridge will send a POST to that URL on each event. Each webhook has its own secret. (wzb_whsec_...) that is shown only once when creating it.

Events you can subscribe to: message.received, message.sent, message.status, line.connected, line.disconnected. line.status it is a subscription alias that includes both line events.

The event field of the body and the header X-WAzion-Bridge-Event always use the normalized name. event_id and X-WAzion-Bridge-Event-Id retain the same identity across all retries.

Each delivery includes these headers:

X-WAzion-Bridge-Event: message.received
X-WAzion-Bridge-Signature: sha256=<hmac>
Content-Type: application/json

{
  "event": "message.received",
  "line_id": "line_xxx",
  "data": { ... }
}

Verify the signature

The signature is an HMAC-SHA256 of the raw body using the webhook secret. Always compare before processing:

// Node.js
import crypto from "node:crypto";

function verify(rawBody, signatureHeader, secret) {
  const expected = "sha256=" + crypto
    .createHmac("sha256", secret)
    .update(rawBody)
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(signatureHeader),
    Buffer.from(expected)
  );
}
<?php
// PHP
$raw = file_get_contents("php://input");
$sig = $_SERVER["HTTP_X_WAZION_BRIDGE_SIGNATURE"] ?? "";
$expected = "sha256=" . hash_hmac("sha256", $raw, $secret);
if (!hash_equals($expected, $sig)) { http_response_code(401); exit; }

You can trigger a test event to your webhook from the console or with POST /v1/webhooks/{id}/test.

Errors

Error handling.

Authentication, account, and server errors use a standardized envelope:

{
  "ok": false,
  "error": { "code": "unauthorized", "message": "...", "retryable": false }
}

Validation and business errors use a flat form with the error code:

{ "error": "quota_exceeded", "message": "Monthly quota exceeded", "metric": "sent_messages", "used": 10000, "limit": 10000, "plan": "pro" }
CodeHTTPMeaning
unauthorized401Missing, invalid, or revoked API key.
subscription_required402The Bridge subscription is not active.
validation_error400Fields are missing or invalid.
line_not_found404The line_id does not exist in your account.
line_not_connected409The line is not connected to WhatsApp.
idempotency_key_required428Missing Idempotency-Key in a durable shipment.
idempotency_conflict409Same Idempotency-Key with different body.
quota_exceeded429You exceeded the quota for the period.
line_limit_reached429You have reached the maximum number of lines in the plan.
server_error500Internal error; you can try again.
Limits and quotas

Plan fees.

  • The quotas (sent messages, webhook events, number of lines) are per account and are counted within your billing cycle.
  • Upon exceeding a quota, you receive 429 (quota_exceeded or line_limit_reached) with the details of used, limit, and plan.
  • GET /v1/chats returns a maximum of 500 chats and GET /v1/messages a maximum of 200 messages per request.
  • For the stability of WhatsApp, the deliveries of the same line are spaced a few seconds apart; it distributes mass deliveries over time.

Check your consumption at any time with GET /v1/usage. The specific limits of each plan are in the plans page.

MCP

MCP server for your agent.

Bridge exposes an MCP (Model Context Protocol) server so that your agent can send and read WhatsApp without writing REST code. Add it with:

claude mcp add --transport http wazion-bridge \
  https://www.wazion.com/api/bridge/mcp \
  --header "Authorization: Bearer wzb_live_xxx"

The initialize response delivers Mcp-Session-Id. The client must return that header: along with the JSON-RPC id and the arguments, it reliably identifies the MCP submissions. If the client does not maintain sessions, it must explicitly provide idempotency_key in send, send-media, and reply.

ToolParameters
bridge_list_lines
bridge_send_messageline_id, to, message, archive_policy?
bridge_send_medialine_id, to, media_url, media_type?, caption?
bridge_reply_messageline_id, to, message, quoted_message_id
bridge_react_messageline_id, jid, message_id, emoji
bridge_get_chatsline_id, limit?, archived?
bridge_get_messagesline_id, phone, limit?
bridge_archive_chatline_id, phone, archive?

Ready to integrate.

Connect a line, create your API key, and test each endpoint from the console.

WAzion Assistant

Commercial information and technical support

Hello! I am the WAzion assistant. I can help you with information about prices and plans, technical questions, configuration, or any questions about our product. How can I assist you?
Developed with WAzion AI