---
sidebar_position: 14
title: Messages (SMS/MMS)
description: Send SMS and MMS messages, query message history, and filter messaging logs via the Firetell REST API.
---

# Messages (SMS/MMS)

Send outbound SMS and MMS messages, retrieve message logs, and inspect delivery statuses using your workspace phone numbers.

Firetell handles carrier dispatch, delivery receipts (DLR), and real-time event updates via [Webhooks](/docs/webhooks/overview) and [Server-Sent Events (SSE)](/docs/rest-api/agent-api/realtime-events).

---

## Endpoints

| Method | Endpoint         | Description                                        |
| ------ | ---------------- | -------------------------------------------------- |
| `POST` | `/messages/send` | Send an outbound SMS or MMS message                |
| `GET`  | `/messages`      | List message history with filters and pagination   |
| `GET`  | `/messages/:id`  | Retrieve detailed information for a single message |

---

## The Message Object

| Field             | Type       | Description                                                                           |
| ----------------- | ---------- | ------------------------------------------------------------------------------------- |
| `id`              | `string`   | Unique message identifier prefixed with `msg_` (e.g. `msg_05f18045cba1452204774f`)    |
| `workspace_id`    | `string`   | Workspace identifier (e.g. `yourcompany`)                                             |
| `phone_number_id` | `string`   | Identifier of the workspace phone number used (`pn_...`)                              |
| `from`            | `string`   | Sender phone number in E.164 format (e.g. `+13074295456`)                             |
| `to`              | `string`   | Recipient phone number in E.164 format (e.g. `+18647123123`)                          |
| `body`            | `string`   | Text content of the message (up to 1,600 characters)                                  |
| `direction`       | `string`   | Direction of the message: `outbound` or `inbound`                                     |
| `status`          | `string`   | Current delivery status (see [Message Statuses](#message-statuses))                   |
| `cost`            | `number`   | Total cost charged in USD including platform markup (or `null` if inbound or pending) |
| `media_urls`      | `string[]` | Array of media attachment URLs for MMS messages                                       |
| `error_code`      | `string`   | Error code returned by carrier if sending/delivery failed (e.g. `40001`, or `null`)   |
| `error_message`   | `string`   | Human-readable error message explaining failure reason (or `null`)                    |
| `created_at`      | `string`   | ISO 8601 creation timestamp                                                           |
| `updated_at`      | `string`   | ISO 8601 last update timestamp                                                        |

### Message Statuses

| Status        | Direction  | Description                                                                     |
| ------------- | ---------- | ------------------------------------------------------------------------------- |
| `queued`      | `outbound` | Message has been accepted by Firetell and queued for carrier delivery.          |
| `sending`     | `outbound` | Message is currently being processed by the carrier adapter.                    |
| `sent`        | `outbound` | Carrier has accepted and dispatched the message to the destination network.     |
| `delivered`   | `outbound` | Delivery Receipt (DLR) received confirming delivery to the recipient's handset. |
| `failed`      | `outbound` | Message could not be sent or delivered (see `error_code` and `error_message`).  |
| `undelivered` | `outbound` | Carrier could not confirm delivery within the standard timeout window.          |
| `received`    | `inbound`  | Incoming SMS/MMS received on your workspace phone number.                       |

---

## Send Message

```http
POST /messages/send
```

Queue an outbound SMS or MMS message for delivery.

### Authentication

Requires `ApiKey` with `owner` or `editor` role.

### Request Headers

| Header          | Type     | Description              |
| --------------- | -------- | ------------------------ |
| `Authorization` | `string` | `ApiKey sk-YOUR_API_KEY` |
| `Content-Type`  | `string` | `application/json`       |

### Request Body

| Field        | Type       | Required | Description                                                                                  |
| ------------ | ---------- | -------- | -------------------------------------------------------------------------------------------- |
| `from`       | `string`   | Yes      | Sender phone number in E.164 format. Must belong to the workspace and have `sms` capability. |
| `to`         | `string`   | Yes      | Destination phone number in E.164 format.                                                    |
| `body`       | `string`   | Yes      | Text content of the message (maximum 1,600 characters).                                      |
| `media_urls` | `string[]` | No       | Array of publicly accessible media URLs (JPEG, PNG, GIF, audio) to send as an MMS message.   |

### Requirements & Validations

1. **Phone Number Capability**: The sender number specified in `from` must belong to your workspace and have `sms` listed in its `capabilities`.
2. **Account Credit Balance**: Your workspace must maintain an available credit balance of at least `$0.01` to initiate outbound SMS sends.
3. **Format**: Phone numbers must adhere to the standard international [E.164](https://en.wikipedia.org/wiki/E.164) format (e.g. `+13074295456`).

### Rate Limiting

The `POST /messages/send` endpoint operates on a dedicated **SMS** rate limit tier:

| Tier | Window | Limit | Scope |
| ---- | ------ | ----- | ----- |
| `sms` | 60 seconds (1 min) | **30 req/min** | Per API Key (`ApiKey`) or agent/user account |

This dedicated quota prevents outbound SMS sending from exhausting your workspace's general REST API rate limit (100 req/min).

:::note
**Need higher limits?**

Enterprise customers can request custom rate limits. Contact us at [enterprise@firetell.com](mailto:enterprise@firetell.com) with your workspace ID and use case.
:::

### Example Request

```bash
curl -X POST "https://{workspace_id}.firetell.app/api/v1/messages/send" \
  -H "Authorization: ApiKey sk-YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "+13074295456",
    "to": "+18647123123",
    "body": "Your appointment is confirmed for tomorrow at 10:00 AM."
  }'
```

### Example Request with MMS Media

```bash
curl -X POST "https://{workspace_id}.firetell.app/api/v1/messages/send" \
  -H "Authorization: ApiKey sk-YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "+13074295456",
    "to": "+18647123123",
    "body": "Here is your digital receipt.",
    "media_urls": [
      "https://storage.yourcompany.com/receipts/inv_9981.png"
    ]
  }'
```

### Response (`201 Created`)

```json
{
  "id": "msg_05f18045cba1452204774f",
  "workspace_id": "yourcompany",
  "phone_number_id": "pn_e71c8caddbe5603f1d0522",
  "from": "+13074295456",
  "to": "+18647123123",
  "body": "Your appointment is confirmed for tomorrow at 10:00 AM.",
  "direction": "outbound",
  "status": "queued",
  "media_urls": [],
  "cost": null,
  "error_code": null,
  "error_message": null,
  "created_at": "2026-09-26T00:00:00.000Z",
  "updated_at": "2026-09-26T00:00:00.000Z"
}
```

:::tip
**Delivery Tracking**

When you submit a message, it is returned immediately with `status: "queued"`. You do not need to poll for updates — register a [Webhook](/docs/rest-api/workspace-api/webhooks) for `message.sent` and `message.delivered` to receive real-time carrier delivery confirmations.
:::

---

## List Messages

```http
GET /messages
```

Retrieve a paginated history of all inbound and outbound messages with rich search and filtering options.

### Authentication

Requires `ApiKey` with any scope.

### Query Parameters

| Parameter         | Type     | Default      | Description                                                                                         |
| ----------------- | -------- | ------------ | --------------------------------------------------------------------------------------------------- |
| `page`            | `number` | `1`          | Page number (minimum: 1).                                                                           |
| `limit`           | `number` | `20`         | Number of records per page (maximum: 100).                                                          |
| `search`          | `string` | —            | Case-insensitive search matching sender (`from`), recipient (`to`), or text content (`body`).       |
| `direction`       | `string` | —            | Filter by direction: `outbound` or `inbound`.                                                       |
| `status`          | `string` | —            | Filter by status: `queued`, `sending`, `sent`, `delivered`, `failed`, `undelivered`, or `received`. |
| `phone_number_id` | `string` | —            | Filter messages associated with a specific workspace phone number ID (`pn_...`).                    |
| `from`            | `string` | —            | Filter messages created on or after this ISO 8601 date (e.g. `2026-09-01T00:00:00Z`).               |
| `to_date`         | `string` | —            | Filter messages created on or before this ISO 8601 date (e.g. `2026-09-30T23:59:59Z`).              |
| `sort_field`      | `string` | `created_at` | Sort field. Allowed values: `created_at`, `updated_at`, `status`.                                   |
| `sort_order`      | `string` | `desc`       | Sort order: `asc` (oldest first) or `desc` (newest first).                                          |

### Example Request

Filter for all delivered outbound messages sent in September 2026:

```bash
curl -X GET "https://{workspace_id}.firetell.app/api/v1/messages?direction=outbound&status=delivered&from=2026-09-01T00:00:00Z&page=1&limit=20" \
  -H "Authorization: ApiKey sk-YOUR_API_KEY"
```

### Search Example

Search messages containing a specific customer phone number or keyword:

```bash
curl -X GET "https://{workspace_id}.firetell.app/api/v1/messages?search=appointment&limit=10" \
  -H "Authorization: ApiKey sk-YOUR_API_KEY"
```

### Response (`200 OK`)

```json
{
  "data": [
    {
      "id": "msg_05f18045cba1452204774f",
      "workspace_id": "yourcompany",
      "phone_number_id": "pn_e71c8caddbe5603f1d0522",
      "from": "+13074295456",
      "to": "+18647123123",
      "body": "Your appointment is confirmed for tomorrow at 10:00 AM.",
      "direction": "outbound",
      "status": "delivered",
      "cost": 0.0048,
      "media_urls": [],
      "error_code": null,
      "error_message": null,
      "created_at": "2026-09-26T00:00:00.000Z",
      "updated_at": "2026-09-26T00:00:05.000Z"
    },
    {
      "id": "msg_be52701819fa34a72ae414",
      "workspace_id": "yourcompany",
      "phone_number_id": "pn_99bf875464f1c096f46aff",
      "from": "+18647123123",
      "to": "+13074295456",
      "body": "Thank you! Can I reschedule for 11:00 AM instead?",
      "direction": "inbound",
      "status": "received",
      "cost": null,
      "media_urls": [],
      "error_code": null,
      "error_message": null,
      "created_at": "2026-09-26T00:01:10.000Z",
      "updated_at": "2026-09-26T00:01:10.000Z"
    }
  ],
  "meta": {
    "total": 2,
    "page": 1,
    "limit": 20,
    "total_pages": 1
  }
}
```

---

## Get Message

```http
GET /messages/:id
```

Retrieve details and delivery status for a specific message by its unique ID.

### Authentication

Requires `ApiKey` with any scope.

### Path Parameters

| Parameter | Type     | Required | Description                                             |
| --------- | -------- | -------- | ------------------------------------------------------- |
| `id`      | `string` | Yes      | Message identifier (e.g. `msg_05f18045cba1452204774f`). |

### Example Request

```bash
curl -X GET "https://{workspace_id}.firetell.app/api/v1/messages/msg_05f18045cba1452204774f" \
  -H "Authorization: ApiKey sk-YOUR_API_KEY"
```

### Response (`200 OK`)

```json
{
  "id": "msg_05f18045cba1452204774f",
  "workspace_id": "yourcompany",
  "phone_number_id": "pn_e71c8caddbe5603f1d0522",
  "from": "+13074295456",
  "to": "+18647123123",
  "body": "Your appointment is confirmed for tomorrow at 10:00 AM.",
  "direction": "outbound",
  "status": "delivered",
  "cost": 0.0048,
  "media_urls": [],
  "error_code": null,
  "error_message": null,
  "created_at": "2026-09-26T00:00:00.000Z",
  "updated_at": "2026-09-26T00:00:05.000Z"
}
```

### Error Responses

#### `404 Not Found`

Returned when the message ID does not exist in the requested workspace:

```json
{
  "statusCode": 404,
  "message": "Message msg_invalid_id not found",
  "error": "Not Found"
}
```

---

## Webhook Notifications

Configure your system to receive real-time HTTP callbacks whenever messaging events occur. See the [Webhook Event Catalog](/docs/webhooks/event-catalog) for sample event payloads:

| Event                 | Trigger                                                                       |
| --------------------- | ----------------------------------------------------------------------------- |
| `message.received`    | An inbound SMS/MMS is received on your workspace phone number.                |
| `message.sent`        | An outbound message was accepted and sent to the carrier network.             |
| `message.delivered`   | A delivery receipt (DLR) confirmed successful delivery to the recipient.      |
| `message.failed`      | An outbound message failed to send or deliver (includes carrier error codes). |
| `message.undelivered` | Delivery could not be confirmed by the carrier within the receipt window.     |
