> ## Documentation Index
> Fetch the complete documentation index at: https://docs.linkiasoft.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Send your first message

> From a fresh API key to a delivered WhatsApp template in four calls.

This walks through the whole path: find a channel, pick a template, send it, confirm it
arrived. Every call uses the two headers from [Authentication](/authentication).

<Steps>
  <Step title="Find the channel to send from">
    `channelId` identifies which connected account the message goes out through. Get it once
    and store it — it doesn't change.

    ```bash theme={null}
    curl https://social.linkiasoft.com/api/v1/connect/channels \
      -H "x-api-key: $LINKIA_API_KEY" \
      -H "X-Tenant-Id: $LINKIA_TENANT_ID"
    ```

    ```json theme={null}
    {
      "channels": [
        {
          "id": "3f2b1a9c-0d4e-4a7b-9c1e-8f6a2b3c4d5e",
          "type": "whatsapp",
          "display_name": "Support",
          "phone_number": "201001234567",
          "connection_status": "connected"
        }
      ]
    }
    ```

    Use a channel whose `connection_status` is `connected`. Anything else cannot send.
  </Step>

  <Step title="Pick an approved template">
    ```bash theme={null}
    curl "https://social.linkiasoft.com/api/v1/templates?channelId=$CHANNEL_ID" \
      -H "x-api-key: $LINKIA_API_KEY" \
      -H "X-Tenant-Id: $LINKIA_TENANT_ID"
    ```

    ```json theme={null}
    {
      "templates": [
        {
          "name": "ticket_resolved",
          "language": "ar",
          "status": "APPROVED",
          "category": "UTILITY",
          "components": [
            { "type": "BODY", "text": "مرحباً {{1}}، تم حل تذكرتك رقم {{2}}." }
          ]
        }
      ]
    }
    ```

    Two things to read off this:

    * **`status` must be `APPROVED`.** A `PENDING` template is rejected at send time.
    * **Count the placeholders in the `BODY` text.** `{{1}}` and `{{2}}` means you must supply
      exactly two `templateParams`, in that order. A mismatch fails the send.
  </Step>

  <Step title="Send it">
    ```bash theme={null}
    curl -X POST https://social.linkiasoft.com/api/v1/conversations/send \
      -H "x-api-key: $LINKIA_API_KEY" \
      -H "X-Tenant-Id: $LINKIA_TENANT_ID" \
      -H "Content-Type: application/json" \
      -d '{
        "channelId": "3f2b1a9c-0d4e-4a7b-9c1e-8f6a2b3c4d5e",
        "to": "201001234567",
        "contactName": "Ahmed Hassan",
        "template": {
          "templateName": "ticket_resolved",
          "templateLanguage": "ar",
          "templateParams": ["Ahmed", "4821"]
        }
      }'
    ```

    You get `202 Accepted` and the created message:

    ```json theme={null}
    {
      "id": "9a8b7c6d-5e4f-4a3b-2c1d-0e9f8a7b6c5d",
      "conversation_id": "7c8d9e0f-1a2b-3c4d-5e6f-7a8b9c0d1e2f",
      "direction": "outbound",
      "type": "template",
      "status": "sent",
      "created_at": "2026-07-24T21:14:07.221Z"
    }
    ```

    <Warning>
      `to` must be **E.164 without a `+`** — `201001234567`. A local-format number like
      `01001234567` is not rejected; it is simply undelivered. Normalize before you send.
    </Warning>

    You didn't need a conversation to exist first: `channelId` + `to` finds the thread or
    starts one. If you already have a `conversationId`, send that instead and omit both.
  </Step>

  <Step title="Confirm it arrived">
    `202` means queued, not delivered. Read the message back to see where it got to:

    ```bash theme={null}
    curl "https://social.linkiasoft.com/api/v1/conversations/$CONVERSATION_ID/messages?limit=1" \
      -H "x-api-key: $LINKIA_API_KEY" \
      -H "X-Tenant-Id: $LINKIA_TENANT_ID"
    ```

    | `status`    | Meaning                                              |
    | ----------- | ---------------------------------------------------- |
    | `pending`   | Queued, not yet handed to the platform               |
    | `sent`      | Accepted by the platform                             |
    | `delivered` | Reached the customer's device                        |
    | `read`      | Opened — only when the customer has read receipts on |
    | `failed`    | Terminal. `error_reason` explains why.               |

    Poll for a short window, or treat `sent` as success and reconcile `failed` separately.
    Don't wait on `read` — plenty of customers have receipts disabled and it will never arrive.
  </Step>
</Steps>

## Sending plain text

Inside the 24-hour window — the customer messaged you recently — you can reply in free
text:

```json theme={null}
{
  "conversationId": "7c8d9e0f-1a2b-3c4d-5e6f-7a8b9c0d1e2f",
  "text": "Thanks — that's all sorted."
}
```

Outside that window this is rejected by WhatsApp. If your integration initiates contact,
send a template.

## Next

<Card title="Zoho Desk: message customers when a ticket closes" icon="ticket" href="/guides/zoho-ticket-closed">
  A complete worked integration, including the flat payload form for callers that can't
  send nested JSON.
</Card>
