# Message API - Insert

Use this endpoint to create a new draft message in your account. To create a message and send it in one request, see [Create and send](https://envoke-developers.pages.dev/v2/messages/sending/#create-and-send).

---

## Endpoint

```
POST https://e1.envoke.com/v2/messages
```

Authentication is via HTTP Basic Auth using your API ID and API Key. The request body must be a single JSON object.

---

## Request Body

| Field | Type | Required | Description |
|---|---|---|---|
| `html` | string | One of `html` or `template_id` | The message HTML. Max 200 kB. |
| `template_id` | integer | One of `html` or `template_id` | ID of a template or message to copy the HTML from. Ignored when `html` is also sent. |
| `replace` | object | No | Placeholder text to replace in the HTML before it is saved. |
| `name` | string | No | Internal name. At least 3 characters. |
| `group` | string | No | Name or ID of an existing message group. |
| `subject` | string | No | Subject line. At least 6 characters. Required to send. |
| `sender` | string | No | Identity ID, `Name <email>`, or email address. Defaults to the account's default sender. |
| `reply_to` | string | No | Identity ID, `Name <email>`, or email address. |
| `language` | string | No | `en` or `fr`. Defaults to `en`. |
| `recipient_subscription` | string | No | Name or ID of a subscription. |
| `recipient_tag` | string | No | Name or ID of a tag. Not with `recipient_segment`. |
| `recipient_segment` | string | No | Name or ID of a segment. Not with `recipient_tag`. |
| `recipient_language` | string | No | `en` or `fr`: send only to contacts with that language. |
| `publish_archive` | boolean | No | Publish the message to the web archive. Defaults to `false`. |
| `utm_tag_links` | boolean | No | Add UTM parameters to links. Defaults to your account's link analytics setting. |
| `send_time` | string | No | A future account-local time, e.g. `2026-10-20 09:00:00`. Stored only; it does not schedule the message. |

Only `html` or `template_id` is required. A message can be created without a subject, sender, or recipients; they are checked when it is [sent](https://envoke-developers.pages.dev/v2/messages/sending/#send-a-draft).

`id`, `external_id`, `preview_url`, `create_time`, `modified_time`, and `status` are read-only and silently ignored. Any other key fails with `'headline' is not a valid field`. See the [Fields reference](https://envoke-developers.pages.dev/v2/messages/fields/) for accepted values and the full rules for each field.

### Defaults

| Field | Value when not sent |
|---|---|
| `name` | `API Message {Y-m-d H:i:s}`, from the time of the request in Envoke's server time |
| `status` | `Draft` |
| `group` | `""` (no group) |
| `sender` | The account's default sender identity |
| `reply_to` | Not set (`null`) |
| `subject` | `""` |
| `language` | `en` |
| `recipient_subscription`, `recipient_tag`, `recipient_segment`, `recipient_language` | `""` |
| `publish_archive` | `false` |
| `utm_tag_links` | `true` if link analytics is on in your account preferences, otherwise `false` |
| `send_time` | `""` |

A message created with `send_time` stays a `Draft`. The stored time is used when the message is later sent without a new `send_time`.

---

## Response

On success, the API returns the new message in full, in the same shape as a [read](https://envoke-developers.pages.dev/v2/messages/read/#response):

```json
{
  "success": true,
  "result_text": "Created",
  "result_data": {
    "id": "2001",
    "external_id": "3e8b1f6c9a2d4e7b0c5f8a1d3e6b9c2f",
    "preview_url": "https://engage.envoke.com/m/a7c3e9f1b5d2/m/3e8b1f6c9a2d4e7b0c5f8a1d3e6b9c2f",
    "create_time": "2026-10-06 10:15:42",
    "modified_time": "2026-10-06 10:15:42",
    "name": "Spring Season Announcement",
    "group": "Productions",
    "status": "Draft",
    "send_time": "",
    "sender": "Box Office <boxoffice@example.org>",
    "reply_to": "Front of House <frontofhouse@example.org>",
    "subject": "Our spring season is here",
    "language": "en",
    "recipient_subscription": "Season News",
    "recipient_tag": "",
    "recipient_segment": "",
    "recipient_language": "",
    "publish_archive": true,
    "utm_tag_links": true
  }
}
```

`result_data.id` is the Envoke message ID, as a string. Store it to update, send, cancel, or delete the message later. The HTML is not included; use `GET /v2/messages/{id}?include_html=1` to read it back.

---

## Validation Errors

```json
{
  "success": false,
  "result_text": "Validation failed, see 'result_data' -> 'errors'",
  "result_data": {
    "errors": [
      "One of the fields 'template_id' or 'html' must be provided in order to create a message"
    ]
  }
}
```

The checks run in the order below. The first six each return on their own, with a single error. The field checks after them are collected and returned together.

| Order | Error | Cause |
|---|---|---|
| 1 | `Request body may not be empty` | No body, an empty body, or `{}`. |
| 2 | `The field 'html' may not be longer than 200kB` | `html` is over 204,800 bytes. |
| 3 | `Nothing found for 'template_id': 1999` | No template or message with that ID is available to your account. |
| 4 | `One of the fields 'template_id' or 'html' must be provided in order to create a message` | Neither field was sent, or `html` is `""`. |
| 5 | `Only one of the fields 'recipient_tag' or 'recipient_segment' may be provided` | Both were sent. |
| 6 | `Invalid 'replace' data` | `replace` is not an object of strings whose keys are wrapped in `{` `}`, or a key targets a preference or consent link. |
| 7 | `'headline' is not a valid field` | The body has a key that is not a message field. |
| 7 | `The field 'name' must be at least 3 characters long` | `name` is too short. |
| 7 | `The field 'subject' must be at least 6 characters long` | `subject` is too short. |
| 7 | `Invalid 'group': 'Playbills'` | No message group has that name or ID. Includes `allowed_values`. |
| 7 | `Invalid 'sender': 'Box Office'` | Not an identity ID, `Name <email>`, or email address. `reply_to` gives `Invalid 'reply_to': ...`. Includes `allowed_values`. |
| 7 | `No sender identity found for email: 'tickets@example.org'` | No identity has that exact address. `reply_to` gives `No reply_to identity found for email: ...`. Includes `allowed_values`. |
| 7 | `Invalid 'language': 'de'` | Not `en`, `fr`, `1`, or `3`. Also for `recipient_language`. Includes `allowed_values`. |
| 7 | `Invalid 'recipient_tag': 'Cast List'` | No tag with that name or ID. Also for `recipient_subscription` and `recipient_segment`. Includes `allowed_values`. |
| 7 | `The field 'send_time' must be in the future` | `send_time` is in the past. |
| 7 | `Invalid 'send_time': 'next Friday evening'` | `send_time` could not be read as a date. |

`allowed_values` lists the valid options for the field, keyed by ID, when your account has 50 or fewer of them (see [Error Responses](https://envoke-developers.pages.dev/v2/messages/fields/#error-responses)).

Two server-side failures use the plain envelope (`result_data: []`) instead: `Message content error` when the content could not be saved, and `insert error: ` followed by the database error when the message could not be saved. A body that is not valid JSON returns `Invalid JSON` in the same shape.

---

## Examples

### Create a message from HTML

```bash
curl -X POST -gs \
  -u "$API_ID:$API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"html": "<html><body><h1>Auditions Open</h1><p>Auditions for our spring production start Monday.</p></body></html>"}' \
  "https://e1.envoke.com/v2/messages"
```

The message is created as a `Draft` named `API Message 2026-10-06 10:12:05`, with the account's default sender, no subject, and no recipients.

### Create a complete message

```bash
curl -X POST -gs \
  -u "$API_ID:$API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Spring Season Announcement", "group": "Productions", "subject": "Our spring season is here", "sender": "boxoffice@example.org", "reply_to": 413, "language": "en", "recipient_subscription": "Season News", "publish_archive": true, "utm_tag_links": true, "html": "<html><body><h1>Spring Season</h1><p>Four shows, one season pass.</p></body></html>"}' \
  "https://e1.envoke.com/v2/messages"
```

`sender` is matched by email address and `reply_to` by identity ID; both are returned as `Name <email>` (see [Response](#response)). The message is ready to [send](https://envoke-developers.pages.dev/v2/messages/sending/#send-a-draft).

### Create a message from a template

```bash
curl -X POST -gs \
  -u "$API_ID:$API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Auditions Reminder", "template_id": 1901, "subject": "Auditions start Monday", "recipient_tag": "Cast Call"}' \
  "https://e1.envoke.com/v2/messages"
```

Only the template's HTML is copied. The subject and recipients come from this request.

### Fill in a template's placeholders

The template `Playbill Template` (ID `1901`) contains the placeholders `{SHOW_TITLE}` and `{CURTAIN_TIME}`:

```bash
curl -X POST -gs \
  -u "$API_ID:$API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Pirates of Penzance - Opening Night", "template_id": 1901, "subject": "Opening night is almost here", "replace": {"{SHOW_TITLE}": "The Pirates of Penzance", "{CURTAIN_TIME}": "7:30 p.m."}}' \
  "https://e1.envoke.com/v2/messages"
```

The message HTML is saved with the placeholders already replaced. The template itself is unchanged.

### Fill in your own HTML

```bash
curl -X POST -gs \
  -u "$API_ID:$API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Opening Date Notice", "html": "<html><body><p>Dear patron, {SHOW_TITLE} opens on {OPENING_DATE}.</p></body></html>", "replace": {"{SHOW_TITLE}": "The Pirates of Penzance", "{OPENING_DATE}": "Friday, October 23"}}' \
  "https://e1.envoke.com/v2/messages"
```

### Send to a subscription, narrowed by a tag

```bash
curl -X POST -gs \
  -u "$API_ID:$API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Cast Party Invitation", "subject": "You are invited to the cast party", "recipient_subscription": "Season News", "recipient_tag": "Cast Call", "html": "<html><body><p>Join us after the final show.</p></body></html>"}' \
  "https://e1.envoke.com/v2/messages"
```

When sent, the message goes only to contacts who have the `Cast Call` tag and are subscribed to `Season News`.

### Create a draft with a send time

```bash
curl -X POST -gs \
  -u "$API_ID:$API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Subscriber Presale", "subject": "Presale opens Tuesday at 9", "recipient_subscription": "Season News", "send_time": "2026-10-20 09:00:00", "html": "<html><body><p>Subscribers get first pick of seats.</p></body></html>"}' \
  "https://e1.envoke.com/v2/messages"
```

The message is a `Draft` with `send_time` `"2026-10-20 09:00:00"` (9:00 a.m. in the account time zone). It is not scheduled until it is [sent](https://envoke-developers.pages.dev/v2/messages/sending/#send-a-draft).

### Missing content

```bash
curl -X POST -gs \
  -u "$API_ID:$API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Spring Season Announcement"}' \
  "https://e1.envoke.com/v2/messages"
```

Returns the validation error shown under [Validation Errors](#validation-errors).

### Tag and segment together

```bash
curl -X POST -gs \
  -u "$API_ID:$API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"html": "<html><body><p>Hello</p></body></html>", "recipient_tag": "Cast Call", "recipient_segment": "Lapsed Subscribers"}' \
  "https://e1.envoke.com/v2/messages"
```

```json
{
  "success": false,
  "result_text": "Validation failed, see 'result_data' -> 'errors'",
  "result_data": {
    "errors": ["Only one of the fields 'recipient_tag' or 'recipient_segment' may be provided"]
  }
}
```

### Unknown group

```bash
curl -X POST -gs \
  -u "$API_ID:$API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"html": "<html><body><p>Hello</p></body></html>", "group": "Playbills"}' \
  "https://e1.envoke.com/v2/messages"
```

```json
{
  "success": false,
  "result_text": "Validation failed, see 'result_data' -> 'errors'",
  "result_data": {
    "errors": ["Invalid 'group': 'Playbills'"],
    "allowed_values": {
      "group": { "31": "Productions", "32": "Newsletters" }
    }
  }
}
```

No message is created. Create the group first with the [Group API](https://envoke-developers.pages.dev/v2/groups/fields/), or use one of the listed names or IDs.

---

*Note: The curl examples above are formatted for readability. All requests must use properly encoded URLs.*

*Full reference, OpenAPI description, and Postman collection: [developers.envoke.com](https://developers.envoke.com).*
