A bridge is a dedicated, hosted connection between one WhatsApp number and your app. Provision one, pair a phone number, and start sending messages over REST. No SDKs, no vendor approval, no infrastructure to manage. Not a developer? There's a no-code path too →
WABridges is a hosted relay between your application and the WhatsApp network. Your app makes REST calls to your bridge; inbound events fire back to your webhook URL in real time.
POST to /api/instances with a customer_ref you control (any string: user ID, order number, etc.) and your webhook URL. Authenticate every call with your account API key — Authorization: Bearer sk_... — created during onboarding or from the dashboard. The bridge starts immediately, and the customer_ref you chose addresses it in all later calls.
{
"customer_ref": "user-123",
"webhook_url": "https://your-app.com/whatsapp/hook"
}
← {
"id": "7d09aa9c-…",
"customer_ref": "user-123",
"state": "running"
}
Provisioning over the API requires an active subscription. On the free trial, create your first bridge from the dashboard instead - everything below works the same either way.
Scan the QR in the dashboard, or call /proxy/pair to request a link code programmatically. Open WhatsApp → Linked Devices → Link a device → Link with phone number and enter the 8-character code. Session persists across restarts.
{ "phone": "15550001234" }
← { "code": "ABCD-EFGH" }
Once paired, GET /proxy/status returns "status":"connected" along with the linked phone number and display name.
POST to /proxy/send/text with the destination number (no +, digits only) and message body. Same Authorization: Bearer sk_... API key as every other call. The response returns a message ID and Unix timestamp.
{ "chat": "15559876543", "body": "Hello from my app!" }
← { "message_id": "ACE41E...", "timestamp": 1777180605 }
The same proxy accepts media, polls, reactions, locations, and more. See the API reference for all endpoints.
Every inbound message, delivery receipt, call, or status change fires a POST to your webhook URL automatically. No polling. Respond with 200 OK to acknowledge.
{
"type": "message",
"from": "15559876543",
"body": "Hey, got your message!",
"timestamp": 1777180621,
"message_id": "BD71F2...",
"customer_ref": "user-123"
}
Send your first message using any HTTP client. Replace CUSTOMER_REF with the ref you chose in step 1 and API_KEY with your account API key from the dashboard.
curl -X POST \ https://wabridges.com/api/instances/$CUSTOMER_REF/proxy/send/text \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{"chat":"15559876543","body":"Hello!"}'
const res = await fetch( `https://wabridges.com/api/instances/${CUSTOMER_REF}/proxy/send/text`, { method: 'POST', headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ chat: '15559876543', body: 'Hello!', }), } ); const { message_id, timestamp } = await res.json();
import requests res = requests.post( f"https://wabridges.com/api/instances/{CUSTOMER_REF}/proxy/send/text", headers={"Authorization": f"Bearer {API_KEY}"}, json={"chat": "15559876543", "body": "Hello!"}, ) data = res.json() # {"message_id": "ACE41E...", "timestamp": 1777180605}
$ch = curl_init("https://wabridges.com/api/instances/$customerRef/proxy/send/text"); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer $apiKey", "Content-Type: application/json", ], CURLOPT_POSTFIELDS => json_encode(["chat" => "15559876543", "body" => "Hello!"]), ]); $data = json_decode(curl_exec($ch), true); // ["message_id" => "ACE41E...", "timestamp" => 1777180605]
require "net/http" require "json" uri = URI("https://wabridges.com/api/instances/#{customer_ref}/proxy/send/text") res = Net::HTTP.post( uri, { chat: "15559876543", body: "Hello!" }.to_json, "Authorization" => "Bearer #{api_key}", "Content-Type" => "application/json" ) data = JSON.parse(res.body) # {"message_id"=>"ACE41E...", "timestamp"=>1777180605}
payload, _ := json.Marshal(map[string]string{"chat": "15559876543", "body": "Hello!"}) req, _ := http.NewRequest("POST", "https://wabridges.com/api/instances/"+customerRef+"/proxy/send/text", bytes.NewReader(payload)) req.Header.Set("Authorization", "Bearer "+apiKey) req.Header.Set("Content-Type", "application/json") res, _ := http.DefaultClient.Do(req) // {"message_id":"ACE41E...","timestamp":1777180605}
let res = reqwest::blocking::Client::new() .post(format!("https://wabridges.com/api/instances/{customer_ref}/proxy/send/text")) .bearer_auth(api_key) .json(&serde_json::json!({ "chat": "15559876543", "body": "Hello!" })) .send()?; let data: serde_json::Value = res.json()?; // {"message_id":"ACE41E...","timestamp":1777180605}
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://wabridges.com/api/instances/" + customerRef + "/proxy/send/text"))
.header("Authorization", "Bearer " + apiKey)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(
"{\"chat\":\"15559876543\",\"body\":\"Hello!\"}"))
.build();
HttpResponse<String> res =
HttpClient.newHttpClient().send(req, HttpResponse.BodyHandlers.ofString());
// {"message_id":"ACE41E...","timestamp":1777180605}
Want the full tutorial with webhook handling? See the step-by-step quickstarts: Node.js, Python, PHP, Ruby, Go, Rust, Java.
First bridge is free for 7 days, no credit card required. Read the full API reference for every endpoint, webhook format, and error code.