Aviral WhatsApp Platform API

Build on WhatsApp with one REST API.

Send templates and session messages, sync contacts, launch campaigns and react to 56 real-time events. JSON over HTTPS, scoped keys, idempotent retries and signed webhooks.

Base URL https://whatsapp.aviraltechlab.com/api/v1

curl https://whatsapp.aviraltechlab.com/api/v1/messages \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-1042-confirmation" \
  -d '{
    "to": "+919876543210",
    "type": "template",
    "template": {
      "name": "order_confirmation",
      "language": "en",
      "parameters": { "1": "Asha", "2": "#1042" }
    }
  }'

Quickstart

Your first message in three steps

Everything works in test mode first, so you can build without sending real messages or spending credit.

  1. 01

    Create a test key

    In Settings → Developers, create a key in test mode with the scopes you need.

  2. 02

    Send a message

    Call POST /messages with one of your approved templates (replace order_confirmation and its parameters). Test keys never reach WhatsApp.

  3. 03

    Receive events

    Add a webhook endpoint to get delivery status, replies and opt-outs pushed to you.

Recipes

Common tasks

Copy, set API_KEY and run. Every sample uses the same endpoints as the API reference.

Create or update a contact

Matches on the phone number, so it is safe to call on every signup or order.

curl https://whatsapp.aviraltechlab.com/api/v1/contacts/upsert \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "+919812345678",
    "name": "Asha Rao",
    "tags": ["vip"],
    "attributes": { "city": "Pune" }
  }'

Reply with buttons

Free-form and interactive messages need an open 24-hour window (the contact messaged you); otherwise the API answers 409 window_closed and you send a template.

curl https://whatsapp.aviraltechlab.com/api/v1/messages \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "+919812345678",
    "type": "interactive",
    "interactive": {
      "type": "button",
      "body": { "text": "Would you like to reorder?" },
      "buttons": [
        { "id": "reorder_yes", "title": "Yes, reorder" },
        { "id": "reorder_no", "title": "Not now" }
      ]
    }
  }'

Page through contacts

Lists are cursor-paginated (up to 100 per page). The SDKs fetch the next page for you.

curl "https://whatsapp.aviraltechlab.com/api/v1/contacts?tag=vip&limit=100" \
  -H "Authorization: Bearer $API_KEY"
# next page: add &after=<next_cursor> while has_more is true

Subscribe to events

Creates a webhook endpoint. The signing secret is returned once: store it next to your API key.

curl https://whatsapp.aviraltechlab.com/api/v1/webhook_endpoints \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/webhooks/whatsapp",
    "events": ["message.received", "message.failed"]
  }'

Clean up duplicates and opt-outs

Finds contacts that look like the same person and merges them (the first one is kept, the others are deleted), then opts out a pasted list of numbers. Numbers that are not valid phones come back in `invalid`.

# 1. Groups of contacts with the same phone number
curl "https://whatsapp.aviraltechlab.com/api/v1/contacts/duplicates?reason=phone" \
  -H "Authorization: Bearer $API_KEY"

# 2. Keep one contact and merge the others into it (use the ids from step 1; chats and tags move over)
curl https://whatsapp.aviraltechlab.com/api/v1/contacts/$KEEP_ID/merge \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "source_ids": ["'"$DUPLICATE_ID"'"] }'

# 3. Opt out a list of numbers (unknown numbers become contacts so the opt-out holds)
curl https://whatsapp.aviraltechlab.com/api/v1/opt_outs \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phones": ["+919812345678", "9876500011"],
    "default_country": "IN",
    "reason": "Do-not-disturb registry sync"
  }'

Automate without code

Start automations from anywhere

Fire a flow from your backend, a website form or a Zapier or Make webhook, and subscribe tools like Zapier the way their apps do.

Trigger an automation from your backend

Report an event from your own system. Every active automation that listens to this source and topic starts a run for the contact (shown in its Runs). Send the same external_id again within 24 hours and nothing starts twice. Use a live key: a test key never starts runs.

curl https://whatsapp.aviraltechlab.com/api/v1/integrations/events \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: checkout-1042" \
  -d '{
    "source": "shopify",
    "topic": "checkouts/abandoned",
    "external_id": "checkout-1042",
    "contact": { "phone": "+919812345678", "name": "Asha Rao" },
    "create_contact": true,
    "payload": {"abandoned_checkout_url":"https://shop.example.com/cart/c-1042","total":1499}
  }'
# 202 { "automation_runs": [{ "automation_id": "…", "run_id": "…" }], "duplicate": false }

Webhook trigger URL (forms, Zapier or Make webhooks, n8n)

Each automation with a Webhook trigger has its own URL and token (Automations, open it, then its trigger). POST any JSON to it: the contact is found at the trigger's phone field (by default "phone"), and every other field becomes {{trigger.payload.field}} in the flow. The run appears under that automation's Runs.

curl "https://whatsapp.aviraltechlab.com/api/hooks/automations/<AUTOMATION_ID>" \
  -H "X-Aviral-Hook-Token: $HOOK_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "+919812345678",
    "name": "Asha Rao",
    "order_number": "KC-10482",
    "total": 1499
  }'
# 202 { "runId": "…" }  (409 automation_not_active while the automation is not published)

