πŸ“š Chatyug WhatsApp Business API - Complete Documentation

Version 1.7 | Last Updated: July 23, 2026

πŸ“‹ About This Documentation:
This comprehensive guide explains how to integrate Chatyug's WhatsApp Business API with your CRM, software applications, or any external system. Whether you're a developer, business owner, or technical integrator, this documentation will help you understand and implement the API effectively.

πŸ“‘ Table of Contents

1. Overview & Introduction

What is Chatyug API?

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.

Why Use Chatyug API?

Base URL

https://chatyug.com/api

API Response Format

All API responses follow a consistent JSON format:

{ "success": true, "message": "Operation completed successfully", "data": { ... } }
πŸ’‘ Key Concept: The API uses standard HTTP methods (GET, POST) and returns JSON responses. All requests require authentication via API key in the Authorization header.

2. Authentication & API Keys

How Authentication Works

All API requests require an API key for authentication. The API key is passed in the Authorization header using Bearer token format.

Authorization: Bearer YOUR_API_KEY

Getting Your API Key

  1. Login to Chatyug Portal at https://chatyug.com
  2. Navigate to API Configuration page
  3. Click "Generate New API Key" button
  4. Enter a descriptive name (e.g., "My CRM Integration")
  5. Save the API key securely - you cannot view it again!
⚠️ Important Security Note:
API keys are like passwords - keep them secret! Never commit API keys to version control, share them in emails, or expose them in client-side code. Store them in environment variables or secure configuration files.

API Key Format

API keys follow this format:

ck_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0

API Key Scoping

Each API key is associated with:

πŸ’‘ Understanding API Keys:
Think of an API key as a "key to your house" - it gives access to send messages from your WhatsApp Business Account. Each key can be named and tracked separately, making it easy to manage multiple integrations (e.g., one for CRM, one for e-commerce).

2b. MCP / AI Assistants

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

Details: sending media from Claude.

3. API Endpoints Reference

3.1 Send Message Endpoint

Endpoint: POST https://chatyug.com/api/external/send-message

Description: Send a text, template, or session media (image/video/audio/document) WhatsApp message.

Request Headers

HeaderValueRequired
AuthorizationBearer YOUR_API_KEYYes
Content-Typeapplication/jsonYes

Request Body Parameters

ParameterTypeRequiredDescription
phoneNumberIdstringYesYour WhatsApp phone number ID
tostringYesRecipient phone number (with country code, e.g., 919876543210)
typestringYestext | template | image | video | audio | document
textstringIf type=textText message content (also used as caption for media if caption omitted)
templateNamestringIf type=templateName of approved WhatsApp template
templateLanguagestringIf type=templateTemplate language code (e.g., "en", "en_US")
templateVariablesarrayNoArray of variable values for template
mediaIdstringFor session media*Meta media ID from POST /messages/upload-media (preferred)
mediaUrlstringFor session media*Public HTTPS media link, or template header media URL
captionstringNoCaption for image/video/document (max 1024)
filenamestringNoFilename for document type

* For image/video/audio/document, provide mediaId or mediaUrl.

Do not send 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.

Example: Send Text Message

POST https://chatyug.com/api/external/send-message Authorization: Bearer ck_your_api_key_here Content-Type: application/json { "phoneNumberId": "719142414620783", "to": "919876543210", "type": "text", "text": "Hello! This is a test message from my CRM." }

Example: Send Image (session media)

{ "phoneNumberId": "719142414620783", "to": "919876543210", "type": "image", "mediaId": "123456789012345", "caption": "Product photo" }

Upload first: POST https://chatyug.com/api/external/messages/upload-media (multipart mediaFile + phoneNumberId) β†’ use returned data.mediaId.

Example: Send Template Message

POST https://chatyug.com/api/external/send-message Authorization: Bearer ck_your_api_key_here Content-Type: application/json { "phoneNumberId": "719142414620783", "to": "919876543210", "type": "template", "templateName": "order_confirmation", "templateLanguage": "en", "templateVariables": ["John Doe", "ORD-12345", "β‚Ή1,299"] }

