Version 1.7 | Last Updated: September 28, 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:
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.
:catalogId accepts the Meta Catalog ID or the ChatYug internal Catalog_Id.productName, price, imageUrl, productUrl. Optional = retailerId, currency, description, availability, category, brand, inventory. Address / lat / long are not required and are ignored for Meta.LOCALITY_REQUIRED if missing.imageUrl on create/update, or upload a JPEG/PNG/WebP file via POST /catalogs/upload-image and use the returned imageUrl. Meta requires a crawlable public URL (max 5MB).category field). GET /categories aggregates distinct labels. Manage via assign / rename / clear endpoints, or set category on create/update. Empty categories are unsupported (a label appears only after at least one product uses it).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.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 (recommended), generic, local_service_businesses, offline_commerce, or 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).
curl -X GET "https://chatyug.com/api/external/catalogs/980328057290841/products?page=1&limit=50" \ -H "Authorization: Bearer YOUR_API_KEY"
{
"success": true,
"products": [
{
"Product_Id": 101,
"Product_Name": "Premium Cotton T-Shirt",
"Retailer_ID": "TSHIRT-WHITE-M",
"Price": 599.00,
"Currency": "INR",
"Image_URL": "https://example.com/tshirt.jpg",
"Product_URL": "https://example.com/products/tshirt",
"Availability": "in stock",
"Category": "Apparel",
"Brand": "MyBrand",
"Inventory": 150,
"sale_price": 499.00
}
],
"pagination": { "page": 1, "limit": 50, "total": 1, "pages": 1 }
}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.
Set the category label on one or more SKUs. Empty categories are not supported β assign to products so they appear in GET /categories.
| Field | Required | Description |
|---|---|---|
name | Yes | Category label (e.g. Dairy) |
retailerIds | Yes | Array of product SKUs |
curl -X POST https://chatyug.com/api/external/catalogs/980328057290841/categories/assign \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "Dairy", "retailerIds": ["MILK-1L", "YOGURT-500G"] }'Bulk-rename a label across all products. Cannot rename Uncategorized.
curl -X PUT https://chatyug.com/api/external/catalogs/980328057290841/categories \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "from": "Dairy", "to": "Milk & Yogurt" }'Clears Category on matching products (they become Uncategorized in GET). Path may be a slug (cat_dairy) or URL-encoded name.
curl -X DELETE https://chatyug.com/api/external/catalogs/980328057290841/categories/cat_dairy \ -H "Authorization: Bearer YOUR_API_KEY"
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.
Multipart upload (field name image). JPEG, PNG, or WebP β max 5MB. Returns a public HTTPS imageUrl for create/update. You may also pass any existing public CDN URL as imageUrl without uploading.
curl -X POST https://chatyug.com/api/external/catalogs/upload-image \ -H "Authorization: Bearer YOUR_API_KEY" \ -F "image=@/path/to/product.jpg"
{
"success": true,
"message": "Image uploaded successfully",
"data": {
"imageUrl": "https://chatyug.com/uploads/product-images/product-1720856400000-123.jpg",
"imagePath": "/uploads/product-images/product-1720856400000-123.jpg",
"filename": "product-1720856400000-123.jpg",
"size": 84210,
"mimeType": "image/jpeg"
}
}| Field | Required | Description |
|---|---|---|
productName | Yes | Product title |
price | Yes | Numeric price in major units (e.g. 599 for βΉ599) |
currency | No | Default INR |
retailerId | No | SKU; auto-generated if omitted |
description | No | Product description |
imageUrl | Yes | Public HTTPS image URL (required for Meta). Upload via POST /catalogs/upload-image or use your CDN |
productUrl | Yes | Full http(s) product/shop URL β Meta link under WhatsApp description (never ChatYug.com default) |
availability | No | in stock or out of stock |
category | No | Browse category label (e.g. Dairy) β drives category picker flow |
brand | No | Brand name (optional for Meta) |
inventory | No | Stock count integer (optional) |
Locality (only when catalog vertical is local_service_businesses or offline_commerce): provide a full address (availabilityAddressStreet, City, State, PostalCode, Country), or availabilityLatitude+availabilityLongitude, or postal code alone. Not required for commerce catalogs.
curl -X POST https://chatyug.com/api/external/catalogs/980328057290841/products \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"productName": "Premium Cotton T-Shirt",
"description": "100% cotton, comfortable fit",
"price": 599,
"currency": "INR",
"retailerId": "TSHIRT-WHITE-M",
"imageUrl": "https://example.com/tshirt.jpg",
"productUrl": "https://example.com/products/tshirt",
"availability": "in stock",
"category": "Apparel",
"brand": "MyBrand",
"inventory": 150
}'{
"success": true,
"message": "Product created successfully",
"data": {
"productId": 101,
"metaProductId": "5678901234567",
"retailerId": "TSHIRT-WHITE-M",
"productName": "Premium Cotton T-Shirt",
"price": 599,
"currency": "INR"
}
}Partial update β send only fields to change. Same body fields as create (all optional).
curl -X PUT https://chatyug.com/api/external/catalogs/980328057290841/products/TSHIRT-WHITE-M \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "price": 499, "availability": "in stock", "inventory": 200 }'Deletes the product from Meta and ChatYug by SKU (retailerId). If Meta delete fails, ChatYug still removes the local row and may return metaWarning.
curl -X DELETE https://chatyug.com/api/external/catalogs/980328057290841/products/TSHIRT-WHITE-M \ -H "Authorization: Bearer YOUR_API_KEY"
{ "success": true, "message": "Product deleted successfully", "data": { "productId": 101, "retailerId": "TSHIRT-WHITE-M" } }Returns sale / coupon / auto offers for the catalogue (scoped to your API key WABA).
curl -X GET https://chatyug.com/api/external/catalogs/980328057290841/offers \ -H "Authorization: Bearer YOUR_API_KEY"
{
"success": true,
"offers": [
{
"offerId": 1,
"applicationType": "SALE",
"valueType": "EXACT_SALE_PRICE",
"salePrice": 225.90,
"targetSelection": "SPECIFIC_PRODUCTS",
"targetRetailerIds": ["TSHIRT-WHITE-M"],
"status": "ACTIVE"
}
]
}applicationType: SALE sets Meta sale_price (WhatsApp strikethrough). Coupon/auto use Meta Offers API (FB/IG). Works for every WABA.
| Field | Required | Description |
|---|---|---|
applicationType | Yes | SALE | AUTOMATIC_AT_CHECKOUT | BUYER_APPLIED |
valueType | Yes | EXACT_SALE_PRICE | PERCENTAGE | FIXED_AMOUNT |
salePrice | * | Exact sale price (major units) when EXACT_SALE_PRICE |
percentOff | * | 1β100 for PERCENTAGE |
fixedAmountOff | * | Amount off for FIXED_AMOUNT |
targetSelection | No | SPECIFIC_PRODUCTS (default) or ALL_CATALOG_PRODUCTS |
targetRetailerIds | * | SKU array for specific products |
couponCode | * | Required for BUYER_APPLIED |
startAt | No | Optional ISO start datetime (API field; alias startTime not used) |
endAt | No | Optional ISO end datetime |
Offer date windows use startAt / endAt on this API. If your app UI omits them, that is an integrator UI gap β ChatYug accepts the fields.
curl -X POST https://chatyug.com/api/external/catalogs/980328057290841/offers \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"applicationType": "SALE",
"valueType": "EXACT_SALE_PRICE",
"salePrice": 225.90,
"targetSelection": "SPECIFIC_PRODUCTS",
"targetRetailerIds": ["TSHIRT-WHITE-M"]
}'For SALE offers, clears Meta sale_price on targeted products.
curl -X DELETE https://chatyug.com/api/external/catalogs/offers/1 \ -H "Authorization: Bearer YOUR_API_KEY"
| 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.
eventType: order (raw Meta in data.order, enriched lines in data.chatyug)GET /orders/:id β items, flow_token, and checkout_submission (answers + media) once the customer completes checkout FlowPUT /commerce/settings, or POST /messages/flow with flowToken = order flow_tokennfm_reply; pull: analytics media APIs or order.checkout_submissionPUT /orders/:id/status (+ optional POST .../notify)pending β confirmed β shipped β delivered (or cancelled). PUT /orders/:id/status can auto-notify the customer on WhatsApp unless notifyCustomer: false.id is the internal PK (use in path params). order_number is the per-WABA display number (prefix + sequence). Customer messages use the display number. Older rows may have order_number: null β fall back to id.Read auto-ack and order numbering for the API key WABA. Catalog link / RSA / Meta cart toggles remain portal-only.
curl -X GET "https://chatyug.com/api/external/commerce/settings" \ -H "Authorization: Bearer YOUR_API_KEY"
Update auto-ack and/or numbering. When autoAckEnabled: true, require autoAckBody (type text) or autoAckTemplateName (type template). Placeholders: {{order_number}}, {{items}}, {{total}}, {{currency}}, {{customer_name}}.
| Field | Required | Description |
|---|---|---|
autoAckEnabled | No* | boolean β *required content when true |
autoAckType | No | text | template |
autoAckBody | Cond. | Free-text ack with placeholders |
autoAckTemplateName | Cond. | APPROVED Meta template name |
autoAckTemplateLanguage | No | Default en |
autoAckTemplateVars | No | JSON array of placeholder names in body-param order |
orderNumberPrefix | No | e.g. ORD- |
orderNumberPad | No | 0β10 zero-pad width |
orderNumberNext | No | Next sequence (β₯1); does not rewrite old orders |
autoSendCheckoutFlow | No | Auto-send checkout Flow after cart |
checkoutFlowId | No | Meta Flow ID |
curl -X PUT "https://chatyug.com/api/external/commerce/settings" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "autoAckEnabled": true, "autoAckType": "text", "autoAckBody": "β
Order #{{order_number}}\n{{items}}\nTotal: {{currency}} {{total}}", "orderNumberPrefix": "ORD-", "orderNumberPad": 4, "orderNumberNext": 1 }'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,
"order_number": "ORD-0007",
"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 id, order_number, items, shipping_address, flow_token, timestamps, and checkout_submission (latest Flow Analytics submit for that flow_token, or null if the customer has not completed the form yet).
{
"success": true,
"order": {
"id": 101,
"order_number": "ORD-0007",
"flow_token": "order_1744012345_abc12",
"shipping_address": { "delivery_address": "12 MG Road", "city": "Bharuch", "pincode": "392001" },
"items": [{ "product_retailer_id": "SKU-001", "product_name": "White Tee", "quantity": 1, "item_price": 599, "currency": "INR" }],
"checkout_submission": {
"eventId": 69,
"submittedAt": "2026-06-23T10:20:00.000Z",
"payload": { "customer_name": "Rahul", "delivery_address": "12 MG Road", "photo_id": { "id": "META_MEDIA_ID", "chatyug_url": "https://chatyug.com/received_media/..." } },
"attachments": [
{
"field": "photo_id",
"mediaType": "image",
"downloadUrl": "https://chatyug.com/api/external/commerce/flows/analytics/events/69/media/photo_id",
"metadataUrl": "https://chatyug.com/api/external/commerce/flows/analytics/events/69/media/photo_id?format=json"
}
],
"hasMedia": true
}
}
}Download Flow uploads with Bearer auth on attachments[].downloadUrl (same as GET /commerce/flows/analytics/events/:eventId/media/:fieldName).
| 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 (shows display order number) |
{ "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 (includes display order number).
WhatsApp Flows for checkout / customer-details forms. Author via portal Flow Design or External API flowJson (full node reference, multi-screen recipes, POST /commerce/flows/media for Image src). Publish to Meta, then send. Deprecate / delete / Meta sync remain portal-only. Deep guide: Commerce Flows API β flowJson design.
message / interactive.type: nfm_reply (raw response_json; PhotoPicker fields often contain Meta media IDs only). For downloadable ChatYug media URLs use Flow Analytics (attachments[]) or GET /orders/:id β checkout_submission when the send used the order flow_token. Recipe: fetch design + analytics + media.List flows for your WABA.
Single flow detail (local id or as returned by list) β includes flow_json design.
Multipart field mediaFile (JPEG/PNG/WebP, max 5MB). Returns public HTTPS url for Image.src / ImageCarousel. Portal designer stays paste-URL only.
curl -X POST "https://chatyug.com/api/external/commerce/flows/media" \ -H "Authorization: Bearer YOUR_API_KEY" \ -F "mediaFile=@./banner.jpg"
| Field | Required | Description |
|---|---|---|
name | Yes | Internal flow name |
category | No | Meta category string, e.g. OTHER (default OTHER) |
flowJson | No | WhatsApp Flow JSON (screens, fields). Per-node examples: commerce-flows.html#flow-nodes |
curl -X POST "https://chatyug.com/api/external/commerce/flows" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "Checkout", "category": "OTHER", "flowJson": { "version": "7.3", "screens": [] } }'Update draft flow name and/or flowJson before publish.
Publishes draft flow to Meta. Required before sending to customers.
Send a published Flow to a customer (24h session or as allowed by Meta). To bind answers to a cart order, pass flowToken = that orderβs flow_token (from GET /orders/:id or auto-send).
| 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 and stored on analytics submit |
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",
"flowToken": "order_1744012345_abc12",
"bodyText": "Please fill in your delivery details",
"ctaText": "Proceed"
}'{
"success": true,
"message": "Flow message sent",
"flowToken": "order_1744012345_abc12",
"messageId": "wamid.HBgM..."
}Query: flowId (local), metaFlowId, eventType (send|submit), phone, page, pageSize, date filters. Each event includes parsed payload and flat attachments[] with downloadUrl / metadataUrl.
Aggregated send/submit counts for filters above.
Query: flowId, format=xlsx|json. Customer submissions export (Excel columns from form fields).
Stream a PhotoPicker/DocumentPicker file for one submit event (Bearer API key). Add ?format=json for metadata only. Same URLs appear on attachments[].downloadUrl and on order.checkout_submission.attachments.
curl -OJ "https://chatyug.com/api/external/commerce/flows/analytics/events/69/media/photo_id" \ -H "Authorization: Bearer YOUR_API_KEY"
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.
Each message includes semantic fields for WhatsApp-like rendering:
contentType β e.g. text, cart_order, commerce_auto_ack, flow_sendmessageType β order for native cart submissions (DB may still store type text)content / text β preview string (multiline for acks; preserve \n)cart β present when contentType is cart_order (items, totals, images)ack β present for commerce auto-acknowledgementstemplateVariables β parsed JSON (same as stored Template_Variables){
"success": true,
"messages": [
{
"messageId": 5001,
"direction": "received",
"messageType": "order",
"contentType": "cart_order",
"content": "1 item Β· βΉ251.00",
"text": "1 item Β· βΉ251.00",
"cart": {
"catalog_id": "980328057290841",
"items_count": 1,
"total_amount": 251,
"currency": "INR",
"thumbnail_url": "https://cdn.example.com/amul.jpg",
"order_id": 5,
"order_number": "5",
"items": [
{
"product_retailer_id": "SKU-001",
"product_name": "Amul Protein Water (250ML)",
"quantity": 1,
"item_price": 251,
"currency": "INR",
"image_url": "https://cdn.example.com/amul.jpg"
}
]
},
"templateVariables": { "kind": "cart_order" }
},
{
"messageId": 5002,
"direction": "sent",
"messageType": "text",
"contentType": "commerce_auto_ack",
"content": "β
Order Received!\n\nOrder #5\nβ’ Amul Protein Water (250ML) Γ 1 INR 251.00\n\nTotal: INR 251.00\n\nWe'll confirm your order shortly. Thank you! π",
"ack": { "ack_type": "text", "order_id": 5, "order_number": "5" }
}
]
}Also use outbound webhook eventType: order β data.chatyug for realtime cart push (see Β§4.5).
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": {
"message": {
"from": "919876543210",
"id": "wamid.HBgM...",
"timestamp": "1719156600",
"type": "interactive",
"interactive": {
"type": "nfm_reply",
"nfm_reply": {
"response_json": "{\"flow_token\":\"order_1744012345_abc12\",\"customer_name\":\"Rahul\",\"delivery_address\":\"12 MG Road\",\"photo_id\":{\"id\":\"META_MEDIA_ID\"}}",
"body": "Sent",
"name": "flow"
}
}
}
}
}Parse response_json as JSON. Correlate with flow_token (same value you passed as flowToken on send, or the cart orderβs flow_token). PhotoPicker/DocumentPicker fields often contain Meta media IDs only on the webhook β use GET /commerce/flows/analytics (attachments[]) or GET /orders/:id β checkout_submission.attachments for ChatYug downloadUrls.
{
"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"
}
]
},
"chatyug": {
"order_id": 135,
"order_number": "135",
"items_count": 1,
"total_amount": 251,
"currency": "INR",
"thumbnail_url": "https://cdn.example.com/amul-protein.jpg",
"items": [
{
"product_retailer_id": "SKU-001",
"product_name": "Amul Protein Water (250ML)",
"quantity": 1,
"item_price": 251,
"currency": "INR",
"image_url": "https://cdn.example.com/amul-protein.jpg"
}
]
}
}
}Raw Meta cart is in data.order. Additive data.chatyug includes ChatYug order_id / order_number, enriched product_name, image_url, totals, and thumbnail_url for native-like cart UI. Also creates a record queryable via GET /orders. Conversation history stores the same cart summary in Template_Variables with kind: "cart_order" (see GET /conversations/:id/messages).
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: September 28, 2026