Chatensy API
Version 1.1.0 · Base URL https://chatensy.in · OpenAPI 3.1 JSON
Authentication
Create a key in Integrations → API and send it as a bearer token. Keys belong to one workspace. A key stops working when revoked, and the workspace's IP allow-list applies to the API too.
Authorization: Bearer tsc_live_…
Rate limits & errors
120 requests per minute per key. Every response has X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (Unix time). Over the limit you get 429 with Retry-After.
Errors are JSON: {"error": "…", "code": "…", "fields": {…}}. 4xx means fix the request; 5xx and 429 are safe to retry with back-off. WhatsApp's own pricing applies to every message and is billed by Meta to your account.
Webhooks
Subscribe with POST /api/v1/webhooks or in Integrations. We send POST with JSON {"event", "data", "created_at"} and the headers X-Event and X-Signature — the hex HMAC-SHA256 of the raw body using your subscription secret. Reply 2xx within 10 seconds; failures are retried, and 10 in a row pause the endpoint.
$body = file_get_contents('php://input');
$ok = hash_equals(hash_hmac('sha256', $body, $secret), $_SERVER['HTTP_X_SIGNATURE'] ?? '');
const sig = crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
const ok = crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(req.get('X-Signature') || ''));
sig = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
ok = hmac.compare_digest(sig, request.headers.get("X-Signature", ""))
Events (14)
{
"event": "message.received",
"data": {
"contact_id": "01a17c00-0000-7000-8000-000000000001",
"phone": "+919876543210",
"bsuid": null,
"name": "Aarav Mehta",
"type": "text",
"text": "Is the linen shirt available in XL?",
"wamid": "wamid.HBgMOTE5ODc2NTQzMjEwFQIAEhgg"
},
"created_at": "2026-10-26T10:15:00+00:00"
}{
"event": "message.status",
"data": {
"wamid": "wamid.HBgMOTE5ODc2NTQzMjEwFQIAERgS",
"status": "read",
"error": null
},
"created_at": "2026-10-26T10:15:00+00:00"
}{
"event": "contact.opted_in",
"data": {
"contact_id": "01a17c00-0000-7000-8000-000000000001",
"phone": "+919876543210",
"bsuid": null
},
"created_at": "2026-10-26T10:15:00+00:00"
}{
"event": "contact.opted_out",
"data": {
"contact_id": "01a17c00-0000-7000-8000-000000000001",
"phone": "+919876543210",
"bsuid": null
},
"created_at": "2026-10-26T10:15:00+00:00"
}{
"event": "conversation.assigned",
"data": {
"conversation_id": "01a17c00-0000-7000-8000-0000000000c1",
"user_id": "01a17c00-0000-7000-8000-0000000000a1"
},
"created_at": "2026-10-26T10:15:00+00:00"
}{
"event": "order.cod_confirmed",
"data": {
"order_ref": "5551234567",
"contact_id": "01a17c00-0000-7000-8000-000000000001"
},
"created_at": "2026-10-26T10:15:00+00:00"
}{
"event": "order.cod_cancelled",
"data": {
"order_ref": "5551234567",
"contact_id": "01a17c00-0000-7000-8000-000000000001"
},
"created_at": "2026-10-26T10:15:00+00:00"
}{
"event": "campaign.finished",
"data": {
"campaign_id": "01a17c00-0000-7000-8000-0000000000d1",
"name": "Diwali sale",
"sent": 4820,
"delivered": 4710,
"read": 3902,
"failed": 110
},
"created_at": "2026-10-26T10:15:00+00:00"
}{
"event": "conversation.sla_breached",
"data": {
"conversation_id": "01a17c00-0000-7000-8000-0000000000c1"
},
"created_at": "2026-10-26T10:15:00+00:00"
}{
"event": "conversation.rated",
"data": {
"conversation_id": "01a17c00-0000-7000-8000-0000000000c1",
"rating": 5
},
"created_at": "2026-10-26T10:15:00+00:00"
}{
"event": "message.sent_from_app",
"data": {
"contact_id": "01a17c00-0000-7000-8000-000000000001",
"phone": "+919876543210",
"type": "text",
"wamid": "wamid.HBgMOTE5ODc2NTQzMjEwFQIAERgT"
},
"created_at": "2026-10-26T10:15:00+00:00"
}{
"event": "order.prepaid",
"data": {
"order_ref": "5551234567",
"order_number": "#1042",
"amount": 1499,
"contact_id": "01a17c00-0000-7000-8000-000000000001"
},
"created_at": "2026-10-26T10:15:00+00:00"
}{
"event": "flow.completed",
"data": {
"flow_id": "01a17c00-0000-7000-8000-0000000000f1",
"flow_name": "Lead form",
"contact_id": "01a17c00-0000-7000-8000-000000000001",
"phone": "+919876543210",
"answers": {
"name": "Riya Kapoor",
"email": "riya@example.com",
"interest": "Bulk / wholesale"
}
},
"created_at": "2026-10-26T10:15:00+00:00"
}{
"event": "payment.paid",
"data": {
"contact_id": "01a17c00-0000-7000-8000-000000000001",
"phone": "+919876543210",
"bsuid": null,
"payment_id": "01a17c00-0000-7000-8000-0000000000e1",
"amount": 1499,
"currency": "INR",
"provider": "razorpay",
"reference": "pay_Nx12abc345",
"description": "Linen shirt, size L"
},
"created_at": "2026-10-26T10:15:00+00:00"
}SDKs & apps
Official clients wrap every endpoint and verify webhook signatures. They live in the sdks/ folder of the product repository.
$api = new TrisparkConnect\Client('tsc_live_…', 'https://chatensy.in');
$api->messages->sendTemplate('+919876543210', 'order_update', ['Aarav', '#1042']);const { Client } = require('trispark-connect');
const api = new Client({ apiKey: 'tsc_live_…', baseUrl: 'https://chatensy.in' });
await api.messages.sendTemplate({ to: '+919876543210', template: 'order_update', values: ['Aarav'] });from trispark_connect import Client
api = Client("tsc_live_…", base_url="https://chatensy.in")
api.messages.send_template("+919876543210", "order_update", ["Aarav", "#1042"])No-code: the Zapier app (integrations/zapier) and the n8n community node (integrations/n8n) offer triggers for every event and actions for messages, contacts, tags and journeys.
Account
GET /api/v1/me
Check your key. Returns the workspace, WhatsApp number and key name. Use it to test a connection.
Responses
- 200 Who this key belongs to
- 401 Bad or missing key
- 429 Rate limited
curl -X GET "https://chatensy.in/api/v1/me" \
-H "Authorization: Bearer $API_KEY"
Sandbox
POST /api/v1/sandbox/inbound
Receive a message as a customer (sandbox only). Acts as a customer writing to your sandbox number, so your webhooks and inbox see a real inbound message. Only works with a key made inside a sandbox workspace (Developers → Sandbox).
Body
| from required | string |
| text required | string |
| name | string |
Responses
- 201 Received
- 403 Not a sandbox workspace
- 422 Validation failed
- 401 Bad or missing key
- 429 Rate limited
curl -X POST "https://chatensy.in/api/v1/sandbox/inbound" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"from":"+15550100001","text":"Where is my order?","name":"Asha"}'
POST /api/v1/sandbox/status
Change a sent message's status (sandbox only). Moves a message you sent to delivered, read or failed, as Meta would, so your status webhooks fire. Only works in a sandbox workspace.
Body
| message_id required | string (uuid) |
| status required | string · delivered | read | failed |
Responses
- 200 Done
- 403 Not a sandbox workspace
- 404 No such sent message
- 422 Validation failed
- 401 Bad or missing key
- 429 Rate limited
curl -X POST "https://chatensy.in/api/v1/sandbox/status" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"message_id":"","status":"delivered"}'
Messages
POST /api/v1/messages/template
Send a template message. Sends an approved template. Starts a conversation even when the 24-hour window is closed. Marketing templates need the contact's opt-in.
Body
| to required | string Recipient phone, international format |
| template required | string Template name |
| language | string Language code; defaults to the contact's language version when approved |
| values | string[] Values for {{1}}, {{2}}… |
| header_media_url | string (uri) Image/video/document URL for media-header templates |
Responses
- 201 Sent
- 403 Not opted in or over the plan quota
- 404 Template not found or not approved
- 409 No connected WhatsApp number
- 422 Validation failed
- 502 WhatsApp rejected the message
- 401 Bad or missing key
- 429 Rate limited
curl -X POST "https://chatensy.in/api/v1/messages/template" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"to":"+919876543210","template":"order_update","language":"en","values":["Aarav","#1042"],"header_media_url":""}'
POST /api/v1/messages/text
Send a text message. Free-form text. Works only inside the 24-hour window after the customer last wrote to you.
Body
| to required | string |
| text required | string |
Responses
- 201 Sent
- 409 Window closed or the contact never messaged you
- 422 Validation failed
- 502 WhatsApp rejected the message
- 401 Bad or missing key
- 429 Rate limited
curl -X POST "https://chatensy.in/api/v1/messages/text" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"to":"+919876543210","text":"Your order is out for delivery 🚚"}'
GET /api/v1/messages
List recent messages. Newest first. Handy for polling; prefer webhooks for real-time.
Parameters
| direction | query · string · in | out in = from customers, out = sent by you |
| since | query · string (date-time) Only messages at or after this time |
| limit | query · integer |
Responses
- 200 Messages
- 422 Bad since value
- 401 Bad or missing key
- 429 Rate limited
curl -X GET "https://chatensy.in/api/v1/messages" \
-H "Authorization: Bearer $API_KEY"
Contacts
GET /api/v1/contacts
List contacts. Newest first.
Parameters
| tag | query · string Only contacts with this tag |
| since | query · string (date-time) Only contacts created at or after this time |
| page | query · integer |
| per_page | query · integer |
Responses
- 200 Contacts
- 422 Bad since value
- 401 Bad or missing key
- 429 Rate limited
curl -X GET "https://chatensy.in/api/v1/contacts" \
-H "Authorization: Bearer $API_KEY"
POST /api/v1/contacts
Create or update a contact. Matched by phone. Tags are replaced; attributes are merged.
Body
| phone required | string |
| name | string |
| string (email) | |
| city | string |
| language | string |
| tags | string[] |
| attributes | object |
| opt_in | boolean Marketing consent you collected |
| opt_in_source | string |
Responses
- 200 The contact
- 422 Validation failed
- 401 Bad or missing key
- 429 Rate limited
curl -X POST "https://chatensy.in/api/v1/contacts" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"phone":"+919876543210","name":"Aarav Mehta","email":"","city":"","language":"hi","tags":["VIP"],"attributes":{"last_order":"#1042"},"opt_in":true,"opt_in_source":"checkout_checkbox"}'
GET /api/v1/contacts/{phone}
Get a contact.
Parameters
| phone required | path · string Phone number in international format, digits only or with +, e.g. 919876543210 |
Responses
- 200 The contact
- 404 Not found
- 401 Bad or missing key
- 429 Rate limited
curl -X GET "https://chatensy.in/api/v1/contacts/{phone}" \
-H "Authorization: Bearer $API_KEY"
POST /api/v1/contacts/{phone}/tags
Add tags to a contact. Adding a tag can start journeys triggered by "tag added".
Parameters
| phone required | path · string Phone number in international format, digits only or with +, e.g. 919876543210 |
Body
| tags required | string[] |
Responses
- 200 The contact
- 404 Not found
- 422 No tags sent
- 401 Bad or missing key
- 429 Rate limited
curl -X POST "https://chatensy.in/api/v1/contacts/{phone}/tags" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"tags":["Lead"]}'
DELETE /api/v1/contacts/{phone}/tags/{tag}
Remove a tag from a contact.
Parameters
| phone required | path · string Phone number in international format, digits only or with +, e.g. 919876543210 |
| tag required | path · string |
Responses
- 200 The contact
- 404 Not found
- 401 Bad or missing key
- 429 Rate limited
curl -X DELETE "https://chatensy.in/api/v1/contacts/{phone}/tags/{tag}" \
-H "Authorization: Bearer $API_KEY"
Templates
GET /api/v1/templates
List templates.
Responses
- 200 Templates
- 401 Bad or missing key
- 429 Rate limited
curl -X GET "https://chatensy.in/api/v1/templates" \
-H "Authorization: Bearer $API_KEY"
Journeys
GET /api/v1/journeys
List journeys.
Responses
- 200 Journeys
- 401 Bad or missing key
- 429 Rate limited
curl -X GET "https://chatensy.in/api/v1/journeys" \
-H "Authorization: Bearer $API_KEY"
POST /api/v1/journeys/{id}/enroll
Add a contact to a journey. Creates the contact if needed. A contact is in each journey once; opted-out contacts are skipped.
Parameters
| id required | path · string (uuid) |
Body
| phone required | string |
| context | object Values steps can use, e.g. order_number |
Responses
- 201 Enrolled
- 200 Not enrolled (already in it, or opted out)
- 403 Journeys need the Growth plan
- 404 Journey not found
- 409 Journey is not active
- 422 Validation failed
- 401 Bad or missing key
- 429 Rate limited
curl -X POST "https://chatensy.in/api/v1/journeys/{id}/enroll" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"phone":"+919876543210","context":{"order_number":"#1042"}}'
Store events
POST /api/v1/events
Send a store event. Triggers store automations and journeys (cart reminders, order updates, COD confirmation) from any shop platform.
Body
| event required | string · cart.abandoned | order.created | order.paid | order.shipped | order.delivered | order.cancelled |
| phone required | string |
| customer_name | string |
| order_id | string |
| order_number | string |
| order_total | number |
| payment_method | string · cod | prepaid |
| checkout_url | string (uri) |
| tracking_url | string (uri) |
| items | object[] |
| marketing_opt_in | boolean |
Responses
- 202 Accepted
- 422 Unknown event
- 401 Bad or missing key
- 429 Rate limited
curl -X POST "https://chatensy.in/api/v1/events" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"event":"cart.abandoned","phone":"+919876543210","customer_name":"Aarav Mehta","order_id":"5551234567","order_number":"#1042","order_total":1499,"payment_method":"cod","checkout_url":"","tracking_url":"","items":[{"title":"","quantity":0}],"marketing_opt_in":true}'
Webhooks
GET /api/v1/webhooks
List webhook subscriptions.
Responses
- 200 Subscriptions
- 401 Bad or missing key
- 429 Rate limited
curl -X GET "https://chatensy.in/api/v1/webhooks" \
-H "Authorization: Bearer $API_KEY"
POST /api/v1/webhooks
Subscribe to events. We POST `{event, data, created_at}` to your HTTPS URL, signed: `X-Signature` is the hex HMAC-SHA256 of the raw body with the returned secret. Revoking the API key removes subscriptions it made.
Body
| url required | string (uri) |
| events required | EventName[] |
| source | string · api | zapier | n8n |
Responses
- 201 Subscribed (the secret is only returned here)
- 403 Webhooks need the Growth plan
- 422 Bad URL or event
- 401 Bad or missing key
- 429 Rate limited
curl -X POST "https://chatensy.in/api/v1/webhooks" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://hooks.example.com/whatsapp","events":["message.received"],"source":"api"}'
DELETE /api/v1/webhooks/{id}
Unsubscribe.
Parameters
| id required | path · string (uuid) |
Responses
- 200 Deleted
- 404 Not found
- 401 Bad or missing key
- 429 Rate limited
curl -X DELETE "https://chatensy.in/api/v1/webhooks/{id}" \
-H "Authorization: Bearer $API_KEY"
GET /api/v1/webhooks/events
Event types with sample payloads.
Responses
- 200 Events
- 401 Bad or missing key
- 429 Rate limited
curl -X GET "https://chatensy.in/api/v1/webhooks/events" \
-H "Authorization: Bearer $API_KEY"