Response Format

{ "success": true, "message": "Message sent successfully", "data": { "messageId": "wamid.HBgMOTE5ODc2NTQzMjEw...", "conversationId": 12345, "status": "sent", "to": "919876543210", "type": "image", "timestamp": "2025-12-25T12:00:00.000Z" } }

Inbound media URLs

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.

3.2 Check Delivery Status Endpoint

Endpoint: GET https://chatyug.com/api/external/delivery-status/:messageId

Description: Check the delivery status of a previously sent message.

Request Headers

HeaderValueRequired
AuthorizationBearer YOUR_API_KEYYes

URL Parameters

ParameterTypeRequiredDescription
messageIdstringYesThe message ID returned from send-message endpoint

Example Request

GET https://chatyug.com/api/external/delivery-status/wamid.HBgMOTE5ODc2NTQzMjEw... Authorization: Bearer ck_your_api_key_here

Response Format

{ "success": true, "data": { "messageId": "wamid.HBgMOTE5ODc2NTQzMjEw...", "status": "delivered", "to": "919876543210", "customerName": "John Doe", "messageType": "template", "content": "Template: order_confirmation", "sentAt": "2025-12-25T12:00:00.000Z", "deliveredAt": "2025-12-25T12:00:05.000Z", "readAt": "2025-12-25T12:00:15.000Z", "error": null } }

Status Values

StatusMeaningWhen It Occurs
sentMessage sent to WhatsAppImmediately after sending
deliveredMessage delivered to phoneWhen phone receives message
readMessage read by recipientWhen user opens WhatsApp
failedMessage failed to sendIf delivery fails
πŸ“Š Understanding Message Status:
Message status is updated automatically via webhooks from WhatsApp. You don't need to poll continuously - just check the status when needed. Status updates typically arrive within seconds of the event occurring.

3.3 Carousel Template API

Send approved media card carousel templates via API. Register templates in the ChatYug portal; use the API to list and send only.

Prerequisites: Template must be APPROVED in Meta. Each card needs a headerMediaId from portal media upload (external upload planned Phase 1b).

3.3.1 Upload Header Media

Endpoint: POST https://chatyug.com/api/external/messages/upload-media

Auth: Bearer API key. Content-Type: multipart/form-data

FieldRequiredDescription
mediaFileYesImage or video file (field name matches portal; max 15MB)
phoneNumberIdYesWhatsApp phone number ID for this API key WABA
mediaTypeNoimage (default) or video β€” local storage subfolder
curl -X POST https://chatyug.com/api/external/messages/upload-media \ -H "Authorization: Bearer YOUR_API_KEY" \ -F "mediaFile=@header.jpg" \ -F "phoneNumberId=YOUR_PHONE_NUMBER_ID" \ -F "mediaType=image"
{ "success": true, "message": "Media uploaded successfully", "data": { "mediaId": "1234567890", "mediaUrl": "https://chatyug.com/chat_media/images/chat_....jpg", "filename": "chat_123.jpg", "size": 102400, "mimetype": "image/jpeg" } }

Use data.mediaId as cards[].headerMediaId when sending carousel messages.

3.3.2 List Carousel Templates

Endpoint: GET https://chatyug.com/api/external/templates/carousel

Query: status (optional, default APPROVED) β€” APPROVED, PENDING, REJECTED

GET https://chatyug.com/api/external/templates/carousel?status=APPROVED Authorization: Bearer YOUR_API_KEY
{ "success": true, "templates": [ { "templateId": 1217, "templateName": "summer_sale_carousel", "status": "APPROVED", "languageCode": "en_US", "carouselConfig": { "cards": [], "source": "catalog" }, "createdAt": "2026-06-03T10:30:00.000Z" } ] }

3.3.3 Get Single Carousel Template

Endpoint: GET https://chatyug.com/api/external/templates/carousel/:templateId

3.3.4 Send Carousel Message

Endpoint: POST https://chatyug.com/api/external/messages/carousel

