Developers

Connect your website, store or CRM to AsysConnect

A REST API with API keys, and webhooks that tell your system the moment a customer replies, a lead comes in or a deal moves.

1. Get an API key

The workspace owner or an admin signs in to AsysConnect, opens Settings → Developers, and makes a key with only the permissions your connection needs (for example “Add and change contacts” and “Reply in chats”). The key is shown once; store it on your server, never in a web page or a mobile app.

Send it on every request as Authorization: Bearer ask_live_… (or X-API-Key: ask_live_…). A key acts as the teammate who made it and never has more than their role allows. It stops working when it is revoked, when it expires, or when that teammate leaves the workspace. Check a key with:

curl https://app.example.com/v1/api-key \
  -H "Authorization: Bearer ask_live_YOUR_KEY"

The answer names the workspace and lists what the key can do right now.

2. Make your first calls

Add a contact when someone orders or signs up on your website. Phone numbers without a country code are read as Indian numbers.

curl https://app.example.com/v1/contacts \
  -H "Authorization: Bearer ask_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-10452-contact" \
  -d '{
    "first_name": "Priya",
    "last_name": "Shah",
    "channels": [{ "type": "phone", "value": "+91 98765 43210" }],
    "source": "website"
  }'

If the phone number is already a contact you get 409 CONTACT_CHANNEL_TAKEN; find it with GET /v1/contacts?q=9876543210 and update it with PATCH /v1/contacts/{id}.

Send an approved WhatsApp template, such as an order confirmation, to a phone number. List your templates and their variables with GET /v1/whatsapp/templates. Templates are charged to the workspace’s prepaid wallet and refunded if they fail. Within 24 hours of the customer’s last message you can also send plain text with {"type": "text", "text": "…"}.

curl https://app.example.com/v1/messages \
  -H "Authorization: Bearer ask_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-10452-confirmation" \
  -d '{
    "type": "template",
    "to": "+919876543210",
    "template_id": "TEMPLATE_ID_FROM_GET_/v1/whatsapp/templates",
    "params": { "body": ["Priya", "#10452", "₹2,499"] }
  }'

The API reference covers the rest: chats and replies, tags and custom fields, SMS through DLT, email, broadcasts, deals and tasks, and posts to Facebook and Instagram.

3. Limits, errors and retries

  • Each key can make 300 requests a minute. Over that you get 429 with a Retry-After header in seconds.
  • Add an Idempotency-Key header (any unique text, such as your order number) to a POST so it is safe to send again after a timeout: a repeat within 24 hours returns the first answer instead of sending a second message.
  • Errors look like {"error": {"code": "…", "message": "…", "request_id": "…"}}. Act on the code, show the message, and quote the request_id if you contact support.

4. Webhooks

Add your address under Settings → Developers → Webhooks (or with POST /v1/webhook-endpoints) and pick the events you want. The address must be public and use https. AsysConnect posts each event as JSON:

POST /your/webhook/address
X-AsysSuite-Event: message.received
X-AsysSuite-Delivery: 01a0e7c2-…
X-AsysSuite-Signature: t=1760000000,v1=5f2b…

{
  "id": "01a0e7c2-…",
  "type": "message.received",
  "created_at": "2026-09-28T10:15:02.114Z",
  "workspace_id": "01a0d9…",
  "data": {
    "id": "01a0e7c1-…",
    "channel": "whatsapp",
    "direction": "inbound",
    "type": "text",
    "text": "Is the blue kurta in stock?",
    "contact": { "id": "01a0…", "first_name": "Priya", "phones": ["+919876543210"], "tags": ["VIP"] }
  }
}
EventWhen
message.receivedA customer sent a message on WhatsApp, Instagram or Messenger
message.sentYour team, an automation or the AI sent a message in a chat
message.statusA sent message was delivered, read or failed
contact.createdA contact was added
contact.updatedA contact’s name, phone, email, tags, fields, stage or owner changed
contact.deletedA contact was deleted (only the id is sent)
lead.receivedA Facebook or Instagram Lead Ads form came in
deal.createdA deal was added to a pipeline
deal.stage_changedA deal moved stage, including won and lost

Answer with any 2xx within 10 seconds, and do slow work afterwards. Anything else is tried again after 1 minute, 5 minutes, 30 minutes, 2, 6 and 12 hours; after that the delivery shows as failed in the delivery log, where it can be resent. An address that fails every delivery for 3 days is turned off. Events can arrive more than once and out of order, so use the event id to skip repeats and created_at to order them.

5. Check a webhook’s signature

Each webhook address has its own secret (whsec_…), shown when you add it. Compute HMAC-SHA256 of t, a dot, and the raw body with that secret, compare it with v1 in constant time, and refuse times more than five minutes old.

PHP (WordPress, WooCommerce, Laravel)

