Use the OnSync API when a customer system, plugin, or automation needs to work with OnSync without using the dashboard. The API is for customer-owned access. Do not ask customers for WhatsApp provider credentials.
Quick start
Base URL:
https://onsync.co/api/v1Create an API key in Settings > API. Give the key only the scopes your integration needs, then store the raw key server-side. OnSync only shows it once.
Test the key:
curl https://onsync.co/api/v1/me \
-H "Authorization: Bearer onsync_sk_live_..."If /me returns the scopes you expect, your integration can start calling the API.
Authentication
Send the API key as a bearer token:
Authorization: Bearer onsync_sk_live_...
Content-Type: application/jsonAvailable scopes:
| Scope | Use |
|---|---|
messages:write | Send text, media, and template messages |
templates:send | Send WhatsApp templates and OTP templates |
templates:read | List synced approved templates |
contacts:read | Read contacts |
contacts:write | Create or update contacts |
conversations:read | Read conversation records |
messages:read | Read messages inside conversations |
webhooks:read | List webhook endpoints |
webhooks:write | Create and delete webhook endpoints |
Use GET /me during plugin setup. It validates the key and returns the key prefix and scopes. It never returns the raw API key.
Endpoints
| Method | Path | Use |
|---|---|---|
GET | /me | Validate an API key and inspect scopes |
POST | /messages/send | Send WhatsApp, Instagram, Facebook, Telegram, or X messages |
GET | /templates | List synced templates |
GET | /contacts | List contacts |
POST | /contacts | Create or update a contact |
GET | /conversations | List conversations |
GET | /conversations/{conversationId}/messages | List conversation messages |
GET | /webhooks | List webhook endpoints |
POST | /webhooks | Create a webhook endpoint |
DELETE | /webhooks/{webhookId} | Delete a webhook endpoint |
Send a WhatsApp message
Use POST /messages/send for text, media, and template sends. Required scope: messages:write.
curl -X POST https://onsync.co/api/v1/messages/send \
-H "Authorization: Bearer onsync_sk_live_..." \
-H "Idempotency-Key: order-1001-ready" \
-H "Content-Type: application/json" \
-d '{
"platform": "whatsapp",
"to": "966500000000",
"messageType": "text",
"content": "Your order is ready for pickup.",
"clientReferenceId": "order-1001-ready"
}'Use Idempotency-Key on every retryable write. Idempotency is scoped per endpoint, so you can safely reuse the same external event id for a contact sync and a message send.
Send a WhatsApp OTP template
Use templates outside the WhatsApp 24-hour customer service window. Public API template sends require messages:write and templates:send.
The template must already be synced in OnSync and approved by Meta.
{
"platform": "whatsapp",
"to": "966500000000",
"messageType": "template",
"template": {
"name": "login_otp",
"language": "en_US",
"components": [
{
"type": "body",
"parameters": [
{ "type": "text", "text": "123456" }
]
},
{
"type": "button",
"sub_type": "url",
"index": "0",
"parameters": [
{ "type": "text", "text": "123456" }
]
}
]
},
"clientReferenceId": "login-otp-123"
}List synced templates with:
GET /api/v1/templates?status=APPROVED&category=AUTHENTICATIONContacts
Use contacts to keep external customer records aligned with OnSync conversations.
List contacts:
GET /api/v1/contacts?limit=50&phone=966500000000Required scope: contacts:read.
Create or update a contact:
curl -X POST https://onsync.co/api/v1/contacts \
-H "Authorization: Bearer onsync_sk_live_..." \
-H "Idempotency-Key: salla-customer-8123" \
-H "Content-Type: application/json" \
-d '{
"firstName": "Sara",
"lastName": "Ahmed",
"phone": "966500000000",
"email": "sara@example.com",
"channel": "whatsapp",
"tags": ["vip"],
"properties": {
"externalCustomerId": "8123"
}
}'Required scope: contacts:write.
Conversations
Use these endpoints when a plugin needs conversation context or delivery history. Responses are scoped to the API key organization and never include provider credentials.
List conversations:
GET /api/v1/conversations?channel=whatsapp&status=open&limit=50Required scope: conversations:read.
List messages in a conversation:
GET /api/v1/conversations/conv_123/messages?limit=50Required scope: messages:read.
Webhooks
Webhooks are the source of truth for message lifecycle tracking. Subscribe to delivery events for OTPs, template sends, and order notifications.
Create a webhook endpoint:
curl -X POST https://onsync.co/api/v1/webhooks \
-H "Authorization: Bearer onsync_sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"targetUrl": "https://example.com/webhooks/onsync",
"events": ["message.sent", "message.delivered", "message.failed"]
}'Required scope: webhooks:write.
The signingSecret is returned only once. Store it server-side.
List webhook endpoints:
GET /api/v1/webhooksRequired scope: webhooks:read.
Delete a webhook endpoint:
DELETE /api/v1/webhooks/{webhookId}Required scope: webhooks:write.
Webhook events
Messaging lifecycle events:
message.sentmessage.deliveredmessage.readmessage.failedtemplate.senttemplate.deliveredtemplate.readtemplate.failedmessage.received
Contact and conversation events:
contact.createdcontact.updatedconversation.createdconversation.assigned
Legacy Zapier-compatible events are still accepted for existing integrations: new_contact, new_message, and message_sent.
Webhook signatures
Webhook deliveries include:
X-OnSync-Event: message.sent
X-OnSync-Event-Id: evt_...
X-OnSync-Org-Id: org_...
X-OnSync-Timestamp: 2026-05-07T10:00:00.000Z
X-OnSync-Signature: sha256=...Verify X-OnSync-Signature using HMAC SHA-256 over:
{eventId}.{timestamp}.{rawBody}Respond with any 2xx status to acknowledge delivery. Failed deliveries are retried with capped backoff. Repeated terminal failures disable the endpoint.
Errors and limits
Authenticated responses include rate-limit headers:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 60Common errors:
| Status | Meaning |
|---|---|
400 | Validation failed, missing template data, or unapproved template |
401 | Missing or invalid API key |
403 | Valid key, but missing scope or inactive subscription |
409 | Idempotency key conflict or a matching request is still processing |
429 | Rate limit exceeded |
Common error codes:
MISSING_BEARER_TOKENINVALID_API_KEY_OR_SCOPERATE_LIMIT_EXCEEDEDVALIDATION_FAILEDIDEMPOTENCY_KEY_CONFLICTIDEMPOTENCY_KEY_PROCESSINGTEMPLATE_METADATA_REQUIREDTEMPLATE_NOT_APPROVEDCONVERSATION_NOT_FOUND
Plugin settings
Zapier, Salla, and Shopify plugins should use /api/v1 for customer-owned access.
| Plugin | Recommended setup |
|---|---|
| Zapier | Use GET /me for auth testing. Keep legacy /api/zapier routes only for existing Zapier app compatibility. |
| Salla | Use Salla event ids as Idempotency-Key. Typical scopes are contacts:write, messages:write, templates:send, and webhooks:write. |
| Shopify | Use order, customer, and checkout ids as idempotency keys. Track OnSync delivery events through OnSync webhooks, not Shopify webhook status. |