{ "phoneNumberId": "YOUR_PHONE_NUMBER_ID", "to": "919876543210", "templateName": "summer_sale_carousel", "templateId": 1217, "languageCode": "en_US", "bodyParams": [{ "type": "text", "text": "Rahul" }], "cards": [ { "card_index": 0, "headerMediaId": "META_MEDIA_ID", "headerMediaType": "image", "bodyParams": [], "buttons": [ { "sub_type": "quick_reply", "index": "0", "parameters": [{ "type": "payload", "payload": "shop" }] } ] }, { "card_index": 1, "headerMediaId": "META_MEDIA_ID_2", "headerMediaType": "image", "bodyParams": [], "buttons": [ { "sub_type": "quick_reply", "index": "0", "parameters": [{ "type": "payload", "payload": "buy" }] } ] } ] }

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).

Carousel error codes

CodeHTTPDescription
TEMPLATE_NOT_APPROVED403Template exists but Status β‰  APPROVED
TEMPLATE_NOT_FOUND404templateId not in this account
PHONE_NOT_FOUND404phoneNumberId not in this account
VALIDATION_ERROR400Invalid cards count, missing fields
META_ERROR502Meta API rejected the request

Feature availability

FeaturePortalExternal API
Register templateYesPhase 3
Sync Meta statusYesPhase 3
Send approved carouselYesYes (Phase 1)
Upload header mediaYesYes (Phase 1b)
Bulk carouselYesPhase 2
Scheduled carouselYesNot planned

Note: Create and approve templates in the portal. Bulk carousel (Phase 2) is portal-only at this time.

Integrator workflow

  1. Create or register a carousel template in the portal (Carousel Templates page)
  2. Wait for Meta approval; Sync from Meta in portal
  3. GET templates/carousel?status=APPROVED β€” inspect carouselConfig
  4. POST messages/upload-media per card β†’ collect mediaId as headerMediaId
  5. POST messages/carousel
  6. GET delivery-status/:messageId

3.4 Catalog API

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.

Integration pattern: Sync products from your ERP via 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.
Category browse (SHOP keyword): ChatYug does not auto-reply to 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.

GET /catalogs β€” List catalogs

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"
    }
  ]
}

POST /catalogs β€” Create catalog

FieldRequiredDescription
catalogNameYesDisplay name
verticalYescommerce 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"}'

GET /catalogs/:catalogId/products β€” List products

Query: page, limit (max 200), search (name/SKU/description), availability (in stock / out of stock), category (category name or slug from GET /categories).

GET /catalogs/:catalogId/categories β€” List 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.

QueryDescription
inStockOnlyDefault 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.

GET /catalogs/:catalogId/product-list-payload β€” Build product_list sections

Builds Meta-ready sections and a flat productRetailerIds array dynamically from the catalog β€” no hardcoded product lists.

QueryDescription
categoryCategory slug from GET /categories (e.g. cat_dairy)
groupByCategoryIf 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.

POST /catalogs/:catalogId/products β€” Create product

FieldRequiredDescription
productNameYesProduct title
priceYesNumeric price in INR
currencyNoDefault INR
retailerIdNoSKU; auto-generated if omitted
descriptionNoProduct description
imageUrlNoPublic HTTPS image URL
availabilityNoin stock or out of stock
categoryNoBrowse category label (e.g. Dairy) β€” drives category picker flow

PUT /catalogs/:catalogId/products/:retailerId β€” Update product

Partial update β€” send only fields to change (price, availability, name, etc.).

POST /messages/product-list β€” Send product list

FieldRequiredDescription
phoneNumberIdYesWhatsApp phone number ID
toYesRecipient (e.g. 919876543210 or +91 98765 43210)
catalogIdYesMeta catalog ID
headerTextNoMessage header
bodyTextYesMessage body
sectionsOne of*Meta format: [{ title, product_items: [{ product_retailer_id }] }]
productRetailerIdsOne of*Flat SKU array β€” single section (legacy / flat browse)
sectionTitleNoTitle 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"
  }'

