Skip to content

WhatsApp Lite API Guide

Complete documentation for both edge functions with internal logic and sample curl commands for all use cases.

Table of Contents

  1. whatsapp-lite-send - Sending Messages
  2. Direct AppGain API – curl for all calling cases
  3. appgain-whatsapp-webhook - Receiving Messages
  4. Common Use Cases

whatsapp-lite-send - Sending Messages

Internal Logic Flow

1. Request Validation
 ├─ Validates JSON payload
 ├─ Ensures required fields: `to`, `message`
 ├─ Validates message length (max 4096 chars)
 └─ Ensures either `suitId` or `organizationId` is provided

2. Phone Number Processing
 ├─ Cleans phone number (removes @s.whatsapp.net)
 └─ Logs both original and cleaned versions

3. Organization Lookup
 ├─ If `suitId` provided → Look up org by `settings->>appgain_suit_id`
 └─ If `organizationId` provided → Look up org by ID

4. Get AppGain Credentials
 ├─ Extract `appgain_api_key` from org settings
 └─ Extract `appgain_suit_id` from org settings

5. Send via AppGain API
 ├─ POST to https://notify.appgain.io/{suitId}/send
 ├─ Headers: appapikey, Content-Type
 └─ Body: UOWHATSAPP payload with cleaned phone number

6. Contact Management
 ├─ Find existing contact by phone number (via shared utility)
 ├─ If not found, create with `contactName` or "Unknown Contact"
 └─ Store multiple phone number variations for better matching

7. Channel Account Management
 ├─ Look up ALL active channel accounts for organization
 ├─ Use the FIRST (most recent) one found
 └─ If none exist, create new channel account

8. Conversation Management
 ├─ If `conversationId` provided → use it directly
 ├─ If not provided:
 │ ├─ Search for existing OPEN conversation for contact + channel
 │ ├─ If found → use existing conversation ID
 │ └─ If not found → create new conversation
 └─ Update `last_message_at` timestamp

9. Message Storage
 ├─ Insert message with direction: "OUTBOUND"
 ├─ Set status: "SENT"
 ├─ Store `external_id` from AppGain response
 ├─ If `from` provided → add to metadata as `sender_name`
 └─ Link to conversation and contact

10. Return Response
 ├─ success: |||/false
 ├─ result: AppGain API response
 ├─ conversationId
 ├─ contactId
 └─ debug info

API Endpoint

POST https://YOUR_SUPABASE_URL/functions/v1/whatsapp-lite-send

Required Headers

Authorization: Bearer YOUR_ANON_KEY
Content-Type: application/json

Request Parameters

Field Type Required Description
to string ✅ Yes Recipient phone number (supports 201001383533@s.whatsapp.net format)
message string ✅ Yes Message content (max 4096 characters)
suitId string ⚠️ Either AppGain suit ID (mutually exclusive with organizationId)
organizationId string ⚠️ Either Supabase organization ID (mutually exclusive with suitId)
conversationId string ❌ No Use existing conversation ID instead of creating/finding one
contactName string ❌ No Contact name when creating new contact
from string ❌ No Sender name for UI display (stored in metadata)

Response

Success Response (200 OK):

{
 "success": true,
 "result": {
 "status": "success",
 "message": "successfully sent"
 },
 "conversationId": "uuid-of-conversation",
 "contactId": "uuid-of-contact",
 "debug": {
 "hasChannelAccount": false,
 "hasConversationId": true,
 "hasContactId": true
 }
}

Error Response (400/404/500):

{
 "error": "Error message describing what went wrong"
}


Direct AppGain API – curl for all calling cases

These examples call the AppGain notify API directly (https://notify.appgain.io/{suitId}/send). Use your suitId and AppGain API key from channel settings.

Base: POST https://notify.appgain.io/{SUIT_ID}/send Headers: appapikey: YOUR_APPGAIN_API_KEY, Content-Type: application/json Body: JSON with top-level key UOWHATSAPP. Phone numbers must be cleaned (no @s.whatsapp.net).

AppGain case 1: Text only

curl -X POST "https://notify.appgain.io/YOUR_SUIT_ID/send" \
 -H "appapikey: YOUR_APPGAIN_API_KEY" \
 -H "Content-Type: application/json" \
 -d '{
 "UOWHATSAPP": {
 "random_string": 0,
 "receivers": [{ "mobileNum": "201001383533" }],
 "message": "Hello, this is a text-only message"
 }
 }'

AppGain case 2: Image only (no caption)

curl -X POST "https://notify.appgain.io/YOUR_SUIT_ID/send" \
 -H "appapikey: YOUR_APPGAIN_API_KEY" \
 -H "Content-Type: application/json" \
 -d '{
 "UOWHATSAPP": {
 "random_string": 0,
 "receivers": [{ "mobileNum": "201001383533" }],
 "imageUrl": "https://example.com/image.jpg"
 }
 }'

AppGain case 3: Image with caption

