> ## 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 campaign management

> Create, schedule, and send SMS/MMS campaigns to contacts or segments. Manage campaign lifecycle from draft through completion with the Amplifi campaigns API.

Campaigns are the primary way to send bulk outbound SMS or MMS messages to an audience in Amplifi. Each campaign targets an audience defined by a saved segment (`segmentId`) or an ad-hoc contact filter (`contactFilter`), and carries a message body plus optional media URL for MMS. Campaigns move through a lifecycle of statuses—from `draft` to `completed`—and can be scheduled for a future time or sent immediately.

## Campaign statuses

| Status      | Description                                                |
| ----------- | ---------------------------------------------------------- |
| `draft`     | Being composed; not yet submitted for sending.             |
| `scheduled` | Approved and queued to send at `scheduledFor`.             |
| `pending`   | Submitted for sending; awaiting queue admission.           |
| `queued`    | Admitted to the send queue; messages being generated.      |
| `sending`   | Messages actively being dispatched.                        |
| `completed` | All messages sent or failed; no further processing.        |
| `failed`    | The campaign failed to start or encountered a fatal error. |
| `paused`    | Sending paused mid-campaign; can be resumed.               |

## List campaigns

<br />

```
GET /api/campaigns
```

Returns all campaigns for your organization ordered by creation date descending. Each campaign in the list includes summary metrics (sent count, failed count, delivery rate) computed at query time.

### Response

```json theme={null}
[
  {
    "id": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
    "name": "April Fundraiser Blast",
    "status": "completed",
    "channel": "text",
    "scheduledFor": null,
    "timezone": null,
    "totalCount": 4200,
    "sentCount": 4187,
    "failedCount": 13,
    "queuedCount": 0,
    "deliveryRate": 100,
    "replyCountExcludingOptouts": 312,
    "message": "Hi {{firstName}}, join us April 28 for our annual fundraiser! Reply STOP to opt out.",
    "mediaUrl": null,
    "createdAt": "2025-04-20T13:00:00.000Z",
    "updatedAt": "2025-04-20T15:43:00.000Z",
    "completedAt": "2025-04-20T15:43:00.000Z"
  }
]
```

## Create a campaign

<br />

```
POST /api/campaigns
```

Creates and immediately submits a campaign for sending (or schedules it if `scheduledFor` is provided). You must supply either `segmentId` or `contactFilter` to define the audience, but not both.

<Note>
  To save a campaign as a draft without sending, use `POST /api/campaigns/draft` instead.
</Note>

### Request body

<ParamField body="name" type="string" required>
  Display name for the campaign (e.g. `"April Fundraiser Blast"`).
</ParamField>

<ParamField body="message" type="string" required>
  The message body to send. Supports merge fields: `{{firstName}}`, `{{lastName}}`, `{{email}}`, `{{phone}}`, `{{city}}`, `{{state}}`, `{{zip}}`, and any custom fields.
</ParamField>

<ParamField body="segmentId" type="string (UUID)">
  UUID of a saved segment to use as the audience. Mutually exclusive with `contactFilter`.
</ParamField>

<ParamField body="contactFilter" type="object">
  Ad-hoc filter defining the audience. Mutually exclusive with `segmentId`. Common structure: `{ "tags": ["vip"], "tagsLogic": "AND" }`.
</ParamField>

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

<ParamField body="scheduledFor" type="string (ISO 8601 datetime)">
  When to send the campaign. If omitted or in the past, the campaign is sent immediately. Must be in UTC.
</ParamField>

<ParamField body="timezone" type="string">
  IANA timezone string for display purposes (e.g. `America/New_York`). Quiet hours (8 AM–9 PM) are enforced in this timezone.
</ParamField>

<ParamField body="mediaUrl" type="string">
  Public URL of media to attach. When present, the campaign is sent as MMS regardless of `forceRoute`.
</ParamField>

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

<ParamField body="channel" type="string">
  Channel type. Currently `text` is the only supported value.
</ParamField>

<ParamField body="normalizeText" type="boolean">
  When `true` (default), smart quotes and other Unicode characters are normalized to ASCII to avoid multi-segment messages.
</ParamField>

<ParamField body="isAbTest" type="boolean">
  Enable A/B testing. When `true`, you must provide `messageVariantA` and `messageVariantB`.
</ParamField>

<ParamField body="messageVariantA" type="string">
  Message body for A/B test variant A (sent to a 5% sample).
</ParamField>

<ParamField body="messageVariantB" type="string">
  Message body for A/B test variant B (sent to a 5% sample).
</ParamField>

<ParamField body="autoReplyEnabled" type="boolean">
  Enable automatic replies to inbound responses. When `true`, configure `yesResponse`, `noResponse`, or `faqReplies`.
</ParamField>

<ParamField body="yesResponse" type="string">
  Auto-reply message when a contact replies with an affirmative response.
</ParamField>

<ParamField body="noResponse" type="string">
  Auto-reply message when a contact replies with a negative response.
</ParamField>