Category browse β€” end-to-end integrator flow

  1. Customer sends text (e.g. SHOP) β†’ your webhook receives eventType: message
  2. GET /catalogs/{metaCatalogId}/categories
  3. POST /messages/interactive with interactiveType: "list" and sections from interactiveListSections
  4. Customer taps a category β†’ webhook interactive.list_reply.id = category slug (e.g. cat_dairy)
  5. GET /catalogs/{id}/product-list-payload?category={slug}
  6. POST /messages/product-list with returned sections or productRetailerIds

See also docs/INTEGRATOR_WHATSAPP_COMMERCE_REFERENCE.md Β§4.3 for full curl examples and webhook payloads.

POST /messages/single-product β€” Send single product card

FieldRequiredDescription
phoneNumberIdYes
toYes
catalogIdYes
productRetailerIdYesSKU from catalog
bodyTextYesCaption text

Catalog errors

HTTPWhen
400Validation (missing fields, invalid price)
403Catalog not owned by this API key WABA
404Catalog or product not found
502Meta Graph API error

3.5 Orders API

WhatsApp Commerce orders (native cart or flow checkout). Orders arrive via the order webhook and are queryable here.

Status pipeline: pending β†’ confirmed β†’ shipped β†’ delivered (or cancelled). PUT /orders/:id/status can auto-notify the customer on WhatsApp unless notifyCustomer: false.

GET /orders

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" }]
    }
  ]
}

GET /orders/:orderId

Full order with items, shipping_address, flow_token, timestamps.

PUT /orders/:orderId/status

FieldRequiredDescription
statusYespending | confirmed | shipped | delivered | cancelled
noteNoInternal note; included in customer notification
notifyCustomerNoDefault true β€” sends WhatsApp text update
{ "success": true, "message": "Order status updated to shipped", "notifySent": true }

POST /orders/:orderId/note

Body: { "note": "AWB: DTDC123456789" } β€” internal note only, no status change.

POST /orders/:orderId/notify

Body: { "message": "Custom WhatsApp text..." } β€” omit message for default status-based text.

3.6 Commerce Flows API

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.

Flow authoring: Use WhatsApp Messaging β†’ Flow Design for non-technical design. 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.

GET /commerce/flows

List flows for your WABA.

POST /commerce/flows β€” Create flow on Meta

FieldRequiredDescription
flowNameYesInternal name
categoriesNoe.g. ["OTHER"]
flowJsonNoWhatsApp Flow JSON (screens, fields). If omitted, a default checkout scaffold may be used

POST /commerce/flows/:flowId/publish

Publishes draft flow to Meta. Required before sending to customers.

POST /messages/flow β€” Send Flow message

FieldRequiredDescription
phoneNumberIdYes
toYesCustomer phone
flowIdYesMeta flow ID from create/list
flowTokenNoCorrelation token returned in nfm_reply
headerTextNo
bodyTextYes
ctaTextNoButton 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.

GET /commerce/flows/analytics

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"
  }
}

GET /commerce/flows/analytics/events/:eventId/media/:fieldName

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.

GET /commerce/flows/analytics/summary

Per-flow send/submit counts.

GET /commerce/flows/analytics/export

format=xlsx (default) or json. Same filters as list. Excel cells for media fields prefer the public chatyug_url when present.

3.7 Chatbot Flows API

Keyword-triggered automation inside ChatYug. Requires automation permission on the WABA. Alternative to building your own keyword engine on inbound webhooks.

When to use: Simple keyword β†’ journey flows managed in ChatYug. For distributor-by-pincode routing or custom COD logic, use inbound message webhooks and your own engine (hybrid architecture).

GET /chatbot/flows

Query: phoneNumberId, published=true, active=true.

POST /chatbot/flows

FieldRequiredDescription
flowNameYes
triggerKeywordsYesComma-separated, e.g. SHOP,CATALOGUE
flowDataYesJSON graph: { nodes: [], edges: [] }
phoneNumberIdNoScope to a phone number
sessionTimeoutMinutesNoDefault session timeout

GET /chatbot/flows/:flowId

PUT /chatbot/flows/:flowId

Update name, keywords, flowData, isActive.

403 if automation permission not enabled for WABA.

3.8 Connectivity Test