Subscribe like Zapier (REST hooks)

Zapier-style apps subscribe when a Zap is switched on and unsubscribe when it is switched off. Tag the endpoint with its source so it shows as "via zapier" in Settings, Developers, Webhooks. The signing secret is returned once: verify every delivery with it (see Verify a webhook).

# Subscribe (Zap switched on)
curl https://whatsapp.aviraltechlab.com/api/v1/webhook_endpoints \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://hooks.zapier.com/hooks/standard/123456/abcdef/",
    "events": ["message.received"],
    "source": "zapier"
  }'
# 201 { "id": "…", "secret": "whsec_…" }  (the secret is shown once)

# Unsubscribe (Zap switched off)
curl -X DELETE https://whatsapp.aviraltechlab.com/api/v1/webhook_endpoints/$ENDPOINT_ID \
  -H "Authorization: Bearer $API_KEY"

API reference

Everything in the app, over the API

Each area links to its endpoints, request and response schemas and a cURL sample for every call.

SDKs

Official libraries for Node.js, Python and PHP

Typed clients with automatic retries, idempotency keys, cursor pagination helpers and webhook signature verification.

npm install @aviral-wa/sdk
import express from 'express';
import { verifyWebhook, WebhookVerificationError } from '@aviral-wa/sdk';

const app = express();

// express.raw keeps the exact bytes received: verify them, never re-serialised JSON.
app.post('/webhooks/whatsapp', express.raw({ type: 'application/json' }), async (req, res) => {
  try {
    const event = await verifyWebhook(
      req.body,
      req.headers['x-aviral-signature'],
      process.env.WEBHOOK_SECRET, // whsec_…
      { toleranceSec: 300 },
    );
    console.log(event.type, event.id); // dedupe on event.id: delivery is at-least-once
    res.sendStatus(200);
  } catch (err) {
    if (err instanceof WebhookVerificationError) return res.sendStatus(400);
    throw err;
  }
});

app.listen(3000);

Essentials

How the API behaves

Conventions that apply to every endpoint. The API reference has the full details.

Authentication
Send Authorization: Bearer <key>. Test keys (awk_test_) use your data but never reach WhatsApp. Keys are shown once and stored only as a hash.
Idempotency
Send an Idempotency-Key header on every POST. Retries with the same key replay the first response for 24 hours.
Rate limits
From 10 requests per second per key, depending on your plan. Every response carries X-RateLimit headers; 429 includes Retry-After.
Pagination
Lists return { data, has_more, next_cursor }. Pass ?after=<cursor> and ?limit= (up to 100).
Errors
Every error has a type, a stable code, a message and a request_id. Handle codes you don’t recognise gracefully.
Webhooks
Events are signed with X-Aviral-Signature and retried 9 times over about a day. Logs and events are kept 30 days.

Webhook events

  • message.received
  • message.sent
  • message.delivered
  • message.read
  • message.failed
  • conversation.created
  • conversation.assigned
  • conversation.resolved
  • contact.created
  • contact.updated
  • contact.opted_out
  • contact.opted_in
  • campaign.started
  • campaign.completed
  • template.status_changed
  • automation.completed
  • contact_list.members_added
  • contact_list.members_removed
  • campaign.ab_winner_selected
  • drip.enrollment_started
  • drip.enrollment_finished
  • flow.response_received
  • flow.status_changed
  • ad_referral.received
  • conversion.created
  • conversation.sla_breached
  • csat.response_received
  • deal.created
  • deal.updated
  • deal.stage_changed
  • deal.won
  • deal.lost
  • task.created
  • task.updated
  • task.completed
  • order.created
  • order.updated
  • order.status_changed
  • order.cancelled
  • payment.link_created
  • payment.captured
  • payment.failed
  • payment.refunded
  • ai.reply_sent
  • ai.handoff
  • call.ringing
  • call.answered
  • call.ended
  • call.missed
  • voicemail.received
  • call_permission.updated
  • social_comment.received
  • social_comment.replied
  • contact.deleted
  • contact.merged
  • cart.changed

Integrations

Plugins and no-code connectors

Connect your store, forms and workflows without writing code. Every integration uses a workspace API key kept on the server, never in the browser.

  • Plugin

    WordPress and WooCommerce

    Chat button, lead forms that sync to contacts, and order and abandoned-cart notifications by template.

    API key stored in WordPress settings, server-side

    Create a key
  • Plugin

    Shopify

    Forward orders, fulfilments and checkouts to automations and send WhatsApp updates.

    API key pasted in the bridge settings

    Create a key
  • No-code

    Zapier

    Instant triggers for messages, contacts and campaigns; actions to send, upsert and tag.

    API key connection

    Create a key
  • No-code

    Make

    Instant webhooks plus modules for messages, templates, contacts and automations.

    API key connection

    Create a key
  • No-code

    n8n

    Community node with a trigger node and action nodes for self-hosted or cloud n8n.

    API key credential

    Create a key
  • Add-on

    Google Sheets

    Sync rows to contacts, send templates to selected rows and log events into a sheet.

    API key in script properties

    Create a key
  • Embed

    Website chat widget

    A click-to-chat WhatsApp button for any site. One script tag, configured with data attributes.

    No key needed

    Configure widget