<ParamField body="faqReplies" type="object[]">
  Up to 5 FAQ reply pairs. Each object: `{ "question": "string", "answer": "string" }`.
</ParamField>

<ParamField body="draftId" type="string (UUID)">
  UUID of an existing draft campaign to promote to a live campaign. The draft is updated in place rather than creating a new record.
</ParamField>

### Example request

```json theme={null}
{
  "name": "April Fundraiser Blast",
  "message": "Hi {{firstName}}, join us April 28 for our annual fundraiser. RSVP at https://example.com/rsvp — Reply STOP to opt out.",
  "segmentId": "c3d4e5f6-a7b8-9012-cdef-234567890123",
  "scheduledFor": "2025-04-28T13:00:00.000Z",
  "timezone": "America/New_York",
  "autoReplyEnabled": true,
  "yesResponse": "Great, we'll see you there!",
  "noResponse": "No worries, we'll keep you updated."
}
```

### Response

Returns the created campaign object with status `201`.

```json theme={null}
{
  "id": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
  "name": "April Fundraiser Blast",
  "status": "scheduled",
  "channel": "text",
  "message": "Hi {{firstName}}, join us April 28...",
  "mediaUrl": null,
  "segmentId": "c3d4e5f6-a7b8-9012-cdef-234567890123",
  "contactFilter": null,
  "scheduledFor": "2025-04-28T13:00:00.000Z",
  "timezone": "America/New_York",
  "totalCount": 0,
  "sentCount": 0,
  "failedCount": 0,
  "queuedCount": 0,
  "forceRoute": "AUTO",
  "normalizeText": true,
  "isAbTest": false,
  "autoReplyEnabled": true,
  "createdAt": "2025-04-24T10:15:00.000Z",
  "updatedAt": "2025-04-24T10:15:00.000Z"
}
```

## Get a campaign

<br />

```
GET /api/campaigns/:id
```

Returns the full campaign record including real-time delivery metrics and the associated sending phone number.

### Path parameters

<ParamField path="id" type="string (UUID)" required>
  The campaign's UUID.
</ParamField>

### Response

In addition to all campaign fields, the response includes:

<ResponseField name="phoneNumber" type="object | null">
  Details of the phone number used to send the campaign, or `null` if not yet assigned.
</ResponseField>

<ResponseField name="displayMetrics" type="object">
  Computed display metrics including audience size, sent/failed/queued counts, and delivery rate.
</ResponseField>

## Update a draft campaign

<br />

```
PUT /api/campaigns/:id/draft
```

Updates a campaign that has `status: "draft"`. All fields from the campaign draft schema are accepted and are optional—send only those you want to change. Returns `400` if the campaign is not in `draft` status.

### Path parameters

<ParamField path="id" type="string (UUID)" required>
  UUID of the draft campaign to update.
</ParamField>

## Send a campaign immediately

<br />

```
POST /api/campaigns/:id/test-send
```

Sends a test copy of the campaign to a specified list of phone numbers without affecting the campaign's audience or metrics. Useful for previewing message rendering with actual merge fields.

<Note>
  To trigger production sending of a campaign that is in `draft` status, use `POST /api/campaigns` with `draftId` set to the draft's UUID.
</Note>

### Request body

<ParamField body="recipients" type="string[]" required>
  Array of E.164 phone numbers to receive the test message.
</ParamField>

<ParamField body="body" type="string">
  Message body to send. Defaults to the campaign's current message.
</ParamField>

<ParamField body="mediaUrls" type="string[]">
  Media URLs for MMS test sends.
</ParamField>

<ParamField body="fromPhoneNumberId" type="string (UUID)">
  Override the sending phone number for this test.
</ParamField>

<ParamField body="mergePreviewData" type="object">
  Key-value pairs substituted into merge fields for the preview (e.g. `{ "firstName": "Alex" }`).
</ParamField>

## Key fields reference

<ResponseField name="forceRoute" type="string">
  `AUTO`, `SMS`, or `MMS`. Controls how message routing is decided. `AUTO` sends as MMS only when `mediaUrl` is present or the message contains characters that require it.
</ResponseField>

<ResponseField name="normalizeText" type="boolean">
  When `true`, smart quotes, em dashes, and other non-ASCII characters are replaced with their ASCII equivalents before sending to maximize message segment efficiency.
</ResponseField>

<ResponseField name="sentCount" type="number">
  Number of messages that have been dispatched to the carrier. Does not indicate delivery confirmation.
</ResponseField>

<ResponseField name="failedCount" type="number">
  Number of messages that failed to send, including carrier rejections and invalid numbers.
</ResponseField>

<ResponseField name="replyCountExcludingOptouts" type="number">
  Count of inbound replies received after the campaign started, excluding opt-out messages.
</ResponseField>

<Warning>
  Campaigns cannot be sent outside of quiet hours (8 AM–9 PM in the campaign's timezone). Attempting to send outside this window will return an error. Schedule campaigns in advance to avoid unexpected failures.
</Warning>