GET /test

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" }

GET /me

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"
    }
  ]
}

3.9 Integrator API (Inbound + Session)

Read conversations, send interactive replies, and fetch media β€” for chat consoles and commerce bots driven by webhooks.

POST /messages/interactive β€” Button or list message

Within 24 hours of the customer's last inbound message. Use for distributor selection, project pickers, COD confirm, etc.

FieldRequiredDescription
phoneNumberIdYes
toYesRecipient phone
interactiveTypeYesbutton (1–3 buttons) or list
bodyTextYesMain message (max 1024 chars)
headerTextNoMax 60 chars
footerTextNoMax 60 chars
buttonsIf button[{ id, title }] β€” id max 256, title max 20
listButtonTextIf listOpen list label (max 20)
sectionsIf list[{ title, rows: [{ id, title, description? }] }] β€” max 10 rows per section
contextMessageIdNoReply 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.

GET /conversations

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"
      }
    }
  ]
}
24-hour window: Each conversation includes session.sessionOpen, lastCustomerMessageAt, and expiresAt (ISO timestamp). When sessionOpen is false, use template messages via POST /send-message with type: "template".

GET /conversations/:conversationId/messages

Query: limit (max 500), offset. Returns messages, conversation, session, total.

GET /messages/:messageId/media

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."
}
Media URL lifetime: Files under /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.

Integrator API errors

HTTPMeaning
400Missing/invalid body (e.g. wrong button count, missing phoneNumberId)
401Invalid or missing API key
403Phone number not in this WABA
404Conversation or message not found
502Meta rejected interactive/flow send (session closed, policy, etc.)

3.10 Standard Templates API

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).

GET /templates β€” List templates

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"
  }
}

GET /templates/:templateId β€” Single template

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.

Integration workflow

  1. GET /templates?status=APPROVED β€” populate template picker in your portal
  2. User selects template β†’ read variables array for form fields
  3. Build templateVariables array from user input in placeholder order
  4. POST /send-message with type: "template", templateName, templateLanguage
  5. Track delivery via status webhook or GET /delivery-status/:messageId
Variable format: templateVariables 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.

Template API errors

HTTPCodeWhen
404TEMPLATE_NOT_FOUNDtemplateId not in your WABA
400β€”Invalid templateId

3.11 Scheduled Messages API

Schedule template-based WhatsApp sends from your CRM, ERP, or custom platform. Requires API key + automation permission on the WABA for write endpoints.

POST /scheduled-messages

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.

3.12 Template Creation API

Create and submit templates to Meta via API. Always returns PENDING. Requires automation permission.

POST /templates

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.

4. Integration Theory & Concepts

4.1 Understanding REST APIs

REST (Representational State Transfer) is an architectural style for designing web services. Our API follows REST principles, making it easy to understand and integrate.

Key Concepts:

4.2 How API Integration Works

Here's the complete flow of how your software integrates with Chatyug API:

Step 1: Your Software β†’ Prepare Message Data Step 2: Your Software β†’ Send HTTP POST Request to Chatyug API Step 3: Chatyug API β†’ Validates API Key & Request Step 4: Chatyug API β†’ Sends Message to WhatsApp Step 5: WhatsApp β†’ Delivers Message to Recipient Step 6: WhatsApp β†’ Sends Status Update to Chatyug (via Webhook) Step 7: Chatyug β†’ Updates Database with Status Step 8: Your Software β†’ Can Check Status Anytime via GET Request

4.3 Understanding Message Types

Text Messages

Template Messages

πŸ’‘ Choosing the Right Message Type:
Use Text Messages when you're in an active conversation (within 24-hour window).
Use Template Messages for automated notifications, order confirmations, or when starting a new conversation outside the 24-hour window.

4.4 Understanding Webhooks (Status Updates)

WhatsApp doesn't provide a "check status" API endpoint. Instead, status updates are delivered automatically via webhooks - this is how WhatsApp designed their system.

How It Works:

  1. You send a message via our API
  2. We save the message to our database
  3. WhatsApp sends status updates to our webhook automatically
  4. We update the message status in our database
  5. You can check the status anytime by querying our database via the delivery-status endpoint
