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

# REST API endpoints for conversations

> List two-way SMS conversations, retrieve message history by phone number, and send replies to contacts. Replies bypass quiet hours and go out immediately.

Conversations in Amplifi represent the two-way SMS threads between your organization and individual contacts. Each conversation is keyed by a contact's phone number and contains both inbound messages received from the contact and outbound messages sent by your team or campaigns. The conversations API lets you list active threads, fetch message history, and send replies programmatically.

## List conversations

<br />

```
GET /api/conversations
```

Returns conversation threads for your organization. Each thread represents all message activity with one phone number. By default, all conversations are returned; use query parameters to filter.

### Query parameters

<ParamField query="unread" type="boolean">
  When `true`, returns only conversations that have unread inbound messages.
</ParamField>

<ParamField query="unresponded" type="boolean">
  When `true`, returns only conversations where the last message was inbound (contact replied but your team has not yet responded).
</ParamField>

<ParamField query="search" type="string">
  Search conversations by contact name or phone number.
</ParamField>

<ParamField query="includeArchived" type="boolean">
  When `true`, includes archived conversations. Defaults to `false`.
</ParamField>

### Response

```json theme={null}
[
  {
    "phoneNumber": "+19195551234",
    "contactId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "firstName": "Jane",
    "lastName": "Smith",
    "lastMessage": "Sounds great, see you there!",
    "lastMessageAt": "2025-04-23T18:45:00.000Z",
    "unreadCount": 1,
    "isArchived": false,
    "isStarred": false
  }
]
```

## Get conversation messages

<br />

```
GET /api/conversations/:phoneNumber/messages
```

Returns the message history for a single conversation, identified by the contact's phone number. Messages are returned in reverse chronological order (newest first) using keyset pagination. Timestamps are always returned in UTC ISO 8601 format.

### Path parameters

<ParamField path="phoneNumber" type="string" required>
  The contact's phone number. Accepts any standard US format; it is normalized to E.164 internally.
</ParamField>

### Query parameters

<ParamField query="limit" type="number">
  Number of messages to return per page. Default `50`, max `200`.
</ParamField>

<ParamField query="cursor" type="string">
  Keyset pagination cursor from a previous response. Pass the `cursor` value to fetch older messages.
</ParamField>

### Response

```json theme={null}
{
  "messages": [
    {
      "id": "f6a7b8c9-d0e1-2345-fghi-678901234567",
      "direction": "incoming",
      "message": "Sounds great, see you there!",
      "mediaUrl": null,
      "mediaUrls": null,
      "status": null,
      "sentiment": "positive",
      "sentimentScore": 0.92,
      "messageCategory": "general",
      "requiresResponse": false,
      "optOutDetected": false,
      "timestamp": "2025-04-23T18:45:00.000Z"
    },
    {
      "id": "e5f6a7b8-c9d0-1234-efgh-567890123456",
      "direction": "outgoing",
      "message": "Hi Jane, just confirming your RSVP for April 28!",
      "mediaUrl": null,
      "status": "delivered",
      "timestamp": "2025-04-23T17:30:00.000Z"
    }
  ],
  "timezone": "America/New_York"
}
```

### Response fields

<ResponseField name="messages[].direction" type="string">
  `incoming` for messages received from the contact, `outgoing` for messages sent by your organization.
</ResponseField>

<ResponseField name="messages[].status" type="string | null">
  Delivery status for outgoing messages: `sent`, `delivered`, `failed`, or `undelivered`. `null` for incoming messages.
</ResponseField>

<ResponseField name="messages[].sentiment" type="string | null">
  Detected sentiment of inbound messages: `positive`, `negative`, or `neutral`. `null` if not yet analyzed.
</ResponseField>

<ResponseField name="messages[].optOutDetected" type="boolean | null">
  `true` if this inbound message was detected as an opt-out request (e.g. STOP, UNSUBSCRIBE).
</ResponseField>

<ResponseField name="messages[].requiresResponse" type="boolean | null">
  `true` if the platform has flagged this inbound message as needing a reply.
