Quickstart
This guide takes you from sign-up to a first message sent through the API and a reply received back. There are five steps, and the second one (connecting your WhatsApp number) is the one people skip most: without it, every send answers 409 number_not_connected.
You need a phone with WhatsApp on the number that will send the messages. Turbo Notify connects to it as a linked device, the same way WhatsApp Web does, and the phone keeps working as usual.
That is why there is no Meta sign-up and no message template approval: Turbo Notify is an independent service, not affiliated with Meta, and does not use the official WhatsApp Business API. Every send follows a pace that helps protect your number, and the good practices keep it healthy.
1. Create your account
Create a free account at dashboard.turbonotify.com. If you already have one, sign in and go to the next step.
2. Connect your main number
The main number is the WhatsApp that sends and receives your account’s messages. You connect it in the dashboard:
- In the dashboard, open Numbers (opens in a new tab) and, on the Main number card, click Connect main number.
- Choose QR code or Pairing code.
- On the phone, open WhatsApp at Linked devices > Link a device. For the QR code, point the camera at the screen. For the code, tap Link with phone number instead and type the code shown in the dashboard.
- The card now shows the number as connected, and Turbo Notify appears under Linked devices on the phone with your organization’s name.
To check it through the API, GET /v1/numbers/main returns status: "connected" (see Status).
3. Create an API key
In the dashboard, open API keys (opens in a new tab) and create a key with the Full access template. The value is shown only once: copy it and store it somewhere safe. Every request carries the key in the Authorization: Bearer YOUR_KEY header (details in API key).
4. Send your first message
Replace YOUR_KEY with your key and the recipient with a WhatsApp number of yours, country code included:
curl -X POST \ https://api.turbonotify.com/v1/messages \ -H "Authorization: Bearer YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "to": {"number": "+5511988887777"}, "content": {"text": "Your order is confirmed!"} }'const response = await fetch('https://api.turbonotify.com/v1/messages', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ to: { number: '+5511988887777' }, content: { text: 'Your order is confirmed!' } })});
const result = await response.json();console.log(result);import requests
url = "https://api.turbonotify.com/v1/messages"headers = { "Authorization": "Bearer YOUR_KEY", "Content-Type": "application/json"}data = { "to": {"number": "+5511988887777"}, "content": {"text": "Your order is confirmed!"}}
response = requests.post(url, json=data, headers=headers)result = response.json()print(result)package main
import ( "fmt" "io" "net/http" "strings")
func main() { payload := strings.NewReader(`{"to": {"number": "+5511988887777"}, "content": {"text": "Your order is confirmed!"}}`) req, _ := http.NewRequest("POST", "https://api.turbonotify.com/v1/messages", payload) req.Header.Set("Authorization", "Bearer YOUR_KEY") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) fmt.Println(string(body))}<?php$url = 'https://api.turbonotify.com/v1/messages';$data = [ 'to' => ['number' => '+5511988887777'], 'content' => ['text' => 'Your order is confirmed!']];
$options = [ 'http' => [ 'header' => [ 'Authorization: Bearer YOUR_KEY', 'Content-Type: application/json' ], 'method' => 'POST', 'content' => json_encode($data) ]];
$context = stream_context_create($options);$result = file_get_contents($url, false, $context);$response = json_decode($result, true);var_dump($response);?>using System.Text;using System.Text.Json;
var client = new HttpClient();client.DefaultRequestHeaders.Add("Authorization", "Bearer YOUR_KEY");
var data = new { to = new { number = "+5511988887777" }, content = new { text = "Your order is confirmed!" }};
var json = JsonSerializer.Serialize(data);var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync( "https://api.turbonotify.com/v1/messages", content);var result = await response.Content.ReadAsStringAsync();Console.WriteLine(result);import java.net.http.*;import java.net.URI;
public class TurboNotify { public static void main(String[] args) throws Exception { var client = HttpClient.newHttpClient();
var json = """ { "to": {"number": "+5511988887777"}, "content": {"text": "Your order is confirmed!"} } """;
var request = HttpRequest.newBuilder() .uri(URI.create("https://api.turbonotify.com/v1/messages")) .header("Authorization", "Bearer YOUR_KEY") .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString(json)) .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.body()); }}The 202 response means Turbo Notify accepted the message. Delivery to WhatsApp happens right after, asynchronously:
{
"message_id": "msg_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
"status": {
"state": "pending",
"at": "2025-07-16T10:00:00Z",
"error": null
}
} To follow the delivery, get the message by its message_id:
curl https://api.turbonotify.com/v1/messages/msg_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4 \ -H "Authorization: Bearer YOUR_KEY"const response = await fetch('https://api.turbonotify.com/v1/messages/msg_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4', { headers: { 'Authorization': 'Bearer YOUR_KEY' }});const result = await response.json();console.log(result.status.state); // 'sent', 'delivered', 'read', ...import requests
response = requests.get( 'https://api.turbonotify.com/v1/messages/msg_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4', headers={'Authorization': 'Bearer YOUR_KEY'})print(response.json()['status']['state'])package main
import ( "fmt" "io" "net/http")
func main() { req, _ := http.NewRequest("GET", "https://api.turbonotify.com/v1/messages/msg_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4", nil) req.Header.Set("Authorization", "Bearer YOUR_KEY") resp, _ := http.DefaultClient.Do(req) body, _ := io.ReadAll(resp.Body) fmt.Println(string(body))}<?php$ch = curl_init('https://api.turbonotify.com/v1/messages/msg_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4');curl_setopt($ch, CURLOPT_HTTPHEADER, ['Authorization: Bearer YOUR_KEY']);curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);$result = json_decode(curl_exec($ch), true);echo $result['status']['state'];?>using var client = new HttpClient();client.DefaultRequestHeaders.Add("Authorization", "Bearer YOUR_KEY");var response = await client.GetAsync( "https://api.turbonotify.com/v1/messages/msg_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4");Console.WriteLine(await response.Content.ReadAsStringAsync());import java.net.URI;import java.net.http.*;
public class TurboNotify { public static void main(String[] args) throws Exception { var client = HttpClient.newHttpClient(); var request = HttpRequest.newBuilder() .uri(URI.create("https://api.turbonotify.com/v1/messages/msg_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4")) .header("Authorization", "Bearer YOUR_KEY") .GET() .build(); var response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.body()); }}{
"id": "msg_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
"organization_id": "org_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
"number_alias": "main",
"number_id": "num_0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"from": {
"contact_id": "ct_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
"name": "My Company",
"number": "5511977776666",
"alias": "main"
},
"to": {
"number": "5511988887777"
},
"preview": "Your order is confirmed!",
"content_expired": false,
"text": "Your order is confirmed!",
"content_type": "text",
"direction": "outbound",
"channel": "whatsapp",
"origin": "tn",
"at": "2025-07-16T10:00:00Z",
"status": {
"state": "delivered",
"at": "2025-07-16T10:00:05Z"
}
} Delivery states are listed in Message status.
5. Receive replies
When someone replies, Turbo Notify produces a message.received event. You get it in one of two ways:
| Option | How it works | When to use it |
|---|---|---|
| Webhook | Turbo Notify sends a signed POST to your endpoint for every event. Set the URL in the dashboard, under Webhooks (opens in a new tab) . Available from the Lone Wolf plan. | You have a public HTTPS endpoint and want to react right away. |
| Event polling | You call GET /v1/events from time to time (scope events:read). Available on every plan. | You have no public endpoint, you are testing, or you are on the free plan. |
Both deliver the same events in the same format. To choose, see Event polling.
What can go wrong
| Response | What it means | What to do |
|---|---|---|
409 number_not_connected | The sending number is not connected to WhatsApp. | Go back to step 2 and connect the main number. If it was connected, check that Turbo Notify was not removed from Linked devices on the phone. |
401 not_authenticated | The key is missing, wrong or revoked. | Check the Authorization: Bearer YOUR_KEY header. |
403 insufficient_scope | The key lacks the operation’s scope (required_scope names it). | Use a key with that scope, or the Full access template. |
400 invalid_phone_number | The recipient is not a valid phone number. | Send the number with its country code, such as +5511988887777. |
429 send_rate_spacing | You sent before the minimum interval between messages of your plan. | Wait the seconds in the Retry-After header. This pace protects your number. |
429 messages_quota_exceeded or 402 contact_quota_exceeded | The cycle’s message or contact quota is used up. | See Quota and usage. |
Message with state: "failed" | WhatsApp did not accept the message. | The status.error field carries the code and a hint. See Message status. |
Every code is listed in Error codes.
Next steps
- Build an AI agent: your agent reads and replies on WhatsApp through the MCP server, signing in with your account or with a key.
- Resell to your customers: one number per customer, paired from inside your own platform.
- Send media, reactions and typing indicator: beyond text.
- API reference: every endpoint, with request testing from the browser.
- Protect your number: the sending pace and the good practices that keep your number healthy.