βœ… Why This Approach Works:
This is the official and only way to track message status according to Meta's WhatsApp Business API. We handle all the webhook complexity for you - you just need to check the status when needed.

4.5 Outbound Webhooks (Push to Your 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.

Webhook registration: URL and secret are configured only in the portal β€” there is no External API to register or rotate webhooks programmatically today. Use the portal UI and store the secret in your integration settings.

Delivery guarantees

AspectBehaviour
MethodHTTP POST, Content-Type: application/json
HeadersX-Chatyug-Event-Id (idempotency key), X-Chatyug-Signature (if secret configured)
RetriesAutomatic for up to 48 hours; backoff ~1, 2, 10, 60, 360 minutes (~12–13 attempts)
Rate limit~300 events/minute per WABA
AcknowledgementReturn HTTP 2xx quickly; process async in your app

Signature verification (confirmed)

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 route

Envelope (all events)

Every 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 β€” inbound text

{
  "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 β€” inbound media

{
  "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 β€” button reply

{
  "eventType": "message",
  "data": {
    "message": {
      "type": "interactive",
      "interactive": {
        "type": "button_reply",
        "button_reply": { "id": "DIST_01", "title": "Distributor A" }
      }
    }
  }
}

eventType: message β€” list reply

{
  "eventType": "message",
  "data": {
    "message": {
      "type": "interactive",
      "interactive": {
        "type": "list_reply",
        "list_reply": { "id": "PROJ_12", "title": "Project Alpha", "description": "Phase 2" }
      }
    }
  }
}

eventType: message β€” Flow submission (nfm_reply)

{
  "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 β€” delivery receipt

{
  "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 β€” WhatsApp cart

{
  "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.

eventType: test

Sent from Webhook Settings "Send test event". Use to validate URL, TLS, and signature handling.

Recommended webhook handler flow

  1. Read raw body β†’ verify X-Chatyug-Signature
  2. Parse JSON β†’ check eventId not already processed
  3. Route on eventType β†’ update your DB / trigger bot logic
  4. Return 200 OK within a few seconds

5. CRM Integration Guide

5.1 Common CRM Integration Scenarios

Scenario 1: Order Confirmation

When: Customer places an order in your e-commerce system

Action: Send template message with order details

// Pseudo-code example function onOrderPlaced(order) { sendWhatsAppMessage({ to: order.customerPhone, type: "template", templateName: "order_confirmation", templateVariables: [ order.customerName, order.orderNumber, order.totalAmount ] }); }

Scenario 2: Follow-up After Support Ticket

When: Support ticket is resolved

Action: Send text message asking for feedback

// Pseudo-code example function onTicketResolved(ticket) { if (isWithin24Hours(ticket.lastCustomerMessage)) { sendWhatsAppMessage({ to: ticket.customerPhone, type: "text", text: "Hi! Your support ticket #" + ticket.id + " has been resolved. " + "Please let us know if you need any further assistance." }); } }

Scenario 3: Payment Reminder

When: Invoice is due in 3 days

Action: Send template message with payment link

// Pseudo-code example function sendPaymentReminder(invoice) { sendWhatsAppMessage({ to: invoice.customerPhone, type: "template", templateName: "payment_reminder", templateVariables: [ invoice.customerName, invoice.invoiceNumber, invoice.amount, invoice.paymentLink ] }); }

5.2 Integration Architecture

Here's how to structure your CRM integration:

Layer 1: CRM Database/System ↓ (triggers event) Layer 2: Integration Service/Webhook Handler ↓ (calls API) Layer 3: Chatyug API ↓ (sends message) Layer 4: WhatsApp ↓ (delivers to customer) Layer 5: Customer's Phone

5.3 Best Practices for CRM Integration

1. Store API Keys Securely

2. Handle Errors Gracefully

3. Track Message Status

4. Respect Rate Limits

5. Personalize Messages

⚠️ Important:
Always test your integration in a development/staging environment before deploying to production. Test with your own phone number first to ensure everything works correctly.

6. Complete Code Examples

πŸ“š How to Use These Examples:
Each example below is a complete, working implementation. Copy the code, replace the API key and phone number IDs with your own values, and you're ready to go! All examples include detailed comments explaining each step.

6.1 Node.js / JavaScript Example

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.

Step 1: Install Required Package

# Install axios for making HTTP requests npm install axios

Step 2: Complete Implementation

// ============================================
// 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();
πŸ’‘ Pro Tips:
β€’ Store your API key in environment variables: process.env.CHATYUG_API_KEY
β€’ Always handle errors gracefully - WhatsApp delivery can fail for various reasons
β€’ Store message IDs in your database to track delivery status later
β€’ Use template messages for automated notifications (order confirmations, etc.)
β€’ Use text messages for customer support conversations

6.2 PHP Example

This example shows how to integrate Chatyug API in a PHP application. Perfect for WordPress plugins, Laravel applications, or any PHP-based system.

Step 1: Complete Implementation

<?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);
    }
}
?>

Step 2: Usage Examples

<?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";
}
?>

6.3 Python Example

This example shows how to integrate Chatyug API in a Python application. Perfect for Django, Flask, or any Python-based system.

Step 1: Install Required Package

# Install requests library pip install requests

Step 2: Complete Implementation

# ============================================
# 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}")

6.4 C# / .NET Example

This example shows how to integrate Chatyug API in a C# / .NET application.

Step 1: Complete Implementation

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}");
        }
    }
}