curl -X POST "https://notify.appgain.io/YOUR_SUIT_ID/send" \
 -H "appapikey: YOUR_APPGAIN_API_KEY" \
 -H "Content-Type: application/json" \
 -d '{
 "UOWHATSAPP": {
 "random_string": 0,
 "receivers": [{ "mobileNum": "201001383533" }],
 "imageUrl": "https://example.com/image.jpg",
 "message": "Check out this image"
 }
 }'

AppGain case 4: Video

curl -X POST "https://notify.appgain.io/YOUR_SUIT_ID/send" \
 -H "appapikey: YOUR_APPGAIN_API_KEY" \
 -H "Content-Type: application/json" \
 -d '{
 "UOWHATSAPP": {
 "random_string": 0,
 "receivers": [{ "mobileNum": "201001383533" }],
 "message": "Optional caption for video",
 "videoUrl": "https://example.com/video.mp4",
 "imageUrl": ""
 }
 }'

AppGain case 5: Document

curl -X POST "https://notify.appgain.io/YOUR_SUIT_ID/send" \
 -H "appapikey: YOUR_APPGAIN_API_KEY" \
 -H "Content-Type: application/json" \
 -d '{
 "UOWHATSAPP": {
 "random_string": 0,
 "receivers": [{ "mobileNum": "201001383533" }],
 "message": "Optional caption for document",
 "documentUrl": "https://example.com/document.pdf",
 "imageUrl": ""
 }
 }'

AppGain case 6: Multiple receivers (broadcast)

curl -X POST "https://notify.appgain.io/YOUR_SUIT_ID/send" \
 -H "appapikey: YOUR_APPGAIN_API_KEY" \
 -H "Content-Type: application/json" \
 -d '{
 "UOWHATSAPP": {
 "random_string": 0,
 "receivers": [
 { "mobileNum": "201001383533" },
 { "mobileNum": "2015551234567" }
 ],
 "message": "Broadcast message to multiple numbers"
 }
 }'

Note: The whatsapp-lite-send edge function only uses AppGain cases 1–3 (text, image, image+caption). Video and document (cases 4–5) are used by the campaign scheduler; multiple receivers (case 6) are used by campaigns, not by the single-message edge function.

Multi-attachment delivery: When one message carries multiple attachments, the edge function sends one AppGain call per attachment. Two things are needed so all of them are delivered (not just the first):

  • Unique random_string on calls 2..N only. AppGain treats random_string as a per-send de-duplication nonce, so reusing a constant value for a burst to the same receiver makes AppGain drop calls 2..N as duplicate retries. However, AppGain also reflects a non-zero random_string in the delivered message content — sending every call with a unique nonce altered normal chat texts in production (recipients received the typed text with the nonce appended). The edge function therefore sends random_string: 0 on the first/only call (the one carrying the typed text or caption — matching the curl examples above) and a unique value only on the caption-less attachment calls 2..N.
  • Randomized pacing. A randomized ~0.8–2.5 s delay is inserted between consecutive sends so the WhatsApp session doesn't collapse a rapid burst.

Curl Examples (Supabase edge function)

Example 1: Basic Message Using suitId

curl -X POST https://txpaxbxhnvnhsjwwaeoy.supabase.co/functions/v1/whatsapp-lite-send \
 -H "Authorization: Bearer YOUR_ANON_KEY" \
 -H "Content-Type: application/json" \
 -d '{
 "to": "201001383533",
 "message": "Hello, this is a test message",
 "suitId": "YOUR_SUIT_ID"
 }'

Example 2: Message with Phone Number Including @s.whatsapp.net

curl -X POST https://txpaxbxhnvnhsjwwaeoy.supabase.co/functions/v1/whatsapp-lite-send \
 -H "Authorization: Bearer YOUR_ANON_KEY" \
 -H "Content-Type: application/json" \
 -d '{
 "to": "201001383533@s.whatsapp.net",
 "message": "Message with @s.whatsapp.net format",
 "suitId": "YOUR_SUIT_ID"
 }'

Example 3: Message with Custom Sender Name (from field)

curl -X POST https://txpaxbxhnvnhsjwwaeoy.supabase.co/functions/v1/whatsapp-lite-send \
 -H "Authorization: Bearer YOUR_ANON_KEY" \
 -H "Content-Type: application/json" \
 -d '{
 "to": "201001383533",
 "message": "Hello from AIBot!",
 "suitId": "YOUR_SUIT_ID",
 "from": "AIBot"
 }'

Example 4: Message with Contact Name

curl -X POST https://txpaxbxhnvnhsjwwaeoy.supabase.co/functions/v1/whatsapp-lite-send \
 -H "Authorization: Bearer YOUR_ANON_KEY" \
 -H "Content-Type: application/json" \
 -d '{
 "to": "201001383533",
 "message": "Hello Mohamed!",
 "suitId": "YOUR_SUIT_ID",
 "contactName": "Mohamed Shaheen"
 }'

