Version 1.7 | Last Updated: July 23, 2026
Chatyug API is a RESTful web service that allows you to send WhatsApp messages programmatically from your external software applications. It provides a simple, secure, and reliable way to integrate WhatsApp messaging capabilities into your CRM, ERP, e-commerce platform, or any custom software.
All API responses follow a consistent JSON format:
All API requests require an API key for authentication. The API key is passed in the Authorization header using Bearer token format.
https://chatyug.comAPI keys follow this format:
Each API key is associated with:
ChatYug MCP (v2.1.3) connects an MCP-compatible AI assistant (Claude, ChatGPT, Gemini CLI, and others)
to your Messaging, CRM, Marketing, and Commerce account (~85 tools).
Generate an mcp_ token in portal API Configuration, then use
connector URL https://mcp.chatyug.com/mcp with
Authorization: Bearer mcp_β¦.
Paste the token only in Authorization / Bearer / API key / Request headers β not Name, not the URL, and not OAuth Client ID or Secret. Claude Custom Connector uses Request headers (when available); ChatGPT needs Bearer/API-key auth if offered; Gemini CLI supports a header flag. Trial plans are read-only; Monthly and Annual can send and update Messaging, CRM, Marketing, and Commerce as allowed. Tool catalog: MCP tools. Guide: ChatYug MCP multi-client help Β· usage guidelines.
Sending attached media from Claude.ai
mcp.chatyug.com under Claude Settings β Capabilities β Code execution β Additional allowed domains (required for sandbox upload).prepare_media_upload then curl the original file (or give you a browser upload link if egress stays blocked), then send_media_message.Details: sending media from Claude.
Endpoint: POST https://chatyug.com/api/external/send-message
Description: Send a text, template, or session media (image/video/audio/document) WhatsApp message.
| Header | Value | Required |
|---|---|---|
| Authorization | Bearer YOUR_API_KEY | Yes |
| Content-Type | application/json | Yes |
| Parameter | Type | Required | Description |
|---|---|---|---|
| phoneNumberId | string | Yes | Your WhatsApp phone number ID |
| to | string | Yes | Recipient phone number (with country code, e.g., 919876543210) |
| type | string | Yes | text | template | image | video | audio | document |
| text | string | If type=text | Text message content (also used as caption for media if caption omitted) |
| templateName | string | If type=template | Name of approved WhatsApp template |
| templateLanguage | string | If type=template | Template language code (e.g., "en", "en_US") |
| templateVariables | array | No | Array of variable values for template |
| mediaId | string | For session media* | Meta media ID from POST /messages/upload-media (preferred) |
| mediaUrl | string | For session media* | Public HTTPS media link, or template header media URL |
| caption | string | No | Caption for image/video/document (max 1024) |
| filename | string | No | Filename for document type |
* For image/video/audio/document, provide mediaId or mediaUrl.
type: "text" with mediaUrl expecting a photo β that only delivers text. Use type: "image" (or video/audio/document). Session media requires an open 24-hour window.
Upload first: POST https://chatyug.com/api/external/messages/upload-media (multipart mediaFile + phoneNumberId) β use returned data.mediaId.
Customer photos are downloaded to ChatYug at /received_media/.... Call GET https://chatyug.com/api/external/messages/:messageId/media for a stable absolute URL. Meta lookaside CDN links expire in minutes and cannot be recovered after expiry if only the CDN URL was stored.
Endpoint: GET https://chatyug.com/api/external/delivery-status/:messageId
Description: Check the delivery status of a previously sent message.
| Header | Value | Required |
|---|---|---|
| Authorization | Bearer YOUR_API_KEY | Yes |
| Parameter | Type | Required | Description |
|---|---|---|---|
| messageId | string | Yes | The message ID returned from send-message endpoint |
| Status | Meaning | When It Occurs |
|---|---|---|
| sent | Message sent to WhatsApp | Immediately after sending |
| delivered | Message delivered to phone | When phone receives message |
| read | Message read by recipient | When user opens WhatsApp |
| failed | Message failed to send | If delivery fails |
Send approved media card carousel templates via API. Register templates in the ChatYug portal; use the API to list and send only.
headerMediaId from portal media upload (external upload planned Phase 1b).
Endpoint: POST https://chatyug.com/api/external/messages/upload-media
Auth: Bearer API key. Content-Type: multipart/form-data
| Field | Required | Description |
|---|---|---|
| mediaFile | Yes | Image or video file (field name matches portal; max 15MB) |
| phoneNumberId | Yes | WhatsApp phone number ID for this API key WABA |
| mediaType | No | image (default) or video β local storage subfolder |
Use data.mediaId as cards[].headerMediaId when sending carousel messages.
Endpoint: GET https://chatyug.com/api/external/templates/carousel
Query: status (optional, default APPROVED) β APPROVED, PENDING, REJECTED
Endpoint: GET https://chatyug.com/api/external/templates/carousel/:templateId
Endpoint: POST https://chatyug.com/api/external/messages/carousel
Responses: 200 success; 403 TEMPLATE_NOT_APPROVED; 400 validation; 404 phone/template not found.
Note: Bulk carousel (Phase 2) and scheduled carousel are portal-only. Register/sync/delete templates via portal (Phase 3).
| Code | HTTP | Description |
|---|---|---|
| TEMPLATE_NOT_APPROVED | 403 | Template exists but Status β APPROVED |
| TEMPLATE_NOT_FOUND | 404 | templateId not in this account |
| PHONE_NOT_FOUND | 404 | phoneNumberId not in this account |
| VALIDATION_ERROR | 400 | Invalid cards count, missing fields |
| META_ERROR | 502 | Meta API rejected the request |
| Feature | Portal | External API |
|---|---|---|
| Register template | Yes | Phase 3 |
| Sync Meta status | Yes | Phase 3 |
| Send approved carousel | Yes | Yes (Phase 1) |
| Upload header media | Yes | Yes (Phase 1b) |
| Bulk carousel | Yes | Phase 2 |
| Scheduled carousel | Yes | Not planned |
Note: Create and approve templates in the portal. Bulk carousel (Phase 2) is portal-only at this time.
Manage WhatsApp product catalogs and send catalog messages. Base path: https://chatyug.com/api/external. One API key is scoped to one WABA; catalog data is stored in Meta and mirrored in ChatYug.
POST /catalogs/:id/products, then send product-list or single-product messages inside the 24-hour session, or use carousel templates for marketing outside the session.SHOP. Your integrator app receives inbound webhooks and calls GET /catalogs/:id/categories β POST /messages/interactive β on list_reply, GET /catalogs/:id/product-list-payload?category={slug} β POST /messages/product-list. Assign category on each product in the portal or via the create-product API.Returns active catalogs linked to your WABA.
curl -X GET https://chatyug.com/api/external/catalogs \ -H "Authorization: Bearer YOUR_API_KEY"
{
"success": true,
"total": 1,
"catalogs": [
{
"Catalog_Id": 1,
"Meta_Catalog_Id": "980328057290841",
"Catalog_Name": "My Shop Catalog",
"Product_Count": 45,
"Is_Active": true,
"Created_At": "2025-01-15T10:30:00.000Z"
}
]
}| Field | Required | Description |
|---|---|---|
catalogName | Yes | Display name |
vertical | Yes | commerce or local_service (and other Meta-supported verticals) |
curl -X POST https://chatyug.com/api/external/catalogs \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"catalogName": "My Shop Catalog", "vertical": "commerce"}'Query: page, limit (max 200), search (name/SKU/description), availability (in stock / out of stock), category (category name or slug from GET /categories).
Returns distinct browse categories with product counts. Includes interactiveListSections ready for POST /messages/interactive (category picker). Products without a category are grouped as Uncategorized.
| Query | Description |
|---|---|
inStockOnly | Default true β only count in-stock products |
curl -X GET "https://chatyug.com/api/external/catalogs/980328057290841/categories" \ -H "Authorization: Bearer YOUR_API_KEY"
{
"success": true,
"catalogId": "980328057290841",
"categories": [
{ "name": "Kitchen Appliances", "slug": "cat_kitchen_appliances", "productCount": 5 },
{ "name": "Dairy", "slug": "cat_dairy", "productCount": 3 }
],
"interactiveListSections": [
{
"title": "Categories",
"rows": [
{ "id": "cat_kitchen_appliances", "title": "Kitchen Appliances", "description": "5 products" },
{ "id": "cat_dairy", "title": "Dairy", "description": "3 products" }
]
}
]
}Row id values are category slug strings (e.g. cat_dairy). Pass the slug back as ?category= on product-list-payload when the customer taps a row.
Builds Meta-ready sections and a flat productRetailerIds array dynamically from the catalog β no hardcoded product lists.
| Query | Description |
|---|---|
category | Category slug from GET /categories (e.g. cat_dairy) |
groupByCategory | If true and no category, one section per category (max 30 products total) |
curl -X GET "https://chatyug.com/api/external/catalogs/980328057290841/product-list-payload?category=cat_dairy" \ -H "Authorization: Bearer YOUR_API_KEY"
{
"success": true,
"catalogId": "980328057290841",
"sections": [
{
"title": "Dairy",
"product_items": [
{ "product_retailer_id": "MILK-1L" },
{ "product_retailer_id": "YOGURT-500G" }
]
}
],
"productRetailerIds": ["MILK-1L", "YOGURT-500G"],
"totalProducts": 2,
"truncated": false
}Meta limits: max 30 products per product_list message. If truncated: true, send follow-up messages with remaining retailer IDs.
| Field | Required | Description |
|---|---|---|
productName | Yes | Product title |
price | Yes | Numeric price in INR |
currency | No | Default INR |
retailerId | No | SKU; auto-generated if omitted |
description | No | Product description |
imageUrl | No | Public HTTPS image URL |
availability | No | in stock or out of stock |
category | No | Browse category label (e.g. Dairy) β drives category picker flow |
Partial update β send only fields to change (price, availability, name, etc.).
| Field | Required | Description |
|---|---|---|
phoneNumberId | Yes | WhatsApp phone number ID |
to | Yes | Recipient (e.g. 919876543210 or +91 98765 43210) |
catalogId | Yes | Meta catalog ID |
headerText | No | Message header |
bodyText | Yes | Message body |
sections | One of* | Meta format: [{ title, product_items: [{ product_retailer_id }] }] |
productRetailerIds | One of* | Flat SKU array β single section (legacy / flat browse) |
sectionTitle | No | Title when using productRetailerIds only (default: Products) |
*Either sections[] or productRetailerIds[] is required.
curl -X POST https://chatyug.com/api/external/messages/product-list \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"phoneNumberId": "YOUR_PHONE_NUMBER_ID",
"to": "919876543210",
"catalogId": "980328057290841",
"sections": [{
"title": "Dairy",
"product_items": [
{ "product_retailer_id": "MILK-1L" },
{ "product_retailer_id": "YOGURT-500G" }
]
}],
"bodyText": "Browse Dairy products"
}'SHOP) β your webhook receives eventType: messageGET /catalogs/{metaCatalogId}/categoriesPOST /messages/interactive with interactiveType: "list" and sections from interactiveListSectionsinteractive.list_reply.id = category slug (e.g. cat_dairy)GET /catalogs/{id}/product-list-payload?category={slug}POST /messages/product-list with returned sections or productRetailerIdsSee also docs/INTEGRATOR_WHATSAPP_COMMERCE_REFERENCE.md Β§4.3 for full curl examples and webhook payloads.
| Field | Required | Description |
|---|---|---|
phoneNumberId | Yes | |
to | Yes | |
catalogId | Yes | |
productRetailerId | Yes | SKU from catalog |
bodyText | Yes | Caption text |
| HTTP | When |
|---|---|
| 400 | Validation (missing fields, invalid price) |
| 403 | Catalog not owned by this API key WABA |
| 404 | Catalog or product not found |
| 502 | Meta Graph API error |
WhatsApp Commerce orders (native cart or flow checkout). Orders arrive via the order webhook and are queryable here.
pending β confirmed β shipped β delivered (or cancelled). PUT /orders/:id/status can auto-notify the customer on WhatsApp unless notifyCustomer: false.Query: status, page, pageSize, dateFrom/dateTo (YYYY-MM-DD), dateFromUtc/dateToUtc (ISO).
curl -X GET "https://chatyug.com/api/external/orders?status=pending&page=1&pageSize=20" \ -H "Authorization: Bearer YOUR_API_KEY"
{
"success": true,
"total": 42,
"page": 1,
"pageSize": 20,
"orders": [
{
"id": 101,
"customer_phone": "919876543210",
"customer_name": "Rahul Sharma",
"status": "pending",
"total_amount": "4999.00",
"currency": "INR",
"items_count": 2,
"items": [{ "product_retailer_id": "SKU-001", "quantity": 1, "item_price": "599", "currency": "INR" }]
}
]
}Full order with items, shipping_address, flow_token, timestamps.
| Field | Required | Description |
|---|---|---|
status | Yes | pending | confirmed | shipped | delivered | cancelled |
note | No | Internal note; included in customer notification |
notifyCustomer | No | Default true β sends WhatsApp text update |
{ "success": true, "message": "Order status updated to shipped", "notifySent": true }Body: { "note": "AWB: DTDC123456789" } β internal note only, no status change.
Body: { "message": "Custom WhatsApp text..." } β omit message for default status-based text.
WhatsApp Flows for checkout / customer-details forms. Prefer authoring in the ChatYug portal Flow Design module (drag-and-drop screens, Approve/Publish, Test Send, per-flow Analytics). See the Flow Design Guide and Commerce Flows API & MCP. Flow JSON can also be created via API, published to Meta, then sent to customers.
POST /commerce/flows still accepts a flowJson object (screens, fields) for integrators. Customer submissions arrive on your webhook as message events with interactive.type: "nfm_reply" and are stored as Flow Analytics submit events.List flows for your WABA.
| Field | Required | Description |
|---|---|---|
flowName | Yes | Internal name |
categories | No | e.g. ["OTHER"] |
flowJson | No | WhatsApp Flow JSON (screens, fields). If omitted, a default checkout scaffold may be used |
Publishes draft flow to Meta. Required before sending to customers.
| Field | Required | Description |
|---|---|---|
phoneNumberId | Yes | |
to | Yes | Customer phone |
flowId | Yes | Meta flow ID from create/list |
flowToken | No | Correlation token returned in nfm_reply |
headerText | No | |
bodyText | Yes | |
ctaText | No | Button label (default "Continue") |
curl -X POST https://chatyug.com/api/external/messages/flow \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"phoneNumberId": "YOUR_PHONE_NUMBER_ID",
"to": "919876543210",
"flowId": "META_FLOW_ID",
"bodyText": "Please fill in your delivery details",
"ctaText": "Proceed"
}'{
"success": true,
"message": "Flow message sent",
"data": { "messageId": "wamid.HBgM...", "flowId": "META_FLOW_ID" }
}Pass flowToken on send so you can correlate the later nfm_reply. Portal Conversations show a βFlow sentβ bubble; Analytics records a send event. Full send + receive walkthrough: Commerce Flows β receive filled data.
List send/submit events. Query: flowId (local id), eventType, phone, fromDate, toDate, page, pageSize.
Submit payload / payload_json may include PhotoPicker / DocumentPicker answers. After ChatYug downloads the file from Meta, each media object is enriched with chatyug_url (absolute HTTPS URL under /received_media/β¦) and chatyug_media_type (image|document|video). There is no VideoPicker β video means a DocumentPicker (or similar) whose MIME starts with video/.
{
"photo_75ke": {
"id": "123456789012345",
"mime_type": "image/jpeg",
"file_name": "photo.jpg",
"chatyug_url": "https://chatyug.com/received_media/flow/β¦/image_β¦.jpg",
"chatyug_media_type": "image"
}
}
Download or resolve one media field from a submit event. Auth: API key. Query: format=json returns { url, mimeType, fileName }; otherwise streams or redirects to the stored file. MCP: get_flow_media.
Per-flow send/submit counts.
format=xlsx (default) or json. Same filters as list. Excel cells for media fields prefer the public chatyug_url when present.
Keyword-triggered automation inside ChatYug. Requires automation permission on the WABA. Alternative to building your own keyword engine on inbound webhooks.
message webhooks and your own engine (hybrid architecture).Query: phoneNumberId, published=true, active=true.
| Field | Required | Description |
|---|---|---|
flowName | Yes | |
triggerKeywords | Yes | Comma-separated, e.g. SHOP,CATALOGUE |
flowData | Yes | JSON graph: { nodes: [], edges: [] } |
phoneNumberId | No | Scope to a phone number |
sessionTimeoutMinutes | No | Default session timeout |
Update name, keywords, flowData, isActive.
403 if automation permission not enabled for WABA.
No API key. Use for load-balancer / integration health checks.
GET https://chatyug.com/api/external/test
{ "success": true, "message": "External API is working!", "timestamp": "2026-06-23T10:00:00.000Z" }Validates API key and returns account context. Use in your integration settings screen (wf-17).
curl -X GET https://chatyug.com/api/external/me -H "Authorization: Bearer YOUR_API_KEY"
{
"success": true,
"userId": 9,
"wabaId": "815098678039367",
"businessName": "My Business",
"phoneNumbers": [
{
"Phone_Number_Id": "719142414620783",
"Phone_Number": "919876543210",
"Display_Phone_Number": "+91 98765 43210"
}
]
}Read conversations, send interactive replies, and fetch media β for chat consoles and commerce bots driven by webhooks.
Within 24 hours of the customer's last inbound message. Use for distributor selection, project pickers, COD confirm, etc.
| Field | Required | Description |
|---|---|---|
phoneNumberId | Yes | |
to | Yes | Recipient phone |
interactiveType | Yes | button (1β3 buttons) or list |
bodyText | Yes | Main message (max 1024 chars) |
headerText | No | Max 60 chars |
footerText | No | Max 60 chars |
buttons | If button | [{ id, title }] β id max 256, title max 20 |
listButtonText | If list | Open list label (max 20) |
sections | If list | [{ title, rows: [{ id, title, description? }] }] β max 10 rows per section |
contextMessageId | No | Reply in thread to a specific message |
curl -X POST https://chatyug.com/api/external/messages/interactive \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"phoneNumberId": "YOUR_PHONE_NUMBER_ID",
"to": "919876543210",
"interactiveType": "list",
"bodyText": "Select your distributor",
"listButtonText": "View distributors",
"sections": [{
"title": "Available",
"rows": [
{ "id": "DIST_01", "title": "Distributor A", "description": "North zone" },
{ "id": "DIST_02", "title": "Distributor B", "description": "South zone" }
]
}]
}'{
"success": true,
"message": "Interactive message sent",
"data": {
"messageId": "wamid.HBgM...",
"conversationId": 12345,
"interactiveType": "list"
}
}Customer replies arrive on your webhook as message with interactive.button_reply or interactive.list_reply.
Query: phoneNumberId (required), page, pageSize (max 200), search (phone/name).
{
"success": true,
"page": 1,
"pageSize": 50,
"total": 90,
"conversations": [
{
"Conversation_Id": 12345,
"Customer_Phone": "919876543210",
"Customer_Name": "Rahul",
"Last_Message_Time": "2026-06-23T09:00:00.000Z",
"Unread_Count": 1,
"session": {
"sessionOpen": true,
"lastCustomerMessageAt": "2026-06-23T08:30:00.000Z",
"expiresAt": "2026-06-24T08:30:00.000Z"
}
}
]
}session.sessionOpen, lastCustomerMessageAt, and expiresAt (ISO timestamp). When sessionOpen is false, use template messages via POST /send-message with type: "template".Query: limit (max 500), offset. Returns messages, conversation, session, total.
Returns mediaUrl for messages with attachments. Relative paths (e.g. /received_media/...) are served from your ChatYug host; persist a copy in your system for long-term audit.
{
"success": true,
"messageId": 98765,
"mediaType": "image",
"mediaUrl": "/received_media/919876543210/image_123.jpg",
"direction": "received",
"note": "Relative URLs are served from chatyug.com. Meta-hosted media may require portal download."
}/received_media/ are stored on ChatYug servers and remain available while the message exists in ChatYug. Meta CDN / lookaside URLs expire in minutes β never cache them. Call GET /messages/:messageId/media; if only a Meta media ID is stored, ChatYug downloads and persists the file on demand.| HTTP | Meaning |
|---|---|
| 400 | Missing/invalid body (e.g. wrong button count, missing phoneNumberId) |
| 401 | Invalid or missing API key |
| 403 | Phone number not in this WABA |
| 404 | Conversation or message not found |
| 502 | Meta rejected interactive/flow send (session closed, policy, etc.) |
List approved WhatsApp message templates (non-carousel) registered in ChatYug, including variable placeholders for POST /send-message. Carousel templates use GET /templates/carousel (Β§3.3).
Query: status (APPROVED default; PENDING, REJECTED, ALL), search, category, language
curl -X GET "https://chatyug.com/api/external/templates?status=APPROVED" \ -H "Authorization: Bearer YOUR_API_KEY"
{
"success": true,
"total": 2,
"statistics": { "total": 2, "approved": 2, "pending": 0, "rejected": 0 },
"templates": [
{
"templateId": 42,
"templateName": "order_confirmation",
"language": "en",
"category": "UTILITY",
"status": "APPROVED",
"bodyText": "Hello {{1}}, your order {{2}} is confirmed for {{3}}.",
"headerText": null,
"footerText": "Thank you for shopping with us",
"mediaType": "None",
"variableCount": 3,
"variables": [
{ "index": 1, "component": "body", "placeholder": "{{1}}", "example": "Rahul", "type": "text" },
{ "index": 2, "component": "body", "placeholder": "{{2}}", "example": "ORD-12345", "type": "text" },
{ "index": 3, "component": "body", "placeholder": "{{3}}", "example": "βΉ1,299", "type": "text" }
],
"buttons": [],
"sampleSendRequest": {
"phoneNumberId": "YOUR_PHONE_NUMBER_ID",
"to": "919876543210",
"type": "template",
"templateName": "order_confirmation",
"templateLanguage": "en",
"templateVariables": ["Rahul", "ORD-12345", "βΉ1,299"]
}
}
],
"usage": {
"sendEndpoint": "POST /api/external/send-message",
"note": "Pass templateVariables as array in {{1}}, {{2}} order"
}
}curl -X GET https://chatyug.com/api/external/templates/42 -H "Authorization: Bearer YOUR_API_KEY"
Returns template (full detail + components) and sendMessageExample ready to POST.
GET /templates?status=APPROVED β populate template picker in your portalvariables array for form fieldstemplateVariables array from user input in placeholder orderPOST /send-message with type: "template", templateName, templateLanguagestatus webhook or GET /delivery-status/:messageIdtemplateVariables accepts an array ["Rahul", "ORD-123"] or object {"1":"Rahul","2":"ORD-123"}. Values map to {{1}}, {{2}} in template body/header. Templates with media headers require mediaUrl on send-message.| HTTP | Code | When |
|---|---|---|
| 404 | TEMPLATE_NOT_FOUND | templateId not in your WABA |
| 400 | β | Invalid templateId |
Schedule template-based WhatsApp sends from your CRM, ERP, or custom platform. Requires API key + automation permission on the WABA for write endpoints.
curl -X POST https://chatyug.com/api/external/scheduled-messages \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"phoneNumberId":"YOUR_PHONE_NUMBER_ID","scheduleName":"Monday promo","scheduleType":"ONE_TIME","templateName":"order_update","templateLanguage":"en","scheduledDate":"2026-07-25","scheduledTime":"10:30","timezone":"Asia/Kolkata","recipients":[{"phoneNumber":"919876543210","variables":{"1":"Rahul","2":"ORD-991"}}]}'Also: GET /scheduled-messages, GET /scheduled-messages/:id, GET /scheduled-messages/:id/report, DELETE /scheduled-messages/:id, POST /scheduled-messages/upload-csv, POST /scheduled-messages/:id/run-now.
Create and submit templates to Meta via API. Always returns PENDING. Requires automation permission.
curl -X POST https://chatyug.com/api/external/templates \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"templateName":"order_update_api","templateContent":"Hi {{1}}, your order {{2}} is confirmed.","category":"UTILITY","language":"en"}'GET /templates/:templateId/status, POST /templates/:templateId/sync, POST /templates/carousel.
REST (Representational State Transfer) is an architectural style for designing web services. Our API follows REST principles, making it easy to understand and integrate.
Here's the complete flow of how your software integrates with Chatyug API:
WhatsApp doesn't provide a "check status" API endpoint. Instead, status updates are delivered automatically via webhooks - this is how WhatsApp designed their system.
Configure your HTTPS webhook in ChatYug portal β API Configuration β Webhook Settings. ChatYug POSTs JSON events to your URL. This is the primary way to receive inbound customer messages, button/list replies, Flow submissions, delivery receipts, and cart orders.
| Aspect | Behaviour |
|---|---|
| Method | HTTP POST, Content-Type: application/json |
| Headers | X-Chatyug-Event-Id (idempotency key), X-Chatyug-Signature (if secret configured) |
| Retries | Automatic for up to 48 hours; backoff ~1, 2, 10, 60, 360 minutes (~12β13 attempts) |
| Rate limit | ~300 events/minute per WABA |
| Acknowledgement | Return HTTP 2xx quickly; process async in your app |
X-Chatyug-Signature is HMAC-SHA256 of the raw JSON request body (UTF-8), prefixed with sha256=, using the secret from Webhook Settings. There is no separate timestamp header β use eventId for idempotency. Verify before parsing if possible (read raw body first).
const crypto = require('crypto');
function verifyChatyugSignature(rawBody, secret, signatureHeader) {
if (!secret || !signatureHeader) return false;
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(rawBody, 'utf8')
.digest('hex');
try {
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signatureHeader));
} catch { return false; }
}
// Express: use express.raw({ type: 'application/json' }) on webhook routeEvery outbound webhook uses this top-level shape:
{
"eventType": "message | status | order | test",
"userId": 34,
"wabaId": "1957290828491918",
"phoneNumberId": "1079034885291122",
"eventId": "unique-id-for-idempotency",
"occurredAt": "2026-06-23T10:10:00.000Z",
"data": { }
}{
"eventType": "message",
"userId": 34,
"wabaId": "1957290828491918",
"phoneNumberId": "1079034885291122",
"eventId": "wamid.HBgMOTE5ODc2NTQzMjEw...",
"occurredAt": "2026-06-23T10:10:00.000Z",
"data": {
"metadata": { "phone_number_id": "1079034885291122", "display_phone_number": "919876543210" },
"contacts": [{ "profile": { "name": "Rahul" }, "wa_id": "919876543210" }],
"message": {
"from": "919876543210",
"id": "wamid.HBgM...",
"timestamp": "1719156600",
"type": "text",
"text": { "body": "SHOP" }
}
}
}{
"eventType": "message",
"data": {
"message": {
"type": "image",
"image": { "id": "META_MEDIA_ID", "mime_type": "image/jpeg", "caption": "Invoice" }
}
}
}Fetch stored file URL via GET /messages/:messageId/media after correlating with ChatYug message ID, or download from Meta using your own media pipeline.
{
"eventType": "message",
"data": {
"message": {
"type": "interactive",
"interactive": {
"type": "button_reply",
"button_reply": { "id": "DIST_01", "title": "Distributor A" }
}
}
}
}{
"eventType": "message",
"data": {
"message": {
"type": "interactive",
"interactive": {
"type": "list_reply",
"list_reply": { "id": "PROJ_12", "title": "Project Alpha", "description": "Phase 2" }
}
}
}
}{
"eventType": "message",
"data": {
"from": "919876543210",
"message": {
"type": "interactive",
"interactive": {
"type": "nfm_reply",
"nfm_reply": {
"name": "flow",
"body": "Sent",
"response_json": "{\"flow_token\":\"lead_42_checkout\",\"customer_name\":\"Rahul\",\"city\":\"Bharuch\",\"mobile_number\":\"9876543210\"}"
}
}
}
}
}response_json is a JSON string. Parse it; keys match Flow Design field names. Correlate with the flowToken you set on POST /messages/flow (appears as flow_token). Same payload is visible in Conversations as a Flow response bubble and in Flow Analytics as a submit event. See also receive filled data.
const answers = JSON.parse(payload.data.message.interactive.nfm_reply.response_json || '{}');
const token = answers.flow_token;
const name = answers.customer_name;{
"eventType": "status",
"eventId": "wamid.HBgM...",
"data": {
"status": {
"id": "wamid.HBgM...",
"status": "delivered",
"timestamp": "1719156600",
"recipient_id": "919876543210",
"conversation": { "id": "...", "origin": { "type": "business_initiated" } }
}
}
}Values: sent, delivered, read, failed. Alternative: poll GET /delivery-status/:messageId.
{
"eventType": "order",
"data": {
"metadata": { "phone_number_id": "1079034885291122" },
"contacts": [{ "wa_id": "919876543210" }],
"order": {
"catalog_id": "980328057290841",
"text": "Order note from customer",
"product_items": [
{
"product_retailer_id": "SKU-001",
"quantity": 2,
"item_price": 599,
"currency": "INR"
}
]
}
}
}Also creates/updates a record queryable via GET /orders.
Sent from Webhook Settings "Send test event". Use to validate URL, TLS, and signature handling.
X-Chatyug-SignatureeventId not already processedeventType β update your DB / trigger bot logic200 OK within a few secondsWhen: Customer places an order in your e-commerce system
Action: Send template message with order details
When: Support ticket is resolved
Action: Send text message asking for feedback
When: Invoice is due in 3 days
Action: Send template message with payment link
Here's how to structure your CRM integration:
This example shows how to integrate Chatyug API in a Node.js application. Perfect for server-side applications, web backends, or Node.js-based systems.
// ============================================
// CHATYUG API INTEGRATION - NODE.JS EXAMPLE
// ============================================
// Step 1: Import required library
const axios = require('axios');
// Step 2: Configure API credentials
// Replace these with your actual values from Chatyug Portal
const API_BASE_URL = 'https://chatyug.com/api';
const API_KEY = 'ck_your_api_key_here'; // Get this from API Configuration page
const PHONE_NUMBER_ID = '719142414620783'; // Your WhatsApp Business Phone Number ID
// ============================================
// FUNCTION: Send WhatsApp Message
// ============================================
/**
* Sends a WhatsApp message (text, template, or session media) to a recipient
* @param {string} to - Recipient phone number (with country code, no + sign)
* @param {string} messageType - 'text' | 'template' | 'image' | 'video' | 'audio' | 'document'
* @param {object} content - Message content (text string or template object)
* @returns {Promise<string>} - Message ID from WhatsApp
*/
async function sendWhatsAppMessage(to, messageType, content) {
try {
// Step 1: Prepare the request URL
const url = `${API_BASE_URL}/external/send-message`;
// Step 2: Build request body based on message type
const requestBody = {
phoneNumberId: PHONE_NUMBER_ID, // Your WhatsApp phone number ID
to: to, // Recipient phone number
type: messageType // 'text' | 'template' | 'image' | 'video' | 'audio' | 'document'
};
// Step 3: Add message-specific fields
if (messageType === 'text') {
// For text messages, add the text content
requestBody.text = content;
} else {
// For template messages, add template details
requestBody.templateName = content.templateName;
requestBody.templateLanguage = content.templateLanguage;
requestBody.templateVariables = content.templateVariables || [];
}
// Step 4: Make HTTP POST request with authentication
const response = await axios.post(url, requestBody, {
headers: {
'Authorization': `Bearer ${API_KEY}`, // API key authentication
'Content-Type': 'application/json' // JSON content type
}
});
// Step 5: Check if request was successful
if (response.data.success) {
console.log('β
Message sent successfully!');
console.log('Message ID:', response.data.data.messageId);
console.log('Status:', response.data.data.status);
// Return the message ID for tracking
return response.data.data.messageId;
} else {
throw new Error('API returned success=false: ' + response.data.message);
}
} catch (error) {
// Handle errors gracefully
if (error.response) {
// API returned an error response
console.error('β API Error:', error.response.status);
console.error('Error details:', error.response.data);
} else if (error.request) {
// Request was made but no response received
console.error('β Network Error: No response from server');
} else {
// Something else happened
console.error('β Error:', error.message);
}
throw error; // Re-throw to allow caller to handle
}
}
// ============================================
// FUNCTION: Check Delivery Status
// ============================================
/**
* Checks the delivery status of a previously sent message
* @param {string} messageId - The message ID returned from sendWhatsAppMessage
* @returns {Promise<object>} - Status information (status, deliveredAt, readAt, etc.)
*/
async function checkDeliveryStatus(messageId) {
try {
// Step 1: Prepare the request URL with message ID
// Note: messageId must be URL-encoded for safety
const url = `${API_BASE_URL}/external/delivery-status/${encodeURIComponent(messageId)}`;
// Step 2: Make HTTP GET request with authentication
const response = await axios.get(url, {
headers: {
'Authorization': `Bearer ${API_KEY}`
}
});
// Step 3: Return the status data
return response.data.data;
} catch (error) {
// Handle errors
if (error.response && error.response.status === 404) {
console.error('β Message not found. It may not have been saved yet.');
} else {
console.error('β Error checking status:', error.message);
}
throw error;
}
}
// ============================================
// USAGE EXAMPLES
// ============================================
// Example 1: Send a Text Message
async function exampleSendTextMessage() {
try {
const messageId = await sendWhatsAppMessage(
'919876543210', // Recipient phone number (India: 91 + 9876543210)
'text', // Message type
'Hello! This is a test message from my CRM system.' // Message text
);
console.log('Text message sent with ID:', messageId);
// Wait a few seconds for delivery, then check status
setTimeout(async () => {
const status = await checkDeliveryStatus(messageId);
console.log('Delivery status:', status.status);
console.log('Delivered at:', status.deliveredAt);
}, 5000);
} catch (error) {
console.error('Failed to send text message:', error.message);
}
}
// Example 2: Send a Template Message
async function exampleSendTemplateMessage() {
try {
const messageId = await sendWhatsAppMessage(
'919876543210', // Recipient phone number
'template', // Message type
{
templateName: 'order_confirmation', // Your approved template name
templateLanguage: 'en', // Template language code
templateVariables: [ // Variables to fill in template
'John Doe', // Customer name
'ORD-12345', // Order number
'βΉ1,299' // Order amount
]
}
);
console.log('Template message sent with ID:', messageId);
// Check status after a delay
setTimeout(async () => {
const status = await checkDeliveryStatus(messageId);
console.log('Message Status:', status.status);
if (status.readAt) {
console.log('Message was read at:', status.readAt);
}
}, 10000);
} catch (error) {
console.error('Failed to send template message:', error.message);
}
}
// Example 3: Send Message from CRM Event (Order Placed)
async function onOrderPlaced(order) {
try {
// Send order confirmation via WhatsApp
const messageId = await sendWhatsAppMessage(
order.customerPhone.replace(/[^0-9]/g, ''), // Remove any formatting
'template',
{
templateName: 'order_confirmation',
templateLanguage: 'en',
templateVariables: [
order.customerName,
order.orderNumber,
order.totalAmount
]
}
);
// Store message ID in your database for tracking
console.log(`Order confirmation sent to ${order.customerName}: ${messageId}`);
return messageId;
} catch (error) {
console.error('Failed to send order confirmation:', error);
// Log error but don't fail the order process
}
}
// Run example (uncomment to test)
// exampleSendTextMessage();
// exampleSendTemplateMessage();process.env.CHATYUG_API_KEYThis example shows how to integrate Chatyug API in a PHP application. Perfect for WordPress plugins, Laravel applications, or any PHP-based system.
<?php
// ============================================
// CHATYUG API INTEGRATION - PHP EXAMPLE
// ============================================
// Step 1: Configure API credentials
$apiBaseUrl = 'https://chatyug.com/api';
$apiKey = 'ck_your_api_key_here';
$phoneNumberId = '719142414620783';
// ============================================
// FUNCTION: Send WhatsApp Message
// ============================================
function sendWhatsAppMessage($to, $messageType, $content) {
global $apiBaseUrl, $apiKey, $phoneNumberId;
$url = $apiBaseUrl . '/external/send-message';
$data = [
'phoneNumberId' => $phoneNumberId,
'to' => $to,
'type' => $messageType
];
if ($messageType === 'text') {
$data['text'] = $content;
} else {
$data['templateName'] = $content['templateName'];
$data['templateLanguage'] = $content['templateLanguage'];
$data['templateVariables'] = $content['templateVariables'] ?? [];
}
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json'
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 200) {
$result = json_decode($response, true);
return $result['data']['messageId'];
} else {
throw new Exception('Failed: ' . $response);
}
}
// Step 3: Check Delivery Status Function
function checkDeliveryStatus($messageId) {
global $apiBaseUrl, $apiKey;
$url = $apiBaseUrl . '/external/delivery-status/' . urlencode($messageId);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $apiKey
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 200) {
return json_decode($response, true)['data'];
} else {
throw new Exception('Failed: ' . $response);
}
}
?><?php
// Example 1: Send Text Message
try {
$messageId = sendWhatsAppMessage(
'919876543210',
'text',
'Hello! This is a test message.'
);
echo "Message sent: " . $messageId . "\n";
} catch (Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
}
// Example 2: Send Template Message
try {
$messageId = sendWhatsAppMessage(
'919876543210',
'template',
[
'templateName' => 'order_confirmation',
'templateLanguage' => 'en',
'templateVariables' => ['John Doe', 'ORD-12345', 'βΉ1,299']
]
);
echo "Message sent: " . $messageId . "\n";
sleep(5);
$status = checkDeliveryStatus($messageId);
echo "Status: " . $status['status'] . "\n";
} catch (Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
}
?>This example shows how to integrate Chatyug API in a Python application. Perfect for Django, Flask, or any Python-based system.
# ============================================
# CHATYUG API INTEGRATION - PYTHON EXAMPLE
# ============================================
import requests
import time
# Step 1: Configure API credentials
API_BASE_URL = 'https://chatyug.com/api'
API_KEY = 'ck_your_api_key_here'
PHONE_NUMBER_ID = '719142414620783'
# Step 2: Send WhatsApp Message Function
def send_whatsapp_message(to, message_type, content):
"""
Sends a WhatsApp message (text or template) to a recipient
Args:
to: Recipient phone number (with country code)
message_type: 'text' or 'template'
content: Message content (text string or template dict)
Returns:
str: Message ID from WhatsApp
"""
url = f"{API_BASE_URL}/external/send-message"
headers = {
'Authorization': f'Bearer {API_KEY}',
'Content-Type': 'application/json'
}
data = {
'phoneNumberId': PHONE_NUMBER_ID,
'to': to,
'type': message_type
}
if message_type == 'text':
data['text'] = content
else:
data['templateName'] = content['templateName']
data['templateLanguage'] = content['templateLanguage']
data['templateVariables'] = content.get('templateVariables', [])
response = requests.post(url, json=data, headers=headers)
response.raise_for_status()
result = response.json()
if result.get('success'):
print(f"β
Message sent! ID: {result['data']['messageId']}")
return result['data']['messageId']
else:
raise Exception(f"API error: {result.get('message', 'Unknown error')}")
# Step 3: Check Delivery Status Function
def check_delivery_status(message_id):
"""
Checks the delivery status of a previously sent message
Args:
message_id: The message ID returned from send_whatsapp_message
Returns:
dict: Status information
"""
url = f"{API_BASE_URL}/external/delivery-status/{requests.utils.quote(message_id)}"
headers = {
'Authorization': f'Bearer {API_KEY}'
}
response = requests.get(url, headers=headers)
response.raise_for_status()
result = response.json()
return result['data']
# Step 4: Usage Examples
if __name__ == '__main__':
# Example 1: Send Text Message
try:
message_id = send_whatsapp_message(
'919876543210',
'text',
'Hello! This is a test message from Python.'
)
print(f"Text message sent: {message_id}")
except Exception as e:
print(f"β Error: {e}")
# Example 2: Send Template Message
try:
message_id = send_whatsapp_message(
'919876543210',
'template',
{
'templateName': 'order_confirmation',
'templateLanguage': 'en',
'templateVariables': ['John Doe', 'ORD-12345', 'βΉ1,299']
}
)
print(f"Template message sent: {message_id}")
time.sleep(5)
status = check_delivery_status(message_id)
print(f"Status: {status['status']}")
except Exception as e:
print(f"β Error: {e}")This example shows how to integrate Chatyug API in a C# / .NET application.
using System;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
// ============================================
// CHATYUG API INTEGRATION - C# EXAMPLE
// ============================================
public class ChatyugAPI
{
// Step 1: Define API configuration
private readonly string apiBaseUrl = "https://chatyug.com/api";
private readonly string apiKey = "ck_your_api_key_here";
private readonly string phoneNumberId = "719142414620783";
private readonly HttpClient httpClient;
// Step 2: Initialize HttpClient with authentication
public ChatyugAPI()
{
httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {apiKey}");
}
// ============================================
// METHOD: Send WhatsApp Message
// ============================================
public async Task<string> SendWhatsAppMessage(string to, string messageType, object content)
{
// Step 1: Build the API endpoint URL
var url = $"{apiBaseUrl}/external/send-message";
// Step 2: Create request payload
var data = new
{
phoneNumberId = phoneNumberId,
to = to,
type = messageType,
text = messageType == "text" ? content : null,
templateName = messageType == "template" ? ((dynamic)content).templateName : null,
templateLanguage = messageType == "template" ? ((dynamic)content).templateLanguage : null,
templateVariables = messageType == "template" ? ((dynamic)content).templateVariables : null
};
// Step 3: Serialize to JSON and create HTTP content
var json = JsonSerializer.Serialize(data);
var httpContent = new StringContent(json, Encoding.UTF8, "application/json");
// Step 4: Send POST request
var response = await httpClient.PostAsync(url, httpContent);
response.EnsureSuccessStatusCode();
// Step 5: Parse response and extract message ID
var responseBody = await response.Content.ReadAsStringAsync();
var result = JsonSerializer.Deserialize<JsonElement>(responseBody);
return result.GetProperty("data").GetProperty("messageId").GetString();
}
// ============================================
// METHOD: Check Delivery Status
// ============================================
public async Task<object> CheckDeliveryStatus(string messageId)
{
// Step 1: Build the API endpoint URL with message ID
var url = $"{apiBaseUrl}/external/delivery-status/{Uri.EscapeDataString(messageId)}";
// Step 2: Send GET request
var response = await httpClient.GetAsync(url);
response.EnsureSuccessStatusCode();
// Step 3: Parse response
var responseBody = await response.Content.ReadAsStringAsync();
var result = JsonSerializer.Deserialize<JsonElement>(responseBody);
return result.GetProperty("data");
}
}
// ============================================
// USAGE EXAMPLE
// ============================================
class Program
{
static async Task Main(string[] args)
{
// Step 1: Create API instance
var api = new ChatyugAPI();
try
{
// Step 2: Send a template message
var messageId = await api.SendWhatsAppMessage(
"919876543210", // Recipient phone number
"template", // Message type
new // Template content
{
templateName = "order_confirmation",
templateLanguage = "en",
templateVariables = new[] { "John Doe", "ORD-12345", "βΉ1,299" }
}
);
Console.WriteLine($"β
Message sent: {messageId}");
// Step 3: Wait a few seconds for delivery
await Task.Delay(5000);
// Step 4: Check delivery status
var status = await api.CheckDeliveryStatus(messageId);
Console.WriteLine($"π Status: {status}");
}
catch (Exception ex)
{
Console.WriteLine($"β Error: {ex.Message}");
}
}
}This example shows how to integrate Chatyug API in a Flutter/Dart mobile application.
# Add to pubspec.yaml
dependencies:
http: ^1.1.0
dart:convert// ============================================
// CHATYUG API INTEGRATION - DART/FLUTTER EXAMPLE
// ============================================
import 'dart:convert';
import 'package:http/http.dart' as http;
class ChatyugAPI {
// Step 1: Configure API credentials
static const String apiBaseUrl = 'https://chatyug.com/api';
final String apiKey;
final String phoneNumberId;
ChatyugAPI({
required this.apiKey,
required this.phoneNumberId,
});
// ============================================
// METHOD: Send WhatsApp Message
// ============================================
/// Sends a WhatsApp message (text or template) to a recipient
/// Returns the message ID from WhatsApp
Future<String> sendWhatsAppMessage({
required String to,
required String messageType,
required dynamic content,
}) async {
try {
// Step 1: Build the API endpoint URL
final url = Uri.parse('$apiBaseUrl/external/send-message');
// Step 2: Create request payload
final Map<String, dynamic> data = {
'phoneNumberId': phoneNumberId,
'to': to,
'type': messageType,
};
// Step 3: Add message-specific fields
if (messageType == 'text') {
data['text'] = content;
} else {
data['templateName'] = content['templateName'];
data['templateLanguage'] = content['templateLanguage'];
data['templateVariables'] = content['templateVariables'] ?? [];
}
// Step 4: Send POST request with authentication
final response = await http.post(
url,
headers: {
'Authorization': 'Bearer $apiKey',
'Content-Type': 'application/json',
},
body: jsonEncode(data),
);
// Step 5: Check response status
if (response.statusCode == 200) {
final result = jsonDecode(response.body);
if (result['success'] == true) {
print('β
Message sent successfully!');
print('Message ID: ${result['data']['messageId']}');
return result['data']['messageId'];
} else {
throw Exception('API error: ${result['message']}');
}
} else {
throw Exception('HTTP ${response.statusCode}: ${response.body}');
}
} catch (e) {
print('β Error sending message: $e');
rethrow;
}
}
// ============================================
// METHOD: Check Delivery Status
// ============================================
/// Checks the delivery status of a previously sent message
Future<Map<String, dynamic>> checkDeliveryStatus(String messageId) async {
try {
// Step 1: Build the API endpoint URL with message ID
final encodedMessageId = Uri.encodeComponent(messageId);
final url = Uri.parse('$apiBaseUrl/external/delivery-status/$encodedMessageId');
// Step 2: Send GET request with authentication
final response = await http.get(
url,
headers: {
'Authorization': 'Bearer $apiKey',
},
);
// Step 3: Parse and return response
if (response.statusCode == 200) {
final result = jsonDecode(response.body);
return result['data'];
} else {
throw Exception('HTTP ${response.statusCode}: ${response.body}');
}
} catch (e) {
print('β Error checking status: $e');
rethrow;
}
}
}
// ============================================
// USAGE EXAMPLE
// ============================================
void main() async {
final api = ChatyugAPI(
apiKey: 'ck_your_api_key_here',
phoneNumberId: '719142414620783',
);
try {
// Send a template message
final messageId = await api.sendWhatsAppMessage(
to: '919876543210',
messageType: 'template',
content: {
'templateName': 'order_confirmation',
'templateLanguage': 'en',
'templateVariables': ['John Doe', 'ORD-12345', 'βΉ1,299'],
},
);
print('β
Message sent: $messageId');
// Wait a few seconds, then check status
await Future.delayed(Duration(seconds: 5));
final status = await api.checkDeliveryStatus(messageId);
print('π Status: ${status['status']}');
} catch (e) {
print('β Error: $e');
}
}This example shows how to integrate Chatyug API in an Android application using Kotlin.
// Add to build.gradle (Module: app)
dependencies {
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
implementation 'com.google.code.gson:gson:2.10.1'
}// ============================================
// CHATYUG API INTEGRATION - KOTLIN EXAMPLE
// ============================================
import com.google.gson.Gson
import okhttp3.*
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.toRequestBody
import java.io.IOException
class ChatyugAPI(
private val apiKey: String,
private val phoneNumberId: String
) {
// Step 1: Configure API base URL
private val apiBaseUrl = "https://chatyug.com/api"
private val client = OkHttpClient()
private val gson = Gson()
private val jsonMediaType = "application/json; charset=utf-8".toMediaType()
// ============================================
// METHOD: Send WhatsApp Message
// ============================================
/**
* Sends a WhatsApp message (text or template) to a recipient
* @param to Recipient phone number
* @param messageType "text" or "template"
* @param content Message content (String for text, Map for template)
* @return Message ID from WhatsApp
*/
suspend fun sendWhatsAppMessage(
to: String,
messageType: String,
content: Any
): String {
try {
// Step 1: Build the API endpoint URL
val url = "$apiBaseUrl/external/send-message"
// Step 2: Create request payload
val data = mutableMapOf<String, Any>(
"phoneNumberId" to phoneNumberId,
"to" to to,
"type" to messageType
)
// Step 3: Add message-specific fields
if (messageType == "text") {
data["text"] = content as String
} else {
val templateContent = content as Map<String, Any>
data["templateName"] = templateContent["templateName"] as String
data["templateLanguage"] = templateContent["templateLanguage"] as String
data["templateVariables"] = templateContent["templateVariables"] ?: emptyList<String>()
}
// Step 4: Create request body
val jsonBody = gson.toJson(data)
val requestBody = jsonBody.toRequestBody(jsonMediaType)
// Step 5: Build request with authentication
val request = Request.Builder()
.url(url)
.post(requestBody)
.addHeader("Authorization", "Bearer $apiKey")
.addHeader("Content-Type", "application/json")
.build()
// Step 6: Execute request
client.newCall(request).execute().use { response ->
if (response.isSuccessful) {
val result = gson.fromJson(response.body?.string(), Map::class.java)
if (result["success"] == true) {
val data = result["data"] as Map<*, *>
println("β
Message sent: ${data["messageId"]}")
return data["messageId"] as String
} else {
throw IOException("API error: ${result["message"]}")
}
} else {
throw IOException("HTTP ${response.code}: ${response.message}")
}
}
} catch (e: Exception) {
println("β Error sending message: ${e.message}")
throw e
}
}
// ============================================
// METHOD: Check Delivery Status
// ============================================
/**
* Checks the delivery status of a previously sent message
* @param messageId The message ID returned from sendWhatsAppMessage
* @return Status information map
*/
suspend fun checkDeliveryStatus(messageId: String): Map<String, Any> {
try {
// Step 1: Build the API endpoint URL with message ID
val encodedMessageId = java.net.URLEncoder.encode(messageId, "UTF-8")
val url = "$apiBaseUrl/external/delivery-status/$encodedMessageId"
// Step 2: Build request with authentication
val request = Request.Builder()
.url(url)
.get()
.addHeader("Authorization", "Bearer $apiKey")
.build()
// Step 3: Execute request
client.newCall(request).execute().use { response ->
if (response.isSuccessful) {
val result = gson.fromJson(response.body?.string(), Map::class.java)
return result["data"] as Map<String, Any>
} else {
throw IOException("HTTP ${response.code}: ${response.message}")
}
}
} catch (e: Exception) {
println("β Error checking status: ${e.message}")
throw e
}
}
}
// ============================================
// USAGE EXAMPLE (in a CoroutineScope)
// ============================================
/*
import kotlinx.coroutines.*
fun main() = runBlocking {
val api = ChatyugAPI(
apiKey = "ck_your_api_key_here",
phoneNumberId = "719142414620783"
)
try {
// Send a template message
val messageId = api.sendWhatsAppMessage(
to = "919876543210",
messageType = "template",
content = mapOf(
"templateName" to "order_confirmation",
"templateLanguage" to "en",
"templateVariables" to listOf("John Doe", "ORD-12345", "βΉ1,299")
)
)
println("β
Message sent: $messageId")
// Wait a few seconds, then check status
delay(5000)
val status = api.checkDeliveryStatus(messageId)
println("π Status: ${status["status"]}")
} catch (e: Exception) {
println("β Error: ${e.message}")
}
}
*/This example shows how to integrate Chatyug API in an Android application using Java.
// Add to build.gradle (Module: app)
dependencies {
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
implementation 'com.google.code.gson:gson:2.10.1'
}// ============================================
// CHATYUG API INTEGRATION - JAVA EXAMPLE
// ============================================
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import okhttp3.*;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class ChatyugAPI {
// Step 1: Configure API credentials
private final String apiBaseUrl = "https://chatyug.com/api";
private final String apiKey;
private final String phoneNumberId;
private final OkHttpClient client;
private final Gson gson;
private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
public ChatyugAPI(String apiKey, String phoneNumberId) {
this.apiKey = apiKey;
this.phoneNumberId = phoneNumberId;
this.client = new OkHttpClient();
this.gson = new Gson();
}
// ============================================
// METHOD: Send WhatsApp Message
// ============================================
/**
* Sends a WhatsApp message (text or template) to a recipient
* @param to Recipient phone number
* @param messageType "text" or "template"
* @param content Message content (String for text, Map for template)
* @return Message ID from WhatsApp
*/
public String sendWhatsAppMessage(String to, String messageType, Object content) throws IOException {
try {
// Step 1: Build the API endpoint URL
String url = apiBaseUrl + "/external/send-message";
// Step 2: Create request payload
Map<String, Object> data = new HashMap<>();
data.put("phoneNumberId", phoneNumberId);
data.put("to", to);
data.put("type", messageType);
// Step 3: Add message-specific fields
if ("text".equals(messageType)) {
data.put("text", content);
} else {
@SuppressWarnings("unchecked")
Map<String, Object> templateContent = (Map<String, Object>) content;
data.put("templateName", templateContent.get("templateName"));
data.put("templateLanguage", templateContent.get("templateLanguage"));
data.put("templateVariables", templateContent.getOrDefault("templateVariables", new java.util.ArrayList<>()));
}
// Step 4: Create request body
String jsonBody = gson.toJson(data);
RequestBody requestBody = RequestBody.create(jsonBody, JSON);
// Step 5: Build request with authentication
Request request = new Request.Builder()
.url(url)
.post(requestBody)
.addHeader("Authorization", "Bearer " + apiKey)
.addHeader("Content-Type", "application/json")
.build();
// Step 6: Execute request
try (Response response = client.newCall(request).execute()) {
if (response.isSuccessful()) {
String responseBody = response.body().string();
JsonObject result = gson.fromJson(responseBody, JsonObject.class);
if (result.get("success").getAsBoolean()) {
JsonObject dataObj = result.getAsJsonObject("data");
String messageId = dataObj.get("messageId").getAsString();
System.out.println("β
Message sent: " + messageId);
return messageId;
} else {
throw new IOException("API error: " + result.get("message").getAsString());
}
} else {
throw new IOException("HTTP " + response.code() + ": " + response.message());
}
}
} catch (Exception e) {
System.err.println("β Error sending message: " + e.getMessage());
throw e;
}
}
// ============================================
// METHOD: Check Delivery Status
// ============================================
/**
* Checks the delivery status of a previously sent message
* @param messageId The message ID returned from sendWhatsAppMessage
* @return Status information as JsonObject
*/
public JsonObject checkDeliveryStatus(String messageId) throws IOException {
try {
// Step 1: Build the API endpoint URL with message ID
String encodedMessageId = java.net.URLEncoder.encode(messageId, "UTF-8");
String url = apiBaseUrl + "/external/delivery-status/" + encodedMessageId;
// Step 2: Build request with authentication
Request request = new Request.Builder()
.url(url)
.get()
.addHeader("Authorization", "Bearer " + apiKey)
.build();
// Step 3: Execute request
try (Response response = client.newCall(request).execute()) {
if (response.isSuccessful()) {
String responseBody = response.body().string();
JsonObject result = gson.fromJson(responseBody, JsonObject.class);
return result.getAsJsonObject("data");
} else {
throw new IOException("HTTP " + response.code() + ": " + response.message());
}
}
} catch (Exception e) {
System.err.println("β Error checking status: " + e.getMessage());
throw e;
}
}
}
// ============================================
// USAGE EXAMPLE
// ============================================
/*
public class Main {
public static void main(String[] args) {
ChatyugAPI api = new ChatyugAPI(
"ck_your_api_key_here",
"719142414620783"
);
try {
// Prepare template content
Map<String, Object> templateContent = new HashMap<>();
templateContent.put("templateName", "order_confirmation");
templateContent.put("templateLanguage", "en");
templateContent.put("templateVariables", java.util.Arrays.asList(
"John Doe", "ORD-12345", "βΉ1,299"
));
// Send a template message
String messageId = api.sendWhatsAppMessage(
"919876543210",
"template",
templateContent
);
System.out.println("β
Message sent: " + messageId);
// Wait a few seconds, then check status
Thread.sleep(5000);
JsonObject status = api.checkDeliveryStatus(messageId);
System.out.println("π Status: " + status.get("status").getAsString());
} catch (Exception e) {
System.err.println("β Error: " + e.getMessage());
}
}
}
*/This example shows how to integrate Chatyug API in an iOS application using Swift.
Swift's built-in URLSession is sufficient for making HTTP requests.
// ============================================
// CHATYUG API INTEGRATION - SWIFT EXAMPLE
// ============================================
import Foundation
class ChatyugAPI {
// Step 1: Configure API credentials
private let apiBaseUrl = "https://chatyug.com/api"
private let apiKey: String
private let phoneNumberId: String
init(apiKey: String, phoneNumberId: String) {
self.apiKey = apiKey
self.phoneNumberId = phoneNumberId
}
// ============================================
// METHOD: Send WhatsApp Message
// ============================================
/// Sends a WhatsApp message (text or template) to a recipient
/// - Parameters:
/// - to: Recipient phone number
/// - messageType: "text" or "template"
/// - content: Message content (String for text, Dictionary for template)
/// - Returns: Message ID from WhatsApp
func sendWhatsAppMessage(
to: String,
messageType: String,
content: Any
) async throws -> String {
// Step 1: Build the API endpoint URL
guard let url = URL(string: "(apiBaseUrl)/external/send-message") else {
throw NSError(domain: "Invalid URL", code: -1)
}
// Step 2: Create request payload
var data: [String: Any] = [
"phoneNumberId": phoneNumberId,
"to": to,
"type": messageType
]
// Step 3: Add message-specific fields
if messageType == "text" {
data["text"] = content as? String
} else if let templateContent = content as? [String: Any] {
data["templateName"] = templateContent["templateName"]
data["templateLanguage"] = templateContent["templateLanguage"]
data["templateVariables"] = templateContent["templateVariables"] ?? []
}
// Step 4: Convert to JSON
let jsonData = try JSONSerialization.data(withJSONObject: data)
// Step 5: Create request with authentication
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("Bearer (apiKey)", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = jsonData
// Step 6: Execute request
let (responseData, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse else {
throw NSError(domain: "Invalid response", code: -1)
}
if httpResponse.statusCode == 200 {
if let result = try JSONSerialization.jsonObject(with: responseData) as? [String: Any],
let success = result["success"] as? Bool, success == true,
let data = result["data"] as? [String: Any],
let messageId = data["messageId"] as? String {
print("β
Message sent: (messageId)")
return messageId
} else {
throw NSError(domain: "API error", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid response format"])
}
} else {
throw NSError(domain: "HTTP Error", code: httpResponse.statusCode, userInfo: [NSLocalizedDescriptionKey: "HTTP (httpResponse.statusCode)"])
}
}
// ============================================
// METHOD: Check Delivery Status
// ============================================
/// Checks the delivery status of a previously sent message
/// - Parameter messageId: The message ID returned from sendWhatsAppMessage
/// - Returns: Status information as Dictionary
func checkDeliveryStatus(messageId: String) async throws -> [String: Any] {
// Step 1: Build the API endpoint URL with message ID
guard let encodedMessageId = messageId.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed),
let url = URL(string: "(apiBaseUrl)/external/delivery-status/(encodedMessageId)") else {
throw NSError(domain: "Invalid URL", code: -1)
}
// Step 2: Create request with authentication
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("Bearer (apiKey)", forHTTPHeaderField: "Authorization")
// Step 3: Execute request
let (responseData, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse else {
throw NSError(domain: "Invalid response", code: -1)
}
if httpResponse.statusCode == 200 {
if let result = try JSONSerialization.jsonObject(with: responseData) as? [String: Any],
let data = result["data"] as? [String: Any] {
return data
} else {
throw NSError(domain: "Invalid response format", code: -1)
}
} else {
throw NSError(domain: "HTTP Error", code: httpResponse.statusCode, userInfo: [NSLocalizedDescriptionKey: "HTTP (httpResponse.statusCode)"])
}
}
}
// ============================================
// USAGE EXAMPLE
// ============================================
/*
Task {
let api = ChatyugAPI(
apiKey: "ck_your_api_key_here",
phoneNumberId: "719142414620783"
)
do {
// Send a template message
let messageId = try await api.sendWhatsAppMessage(
to: "919876543210",
messageType: "template",
content: [
"templateName": "order_confirmation",
"templateLanguage": "en",
"templateVariables": ["John Doe", "ORD-12345", "βΉ1,299"]
]
)
print("β
Message sent: (messageId)")
// Wait a few seconds, then check status
try await Task.sleep(nanoseconds: 5_000_000_000) // 5 seconds
let status = try await api.checkDeliveryStatus(messageId: messageId)
print("π Status: (status["status"] ?? "unknown")")
} catch {
print("β Error: (error.localizedDescription)")
}
}
*/Always implement proper error handling in your integration:
Cause: Invalid or missing API key
Solution:
Bearer ck_...Cause: Message wasn't saved to database or messageId is incorrect
Solution:
Cause: Template name is incorrect or template not approved
Solution:
Possible Causes:
Solution: Check delivery status endpoint for error details
Use the diagnostic endpoint to troubleshoot issues:
This endpoint provides:
If you're still experiencing issues:
API Base URL: https://chatyug.com/api
Documentation Version: 1.3
Last Updated: July 23, 2026