</ResponseField>

<ResponseField name="timezone" type="string">
  The organization's configured timezone, useful for displaying timestamps in local time.
</ResponseField>

## Send a reply

<br />

```
POST /api/conversations/:phoneNumber/reply
```

Sends a reply message to the contact identified by `phoneNumber`. The contact must exist in your organization and must be textable (`isTextable: true`) and opted in (`isOptedIn: true`).

Replies sent through this endpoint **bypass quiet hours** and are delivered immediately, regardless of the time of day. Use this for time-sensitive individual responses, not bulk outreach.

### Path parameters

<ParamField path="phoneNumber" type="string" required>
  The recipient's phone number. Accepts any standard US format.
</ParamField>

### Request body

<ParamField body="message" type="string" required>
  The message text to send. Must be a non-empty string.
</ParamField>

<ParamField body="fromPhoneNumberId" type="string (UUID)">
  UUID of the sending phone number. Defaults to your organization's default phone number.
</ParamField>

<ParamField body="mediaUrl" type="string">
  Public URL of media to attach. When provided, the message is sent as MMS.
</ParamField>

<ParamField body="normalizeText" type="boolean">
  When `true` (default), normalizes smart quotes and non-ASCII characters before sending.
</ParamField>

<ParamField body="forceRoute" type="string">
  Override routing: `AUTO` (default), `SMS`, or `MMS`.
</ParamField>

### Example request

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST "https://api.amplifi.com/api/conversations/%2B19195551234/reply" \
    -H "Authorization: Bearer <token>" \
    -H "x-organization-id: 3f4e5c6d-7a8b-9012-cdef-1234567890ab" \
    -H "Content-Type: application/json" \
    -d '{
      "message": "Thanks for reaching out! Our team will follow up shortly.",
      "fromPhoneNumberId": "a2b3c4d5-e6f7-8901-bcde-f23456789012"
    }'
  ```

  ```javascript fetch theme={null}
  const response = await fetch(
    "https://api.amplifi.com/api/conversations/%2B19195551234/reply",
    {
      method: "POST",
      headers: {
        "Authorization": "Bearer <token>",
        "x-organization-id": "3f4e5c6d-7a8b-9012-cdef-1234567890ab",
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        message: "Thanks for reaching out! Our team will follow up shortly.",
        fromPhoneNumberId: "a2b3c4d5-e6f7-8901-bcde-f23456789012",
      }),
    }
  );
  const result = await response.json();
  ```
</CodeGroup>

### Response

```json theme={null}
{
  "success": true,
  "messageLog": {
    "id": "g7h8i9j0-k1l2-3456-mnop-789012345678",
    "phoneNumber": "+19195551234",
    "message": "Thanks for reaching out! Our team will follow up shortly.",
    "status": "sent",
    "sentAt": "2025-04-24T10:30:00.000Z"
  },
  "provider": "twilio",
  "providerMessageId": "SM1234567890abcdef1234567890abcdef"
}
```

## Error responses

| Status | Code                   | Meaning                                                                 |
| ------ | ---------------------- | ----------------------------------------------------------------------- |
| `400`  | `CONTACT_NOT_FOUND`    | No contact exists with this phone number. Create the contact first.     |
| `400`  | `CONTACT_OPTED_OUT`    | The contact has opted out and cannot receive messages.                  |
| `400`  | `CONTACT_NON_TEXTABLE` | The contact's number is confirmed non-textable (landline, VOIP, etc.).  |
| `400`  | `NO_FROM_NUMBER`       | Your organization has no default phone number configured.               |
| `402`  | —                      | Insufficient credits to send the message.                               |
| `403`  | —                      | The specified `fromPhoneNumberId` does not belong to your organization. |

<Warning>
  If a contact's `isTextable` value is `null` (lookup pending), replies are blocked until the lookup completes. A contact that has previously sent you an inbound message is automatically marked textable.
</Warning>

<Note>
  URLs included in reply messages are automatically shortened using your organization's configured link-shortening service, enabling click tracking.
</Note>