<?php
$secret = getenv('ASYSSUITE_WEBHOOK_SECRET'); // whsec_...
$body = file_get_contents('php://input');      // the raw body, before json_decode
$header = $_SERVER['HTTP_X_ASYSSUITE_SIGNATURE'] ?? '';

parse_str(str_replace(',', '&', $header), $sig); // ['t' => ..., 'v1' => ...]
$expected = hash_hmac('sha256', ($sig['t'] ?? '') . '.' . $body, $secret);

if (!isset($sig['v1']) || !hash_equals($expected, $sig['v1'])
    || abs(time() - (int) $sig['t']) > 300) {
    http_response_code(400);
    exit;
}

$event = json_decode($body, true);
// Skip events you've already handled: $event['id'] is the same on retries.
http_response_code(200); // answer quickly; do slow work after

Node.js

import crypto from 'node:crypto';
import express from 'express';

const app = express();
const secret = process.env.ASYSSUITE_WEBHOOK_SECRET; // whsec_...

app.post('/asyssuite/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const body = req.body.toString('utf8');
  const sig = Object.fromEntries(
    String(req.get('X-AsysSuite-Signature')).split(',').map((p) => p.split('=')),
  );
  const expected = crypto.createHmac('sha256', secret).update(`${sig.t}.${body}`).digest('hex');
  const ok =
    sig.v1?.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(sig.v1), Buffer.from(expected)) &&
    Math.abs(Date.now() / 1000 - Number(sig.t)) <= 300;
  if (!ok) return res.sendStatus(400);

  const event = JSON.parse(body);
  res.sendStatus(200); // answer first, then handle event.type
});

6. Build an app for many workspaces

If you make a product that many AsysConnect customers will use (a WordPress plugin, a CRM, a shop platform), don’t ask each one to copy a key. Use Connect with AsysConnect: the customer clicks a button in your app, sees what your app wants on an AsysConnect approval screen, approves, and your app gets its own key for their workspace. It works like “Sign in with Google” (OAuth 2.0 authorization code), so standard OAuth libraries work.

  1. Ask us to register your app. Tell us its name, your company, the address customers return to after approving (https), and what it needs (for example “See contacts” and “Reply in chats”). You get a client id (asa_…) and, for apps that run on your server, a client secret (ass_…). Keep the secret on your server.
  2. Send the workspace owner’s browser to the approval screen, with a random state you saved in their session:
    https://app.example.com/connect?client_id=asa_YOUR_CLIENT_ID
      &redirect_uri=https://app.example.com/asysconnect/callback
      &scope=contacts.read contacts.write conversations.read
      &state=RANDOM_VALUE_YOU_SAVED
    scope lists what you need, separated by spaces, and can only include what your app was registered for. The owner or an admin must approve; they sign in first if needed.
  3. AsysConnect sends the browser back to your address with ?code=…&state=… (or ?error=access_denied if they said no). Check state matches, then trade the code for a key within 10 minutes. A code works once.
    curl https://app.example.com/v1/oauth/token \
      -u "asa_YOUR_CLIENT_ID:ass_YOUR_CLIENT_SECRET" \
      -d grant_type=authorization_code \
      -d code=THE_CODE \
      -d redirect_uri=https://app.example.com/asysconnect/callback
    {
      "access_token": "ask_live_...",
      "token_type": "Bearer",
      "scope": "contacts.read contacts.write conversations.read",
      "workspace": { "id": "…", "name": "Shah Textiles" }
    }
  4. Use access_token like any API key, and store it per workspace. It keeps working until the customer disconnects your app under Settings → Developers, the teammate who approved leaves, or AsysConnect turns your app off; then calls return 401 and you should ask them to connect again. Approving again replaces the old key.

Apps without a server (plugins installed by each customer)

A WordPress or other self-hosted plugin can’t keep a secret, because every customer has a copy. Register it as a public app: it gets no secret and must use PKCE instead. Make a random verifier, send its SHA-256 as code_challenge with code_challenge_method=S256, and send the verifier when trading the code. Since each site has its own address, register one return page on your own website that sends the browser on to the customer’s site, or ask us to register the addresses you need.

// Before sending the owner to /connect:
$verifier  = rtrim(strtr(base64_encode(random_bytes(32)), '+/', '-_'), '=');
$challenge = rtrim(strtr(base64_encode(hash('sha256', $verifier, true)), '+/', '-_'), '=');
update_option('asyssuite_pkce', $verifier);
// Add to the /connect link: &code_challenge=$challenge&code_challenge_method=S256

// On the return address, trade the code (no client secret):
$res = wp_remote_post('https://app.example.com/v1/oauth/token', ['body' => [
  'grant_type'    => 'authorization_code',
  'code'          => $_GET['code'],
  'redirect_uri'  => $redirect_uri,
  'client_id'     => 'asa_YOUR_CLIENT_ID',
  'code_verifier' => get_option('asyssuite_pkce'),
]]);

Questions? Get in touch.