helpAPI Documentation

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/v1

Create 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/json

Available scopes:

ScopeUse
messages:writeSend text, media, and template messages
templates:sendSend WhatsApp templates and OTP templates
templates:readList synced approved templates
contacts:readRead contacts
contacts:writeCreate or update contacts
conversations:readRead conversation records
messages:readRead messages inside conversations
webhooks:readList webhook endpoints
webhooks:writeCreate 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

MethodPathUse
GET/meValidate an API key and inspect scopes
POST/messages/sendSend WhatsApp, Instagram, Facebook, Telegram, or X messages
GET/templatesList synced templates
GET/contactsList contacts
POST/contactsCreate or update a contact
GET/conversationsList conversations
GET/conversations/{conversationId}/messagesList conversation messages
GET/webhooksList webhook endpoints
POST/webhooksCreate 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=AUTHENTICATION

Contacts

Use contacts to keep external customer records aligned with OnSync conversations.

List contacts:

GET /api/v1/contacts?limit=50&phone=966500000000

Required 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=50

Required scope: conversations:read.

List messages in a conversation:

GET /api/v1/conversations/conv_123/messages?limit=50

Required 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/webhooks

Required scope: webhooks:read.

Delete a webhook endpoint:

DELETE /api/v1/webhooks/{webhookId}

Required scope: webhooks:write.

Webhook events

Messaging lifecycle events:

  • message.sent
  • message.delivered
  • message.read
  • message.failed
  • template.sent
  • template.delivered
  • template.read
  • template.failed
  • message.received

Contact and conversation events:

  • contact.created
  • contact.updated
  • conversation.created
  • conversation.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: 60

Common errors:

StatusMeaning
400Validation failed, missing template data, or unapproved template
401Missing or invalid API key
403Valid key, but missing scope or inactive subscription
409Idempotency key conflict or a matching request is still processing
429Rate limit exceeded

Common error codes:

  • MISSING_BEARER_TOKEN
  • INVALID_API_KEY_OR_SCOPE
  • RATE_LIMIT_EXCEEDED
  • VALIDATION_FAILED
  • IDEMPOTENCY_KEY_CONFLICT
  • IDEMPOTENCY_KEY_PROCESSING
  • TEMPLATE_METADATA_REQUIRED
  • TEMPLATE_NOT_APPROVED
  • CONVERSATION_NOT_FOUND

Plugin settings

Zapier, Salla, and Shopify plugins should use /api/v1 for customer-owned access.

PluginRecommended setup
ZapierUse GET /me for auth testing. Keep legacy /api/zapier routes only for existing Zapier app compatibility.
SallaUse Salla event ids as Idempotency-Key. Typical scopes are contacts:write, messages:write, templates:send, and webhooks:write.
ShopifyUse order, customer, and checkout ids as idempotency keys. Track OnSync delivery events through OnSync webhooks, not Shopify webhook status.