6.5 Dart / Flutter Example

This example shows how to integrate Chatyug API in a Flutter/Dart mobile application.

Step 1: Add Required Package

# Add to pubspec.yaml
dependencies:
  http: ^1.1.0
  dart:convert

Step 2: Complete Implementation

// ============================================
// 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');
  }
}

6.6 Android - Kotlin Example

This example shows how to integrate Chatyug API in an Android application using Kotlin.

Step 1: Add Required Dependencies

// Add to build.gradle (Module: app)
dependencies {
    implementation 'com.squareup.okhttp3:okhttp:4.12.0'
    implementation 'com.google.code.gson:gson:2.10.1'
}

Step 2: Complete Implementation

// ============================================
// 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}")
    }
}
*/

6.7 Android - Java Example

This example shows how to integrate Chatyug API in an Android application using Java.

Step 1: Add Required Dependencies

// Add to build.gradle (Module: app)
dependencies {
    implementation 'com.squareup.okhttp3:okhttp:4.12.0'
    implementation 'com.google.code.gson:gson:2.10.1'
}

Step 2: Complete Implementation

// ============================================
// 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());
        }
    }
}
*/

6.8 iOS - Swift Example

This example shows how to integrate Chatyug API in an iOS application using Swift.

Step 1: No External Dependencies Required

Swift's built-in URLSession is sufficient for making HTTP requests.

Step 2: Complete Implementation

// ============================================
// 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)")
    }
}
*/

7. Best Practices & Security

7.1 Security Best Practices

7.2 Error Handling

Always implement proper error handling in your integration:

// Example error handling pattern try { const result = await sendMessage(...); // Handle success } catch (error) { if (error.response) { // API returned an error response console.error('API Error:', error.response.status, error.response.data); } else if (error.request) { // Request was made but no response received console.error('Network Error:', error.message); } else { // Something else happened console.error('Error:', error.message); } // Implement retry logic or notify admin }

7.3 Rate Limiting

7.4 Message Content Guidelines

8. Troubleshooting Guide

8.1 Common Issues and Solutions

Issue: "401 Unauthorized" Error

Cause: Invalid or missing API key

Solution:

Issue: "404 Message not found" when checking status

Cause: Message wasn't saved to database or messageId is incorrect

Solution:

Issue: "Template not found" Error

Cause: Template name is incorrect or template not approved

Solution:

Issue: Message sent but not delivered

Possible Causes:

Solution: Check delivery status endpoint for error details

8.2 Diagnostic Endpoint

Use the diagnostic endpoint to troubleshoot issues:

GET https://chatyug.com/api/external/diagnostic?messageId=wamid.XXX&wabaId=XXX&checkWebhooks=true Authorization: Bearer YOUR_API_KEY

This endpoint provides:

8.3 Getting Help

If you're still experiencing issues:

πŸ“ž Support & Resources

API Base URL: https://chatyug.com/api

Documentation Version: 1.3

Last Updated: July 23, 2026

πŸ’‘ Need More Help?
For additional support, feature requests, or to report bugs, please contact the Chatyug support team through your account portal or email support.

9. Third-Party Integrator FAQ

Answers to common questions from commerce/chat integrators (updated June 2026, API v1.6).

9.1 Full webhook payload samples?

See Β§4.5 Outbound Webhooks for field-level JSON for message (text, media, button, list, nfm_reply), status, and order.

9.2 Webhook signature β€” what is signed?

HMAC-SHA256 of the exact raw POST body (UTF-8), secret from Webhook Settings, header value sha256=<hex>. No timestamp/replay header β€” dedupe on eventId.

9.3 Can we register webhooks via API?

No β€” portal only (API Configuration β†’ Webhook Settings). Programmatic registration is not available in v1.5.

9.4 Flow form β€” API or portal first?

Prefer the ChatYug portal Flow Design module (templates + drag-and-drop + Approve/Publish + Test Send). POST /commerce/flows can still create flows with flowJson for automation. Then publish and send via POST /messages/flow. Responses always arrive as webhook nfm_reply.

9.5 List standard templates via API?

Yes. GET /api/external/templates?status=APPROVED returns template names, languages, body text, and variables with placeholders. GET /templates/:templateId returns full detail and a sendMessageExample. Carousel templates: GET /templates/carousel.

9.6 Rate limits and errors for new endpoints?

AreaGuidance
Outbound webhooks~300 events/min per WABA
External APISubject to Meta WhatsApp throughput; avoid burst > 80 msg/sec per number
Interactive / flow send400 validation, 403 phone/WABA, 502 Meta rejection (e.g. session closed)
Orders / catalog400 invalid status/fields, 404 not found, 502 Meta catalog errors

9.7 Media URL lifetime?

/received_media/... paths are persisted on ChatYug. Meta-hosted media IDs expire β€” download and store in your system when processing webhooks or immediately after GET /messages/:id/media.

9.8 One WABA for multi-distributor?

Yes. One API key = one WABA (one or more phone numbers). Route distributors in your application using customer phone + your pincode/selection logic; ChatYug does not split by distributor.

9.9 Session window expiry timestamp?

Yes. GET /conversations and GET /conversations/:id/messages return session.sessionOpen, lastCustomerMessageAt, and expiresAt (last inbound + 24 hours). Use to auto-switch between text/interactive and templates.

9.10 Mark-as-read / typing indicators?

Not available in External API v1.5. Portal chat UI supports read state internally; API exposure is planned as a future enhancement (cosmetic for integrators).

9.11 Feature β†’ API quick map (commerce journey)

StepAPI
Keyword / inboundWebhook message or Chatbot Flows
Catalogue welcomesend-message, messages/product-list, messages/carousel
Pincode / locationsend-message + inbound webhook
Distributor / project pickersPOST /messages/interactive
Customer details formPOST /messages/flow β†’ nfm_reply
Order notificationsPUT /orders/:id/status or send-message template
Chat consoleGET /conversations, GET .../messages, webhooks
Hybrid architecture (recommended): Keep your portal/DB as source of truth for orders, distributors, pincode routing, and COD. Use ChatYug for WhatsApp transport β€” webhooks in, send-message / interactive / flow out. Optional: ChatYug Catalog/Orders/Chatbot APIs as accelerators, not system of record.

10. Known Gaps & Roadmap

ItemStatusWorkaround
Mark-as-read / typing via API❌ Not in v1.6Portal only
Webhook registration API❌ Portal onlyManual setup in Webhook Settings
Bulk carousel via API❌ Portal onlyUse portal bulk messaging
Register non-carousel templates via API❌ Portal onlyPortal template manager; list/send via API