Test WhatsApp sends, replies and webhooks from a shared Pozy number before you buy or connect a number of your own. Free.
The sandbox lets you try WhatsApp end to end without a number, a WABA or a Meta review. Pozy runs one shared WhatsApp number for testing. You prove you own a test phone by replying to it once, and for the next 7 days that phone is a normal conversation in your inbox: you can send it a template, chat with it freely and receive every webhook.
It costs nothing. When you are ready for real traffic, get a number of your own.
#Sandbox limits
| Property | Value |
|---|---|
| Number | One shared Pozy number, returned under sandbox by GET /v1/phone-numbers |
| Templates | One, locked: sandbox_start in en, no variables |
| Free-form messages | Yes, inside the 24-hour window each reply opens |
| Test phones | 1 per user at a time |
| Daily cap | 50 messages and 5 distinct recipients per 24 hours |
| Activation link validity | 24 hours while pending |
| Session length | 7 days after activation |
| Price | Free: no number charge and no message charge |
Because the number is shared, a phone can only be messaged after its owner has replied to it from WhatsApp. That stops anyone from using the sandbox to reach strangers.
#Try it
#Find the sandbox number
Call GET /v1/phone-numbers. The sandbox object holds the number, the accountId you send from and the locked template.
{
"numbers": [],
"connected": [],
"sandbox": {
"phoneNumber": "+14155550100",
"accountId": "6716e3b8a4c7f92d5e1b6c08",
"template": { "name": "sandbox_start", "language": "en" },
"isSandbox": true
}
}#Activate your test phone
Call POST /v1/whatsapp/sandbox/sessions with the phone in E.164. Pozy creates a pending session and immediately sends sandbox_start to that phone.
curl -X POST https://api.pozy.ai/v1/whatsapp/sandbox/sessions \
-H "Authorization: Bearer $POZY_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "phone": "+351912345678" }'const res = await fetch("https://api.pozy.ai/v1/whatsapp/sandbox/sessions", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.POZY_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ phone: "+351912345678" }),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error);
console.log(data.session.status, data.sandboxNumber); // "pending"import os
import requests
H = {"Authorization": f"Bearer {os.environ['POZY_API_KEY']}"}
resp = requests.post(
"https://api.pozy.ai/v1/whatsapp/sandbox/sessions",
headers=H,
json={"phone": "+351912345678"},
timeout=30,
)
print(resp.json()["session"]["status"])Posting the same phone again is safe: it resends the template.
#Reply from the phone
Open WhatsApp on the test phone and reply to the message, or tap its button. Any reply flips the session to active. Watch for it with a message.received webhook, or poll GET /v1/whatsapp/sandbox/sessions until status is active.
#Send messages
The phone is now an ordinary WhatsApp conversation. Send the locked template with POST /v1/inbox/conversations, using the sandbox accountId and the phone as digits only:
curl -X POST https://api.pozy.ai/v1/inbox/conversations \
-H "Authorization: Bearer $POZY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"accountId": "6716e3b8a4c7f92d5e1b6c08",
"participantId": "351912345678",
"templateName": "sandbox_start",
"templateLanguage": "en",
"templateParams": []
}'Each reply from the phone opens a 24-hour window. Inside it, POST /v1/inbox/conversations/{conversationId}/messages sends free-form text, attachments and interactive messages, exactly as with a real number.
#Switch to another test phone
You can test one phone at a time. Revoke the current session with DELETE /v1/whatsapp/sandbox/sessions/{sessionId}, then activate the new phone. Messages already exchanged stay in the inbox; revoking only blocks new sends.
To send sandbox traffic to its own endpoint, create a webhook scoped to the sandbox accountId. Note that an account-scoped endpoint no longer receives events that belong to no account, such as whatsapp.number.*.
#What the sandbox cannot do
- Send to more than one phone at a time, or to anyone who has not replied.
- Send any template other than
sandbox_start, or use templates from your own WhatsApp Manager. - Carry production traffic. It exists to test your integration, not to message customers.
#Common errors
| Error | Cause | Fix |
|---|---|---|
400 "You can only test one phone at a time" |
Another phone has an active or pending session. The message names it. | Revoke that session first |
400 "This phone is not activated for sandbox sends" |
The recipient has not replied yet | Finish activation for that phone |
400 "Cannot activate the sandbox number itself" |
You passed the sandbox number as phone |
Use your own WhatsApp number |
400 "Could not send the activation message" |
Meta refused the send, usually because the phone is not on WhatsApp. Meta's message is included. | Check the number |
rate_limited |
50 messages or 5 recipients in 24 hours | Wait for the rolling window, or use your own number |
#Endpoints
| Endpoint | What it does |
|---|---|
GET /v1/phone-numbers |
List phone numbers |
GET /v1/whatsapp/sandbox/sessions |
List your sandbox sessions |
POST /v1/whatsapp/sandbox/sessions |
Start a sandbox activation |
DELETE /v1/whatsapp/sandbox/sessions/{sessionId} |
Revoke a sandbox session |
POST /v1/inbox/conversations |
Create conversation |
POST /v1/inbox/conversations/{conversationId}/messages |
Send message |
#Webhook events
| Event | When it fires |
|---|---|
message.received |
Message received. |
message.sent |
Message sent. |
message.delivered |
Message delivered. |
message.read |
Message read. |