Example 5: Complete Example with All Optional Fields

curl -X POST https://txpaxbxhnvnhsjwwaeoy.supabase.co/functions/v1/whatsapp-lite-send \
 -H "Authorization: Bearer YOUR_ANON_KEY" \
 -H "Content-Type: application/json" \
 -d '{
 "to": "201001383533@s.whatsapp.net",
 "message": "Hello Mohamed from AIBot!",
 "suitId": "YOUR_SUIT_ID",
 "contactName": "Mohamed Shaheen",
 "from": "AIBot"
 }'

Example 6: Using organizationId Instead of suitId

curl -X POST https://txpaxbxhnvnhsjwwaeoy.supabase.co/functions/v1/whatsapp-lite-send \
 -H "Authorization: Bearer YOUR_ANON_KEY" \
 -H "Content-Type: application/json" \
 -d '{
 "to": "201001383533",
 "message": "Message using organizationId",
 "organizationId": "your-org-uuid-here"
 }'

Example 7: Send to Existing Conversation

curl -X POST https://txpaxbxhnvnhsjwwaeoy.supabase.co/functions/v1/whatsapp-lite-send \
 -H "Authorization: Bearer YOUR_ANON_KEY" \
 -H "Content-Type: application/json" \
 -d '{
 "to": "201001383533",
 "message": "Follow-up message",
 "suitId": "YOUR_SUIT_ID",
 "conversationId": "existing-conversation-uuid"
 }'

Example 8: Send Media (image URL with optional caption)

curl -X POST https://txpaxbxhnvnhsjwwaeoy.supabase.co/functions/v1/whatsapp-lite-send \
 -H "Authorization: Bearer YOUR_ANON_KEY" \
 -H "Content-Type: application/json" \
 -d '{
 "to": "201001383533",
 "message": "Check out this image",
 "suitId": "YOUR_SUIT_ID",
 "media_urls": ["https://example.com/image.jpg"]
 }'

Example 9: Cross-Channel Response (e.g. reply via WhatsApp Lite when original was WhatsApp Cloud)

curl -X POST https://txpaxbxhnvnhsjwwaeoy.supabase.co/functions/v1/whatsapp-lite-send \
 -H "Authorization: Bearer YOUR_ANON_KEY" \
 -H "Content-Type: application/json" \
 -d '{
 "to": "201001383533",
 "message": "Reply from Lite channel",
 "suitId": "YOUR_SUIT_ID",
 "conversationId": "existing-conversation-uuid",
 "crossChannelResponse": {
 "originalChannelId": "original-channel-account-uuid",
 "originalChannelType": "WHATSAPP_CLOUD",
 "responseChannelId": "whatsapp-lite-channel-account-uuid"
 }
 }'

appgain-whatsapp-webhook - Receiving Messages

Complete webhook documentation is in the main WHATSAPP_LITE_API_GUIDE.md file.

Common Use Cases

Use Case 1: Send Welcome Message to New Customer

curl -X POST https://txpaxbxhnvnhsjwwaeoy.supabase.co/functions/v1/whatsapp-lite-send \
 -H "Authorization: Bearer YOUR_ANON_KEY" \
 -H "Content-Type: application/json" \
 -d '{
 "to": "201001383533",
 "message": "Welcome to our service! How can we help you today?",
 "suitId": "YOUR_SUIT_ID",
 "contactName": "New Customer",
 "from": "Support Team"
 }'

Use Case 2: Send Order Confirmation as AIBot

curl -X POST https://txpaxbxhnvnhsjwwaeoy.supabase.co/functions/v1/whatsapp-lite-send \
 -H "Authorization: Bearer YOUR_ANON_KEY" \
 -H "Content-Type: application/json" \
 -d '{
 "to": "201001383533",
 "message": "Your order #12345 has been confirmed. Expected delivery: 3 days.",
 "suitId": "YOUR_SUIT_ID",
 "from": "AIBot"
 }'

Use Case 3: Follow-up Message in Existing Conversation

curl -X POST https://txpaxbxhnvnhsjwwaeoy.supabase.co/functions/v1/whatsapp-lite-send \
 -H "Authorization: Bearer YOUR_ANON_KEY" \
 -H "Content-Type: application/json" \
 -d '{
 "to": "201001383533",
 "message": "I wanted to follow up on your inquiry.",
 "suitId": "YOUR_SUIT_ID",
 "conversationId": "existing-conversation-uuid",
 "from": "Agent Sarah"
 }'

Error Handling

See main documentation for complete error handling guide.

Notes

  1. Phone Number Formats: Both functions automatically handle phone numbers with or without @s.whatsapp.net suffix
  2. Duplicate Prevention: Both functions use the same channel account lookup to prevent duplicate conversations
  3. Contact Matching: Uses multiple phone number variations to find existing contacts
  4. Sender Display: The from field is stored in metadata and can be displayed in the UI as the message sender
  5. Automatic Creation: Both contacts and conversations are automatically created if they don't exist