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

# SMS Messaging with LaraCopilot Gateways

> LaraCopilot supports SMS messaging through configurable gateways, enabling outbound message sending and inbound delivery receipt tracking.

LaraCopilot routes outbound SMS through provider-specific gateways you configure in the admin panel. Each gateway maps to one upstream SMS provider and handles authentication, transport settings, and delivery receipt (DLR) callbacks automatically. Messages sent through a gateway are recorded and tied to both the gateway and the originating tenant, giving you a full audit trail from dispatch through delivery confirmation.

## How SMS Gateways Work

Each SMS gateway represents a single upstream provider connection. When you send a message, LaraCopilot constructs the upstream endpoint from the gateway's transport fields and posts the payload using HTTP Basic Auth. The fields that control this behaviour are:

| Field               | Type        | Purpose                                                |
| ------------------- | ----------- | ------------------------------------------------------ |
| `provider_type`     | string      | Identifies the upstream provider (e.g. `smpp`, `http`) |
| `server_host`       | string      | Hostname or IP of the provider's API server            |
| `server_port`       | integer     | Port to connect on                                     |
| `api_path`          | string      | Path appended to the host, defaults to `send`          |
| `username`          | string      | HTTP Basic Auth username                               |
| `password`          | string      | HTTP Basic Auth password                               |
| `default_sender_id` | string      | Fallback sender ID when none is specified per message  |
| `callback_token`    | string      | Token used to authenticate inbound DLR callbacks       |
| `use_ssl`           | boolean     | Whether to use HTTPS (`true`) or HTTP (`false`)        |
| `is_active`         | boolean     | Gates whether the gateway accepts new send requests    |
| `meta`              | JSON object | Arbitrary provider-specific key/value pairs            |

<Note>
  Only gateways with `is_active: true` will process outbound messages. Deactivating a gateway does not affect messages already in a `submitted` state.
</Note>

## Configuring a Gateway and Sending Your First Message

<Steps>
  <Step title="Create the gateway">
    In the admin panel, navigate to **SMS → Gateways** and click **New Gateway**. Fill in `name`, `provider_type`, `server_host`, `server_port`, `username`, and `password`. Set `use_ssl` and `is_active` as appropriate for your provider, then save.
  </Step>

  <Step title="Verify the gateway is active">
    Confirm the gateway card shows `is_active: true`. If your provider requires a specific `api_path` (e.g. `/api/v2/send`), enter it in the **API Path** field — otherwise the platform defaults to `send`.
  </Step>

  <Step title="Send a message via the API">
    POST to `/api/sms-gateways/{id}/send` where `{id}` is the integer ID of the gateway. Supply the following JSON body:

    <CodeGroup>
      ```json Request body theme={null}
      {
        "to_number": "+14155550100",
        "from_sender": "LaraCopilot",
        "message": "Your verification code is 482910.",
        "tenant_id": 7,
        "callback_url": "https://your-app.example.com/webhooks/dlr"
      }
      ```

      ```json Response body theme={null}
      {
        "message": "SMS request processed.",
        "data": {
          "id": 1024,
          "sms_gateway_id": 3,
          "tenant_id": 7,
          "to_number": "+14155550100",
          "from_sender": "LaraCopilot",
          "delivery_status": "submitted",
          "direction": "outbound",
          "external_message_id": "abc-123",
          "requested_at": "2026-04-22T10:00:00Z",
          "submitted_at": "2026-04-22T10:00:01Z"
        }
      }
      ```
    </CodeGroup>

    | Parameter      | Required | Description                                                                                     |
    | -------------- | -------- | ----------------------------------------------------------------------------------------------- |
    | `to_number`    | Yes      | Destination phone number, max 30 chars                                                          |
    | `from_sender`  | Yes      | Sender ID or number shown to the recipient, max 30 chars                                        |
    | `message`      | Yes      | Message body, max 1,000 chars                                                                   |
    | `tenant_id`    | No       | Associates the message with a specific tenant                                                   |
    | `callback_url` | No       | URL to receive DLR callbacks; defaults to the platform's built-in DLR endpoint for this gateway |
  </Step>
</Steps>

## Message Statuses

Every message moves through the following `delivery_status` lifecycle:

| Status      | Meaning                                                       |
| ----------- | ------------------------------------------------------------- |
| `queued`    | Message created locally, not yet dispatched to the provider   |
| `submitted` | Provider accepted the message and returned a success response |
| `delivered` | Provider confirmed delivery to the handset via DLR callback   |
| `failed`    | Dispatch attempt failed or the provider returned an error     |

The timestamps `requested_at`, `submitted_at`, and `delivered_at` are set automatically as the message advances through each state. The raw provider response is stored in `remote_response`, and any error detail is captured in `error_message`.

## Delivery Receipts (DLR Callbacks)

When the provider delivers the message to the handset it calls the URL supplied in `callback_url` during dispatch. If you did not supply a custom URL, LaraCopilot uses its own DLR endpoint:

```
POST /api/sms-gateways/{id}/dlr
```

The endpoint looks for `message_id`, `id`, or `messageId` in the request body to match the original `SmsMessage`, then updates `delivery_status` and sets `delivered_at` to the current timestamp. The full callback payload is merged into the `remote_response` field for debugging.

<Note>
  If you supply a custom `callback_url` when sending, your server receives the DLR directly. You are responsible for forwarding it to the platform's DLR endpoint, or for updating `delivery_status` through your own logic.
</Note>

<Tip>
  Set `callback_token` on the gateway and validate it in your custom DLR handler to prevent spoofed delivery receipts from third parties.
</Tip>
