Hey Pingr API Documentation
Quickstart
Get your first WhatsApp login link sent in under 10 minutes. You'll need a Hey Pingr account and a WhatsApp number to connect.
Step by step
pk_live_ production key./v1/send with the user's number and your magic link.Your first request
const pingr = new Hey Pingr(process.env.PINGR_API_KEY);
const result = await pingr.messages.send({
to: '919876543210', // digits only, with country code
message: 'Click here to log in: https://yourapp.com/auth?token=abc123',
});
console.log(result.messageId); // msg_xK9p2mQr8nVs4wLj
console.log(result.rateLimitRemaining); // 499
client = pingr.Hey Pingr("pk_live_your_key_here")
result = client.messages.send(
to="919876543210", # digits only, with country code
message="Click here to log in: https://yourapp.com/auth?token=abc123"
)
print(result["message_id"]) # msg_xK9p2mQr8nVs4wLj
print(result["rate_limit_remaining"]) # 499
-H "X-API-Key: pk_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"to":"919876543210","message":"Log in: https://yourapp.com/auth?t=abc"}'
Response
"success": true,
"message_id": "msg_xK9p2mQr8nVs4wLj",
"to": "919876543210",
"session_id": "sess_abc123",
"rate_limit_remaining": 499
}
Authentication
All API requests must include your API key in the X-API-Key header. You can find and manage your keys in the dashboard.
API key types
Production keys (pk_live_) send real WhatsApp messages and count toward your plan limits.
Test keys (pk_test_) simulate the full API response without sending actual messages. Use these in development and CI.
Authenticating requests
Host: api.heypingr.com
X-API-Key: pk_live_xK9p2mQr8nVs4wLj7dFhTbYcXeAuZo
Content-Type: application/json
POST /v1/send
Sends a WhatsApp message to a phone number. The message is delivered via your connected session.
Request body
| Parameter | Type | Required | Description |
|---|---|---|---|
| to | string | required | Recipient phone — digits only with country code. e.g. 919876543210 (no +, no spaces) |
| message | string | required | The message text to send. Supports WhatsApp formatting: *bold*, _italic_, ~strikethrough~. |
| session_id | string | optional | Session ID to use. Omit to auto-pick any connected session. |
Response
"success": true,
"message_id": "msg_xK9p2mQr8nVs4wLj",
"to": "919876543210",
"session_id": "sess_abc123",
"rate_limit_remaining": 499
}
Status codes
Retry-After header.Webhooks
Hey Pingr sends a POST request to your configured webhook URL whenever an event occurs — like an incoming message from a user.
Verifying signatures
// Express — use express.raw() so body arrives as a Buffer
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
try {
const payload = verifyWebhook(
req.body,
req.headers['x-pingr-signature'],
process.env.PINGR_WEBHOOK_SECRET,
);
console.log(payload.event, payload.session_id);
res.sendStatus(200);
} catch (err) {
res.sendStatus(400); // invalid signature
}
});
Event payload — message.received
"event": "message.received",
"session_id": "sess_abc123",
"from": {
"phone": "919876543210",
"jid": "919876543210@s.whatsapp.net",
"is_group": false,
"group_jid": null
},
"message": { "text": "hey login", "type": "text" },
"timestamp": 1714825320000
}
Node.js SDK
The official Node.js SDK wraps the Hey Pingr REST API with a clean, typed interface.
Installation
Initialise
const pingr = new Hey Pingr(process.env.PINGR_API_KEY);
Send a message
to: '919876543210', // digits only, with country code
message: `Your login link: https://yourapp.com/auth?token=${token}`,
});
console.log(result.messageId); // msg_abc123
console.log(result.rateLimitRemaining); // 498
Error handling
try {
await pingr.messages.send({ to, message });
} catch (err) {
if (err instanceof errors.PingrRateLimitError) {
console.log(`Retry after ${err.retryAfter}s`);
} else if (err instanceof errors.PingrAuthError) {
console.log('Invalid API key');
}
}
Verify webhooks
// Express — use express.raw() to get a Buffer
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const payload = verifyWebhook(
req.body,
req.headers['x-pingr-signature'],
process.env.PINGR_WEBHOOK_SECRET,
);
console.log(payload.event); // 'message.received'
res.sendStatus(200);
});
Python SDK
The official Python SDK for Hey Pingr. Supports both sync and async usage.
Installation
# async support (FastAPI, asyncio)
pip install hey-pingr[async]
Usage
client = pingr.Hey Pingr("pk_live_your_key_here")
result = client.messages.send(
to="919876543210", # digits only, with country code
message=f"Your login link: https://yourapp.com/auth?token={token}"
)
print(result["message_id"]) # msg_abc123
print(result["rate_limit_remaining"]) # 498
Async usage (FastAPI, asyncio)
async def send_otp(phone: str, code: str):
async with pingr.AsyncPingr(os.environ["PINGR_API_KEY"]) as client:
result = await client.messages.send(
to=phone,
message=f"Your OTP is {code}"
)
return result["message_id"]
Verify webhooks
# Flask example
@app.route("/webhook", methods=["POST"])
def webhook():
try:
payload = verify_webhook(
request.get_data(),
request.headers["x-pingr-signature"],
os.environ["PINGR_WEBHOOK_SECRET"],
)
print(payload["event"]) # 'message.received'
return "", 200
except PingrWebhookError:
return "", 400
Rate limits
Hey Pingr enforces two levels of rate limiting to protect your sessions and ensure fair use.
Per-recipient cooldown
By default, the same phone number cannot receive a message more than once every 60 seconds. This is configurable in Dashboard → Settings → Cooldown settings.
When a number is rate limited, the API returns a 429 response with a Retry-After header indicating seconds remaining.
Plan-level limits
| Plan | Messages/month | Overage rate |
|---|---|---|
| Starter | 10,000 | $0.002/msg |
| Growth | 70,000 | $0.0015/msg |
| Scale | 500,000 | $0.0008/msg |
Handling 429 responses
try {
await pingr.messages.send({ to: '919876543210', message: 'Your OTP is 123456' });
} catch (err) {
if (err instanceof errors.PingrRateLimitError) {
console.log(`Rate limited. Retry in ${err.retryAfter}s`);
// Queue the message and schedule a retry
}
}
Error handling
All errors return a JSON body under a detail key with an error code and human-readable message.
"detail": {
"error": "rate_limit",
"message": "Number +919876543210 is in cooldown. Try again in 47s.",
"retry_after": 47
}
}
Error codes
| Code | HTTP | Description |
|---|---|---|
| invalid_key | 401 | The API key is missing or invalid. |
| missing_param | 422 | A required parameter is missing or malformed. |
| rate_limit | 429 | Recipient is in cooldown window. Check retry_after in the response. |
| quota_exceeded | 429 | Monthly message quota exhausted. Upgrade your plan. |
| no_session | 503 | No connected WhatsApp session found. Connect a number in the dashboard. |
Sessions & QR codes
A session represents a connected WhatsApp number on Hey Pingr's infrastructure. Each plan allows a different number of concurrent sessions.
Connecting a session
Go to Dashboard → Sessions → Add session. A QR code is generated. Open WhatsApp → Settings → Linked Devices → Link a device → scan the QR. The session goes live within seconds.
Session health monitoring
Hey Pingr monitors session health every 30 seconds. If a session disconnects (phone goes offline, WhatsApp logs out, etc.), a session.disconnected webhook event fires immediately and the dashboard shows a red status indicator.
GET /v1/sessions
Returns all sessions associated with your account and their current status.
"sessions": [
{
"id": "main-login-bot",
"name": "Main login bot",
"number": "+919876543210",
"status": "connected",
"connectedAt": "2025-04-18T08:22:11.000Z",
"messagesToday": 842
}
]
}