# Reply to a contact

> Sends a reply to a contact on a specific channel and appends it to the timeline. Each channel has its own requirements:

Source: https://warmerly.com/docs/inbox/reply-to-a-contact

```text
POST /inbox/contacts/{contactId}/reply
```

Sends a reply to a contact on a specific channel and appends it to the timeline. Each channel has its own requirements:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `channel` | `"email"` \\| `"linkedin"` | Yes | Channel to send on. |
| `body` | string | Yes | Message text, at least 1 character. |
| `subject` | string | Email only | Required when `channel` is `"email"`. A `Re: ` prefix is added if missing. |
| `sourceAccountId` | string | Yes | ID of the connected account to send from (email account or LinkedIn account, matching `channel`). Must belong to your workspace, otherwise `400 invalid_source_account`. |

```bash
curl -X POST https://app.warmerly.com/api/v1/inbox/contacts/c3a1f6e2-9c4d-4e2a-8b5f-6a2c1d9e0f7b/reply \
  -H "X-Api-Key: wmv_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
        "channel": "email",
        "subject": "Re: Quick question about your workflow",
        "body": "Great, does Tuesday at 3pm work for a quick call?",
        "sourceAccountId": "8f14e45f-ceea-4c6a-8c8d-6b1a5b5c9c1a"
      }'
```

```json
{
  "message": {
    "id": "7f3a2cdb-9e1a-4f0c-8b6d-2e5f7a1c3b9d",
    "channel": "email",
    "direction": "outbound",
    "status": "sent",
    "contactId": "c3a1f6e2-9c4d-4e2a-8b5f-6a2c1d9e0f7b",
    "accountId": "8f14e45f-ceea-4c6a-8c8d-6b1a5b5c9c1a",
    "subject": "Re: Quick question about your workflow",
    "bodyText": "Great, does Tuesday at 3pm work for a quick call?",
    "toAddrs": ["jamie@northwindtraders.com"],
    "fromAddr": "you@yourcompany.com",
    "receivedAt": "2026-07-01T16:42:03.000Z"
  }
}
```

`message` is the stored message row, so it carries more fields than shown here. For email, the stored `bodyText` is the text you sent plus your mailbox signature and the quoted message you replied to.

Notes on behaviour by channel:

- **Email** sends synchronously over SMTP; the contact must have an `email` on file and `subject` is required. If the contact already has an email thread in your workspace, the reply goes out from the mailbox that thread started on, even if `sourceAccountId` names another of your mailboxes. A send failure returns `500` with the SMTP error message, but the failed message is still recorded in the timeline with `status: "failed"`.
- **LinkedIn** sends synchronously through your connected LinkedIn account; the contact must have a `linkedinProfileId` on file. A send failure returns `500` and is recorded as `failed`, as for email. Some account types cannot send yet and return `400` (for example `native_send_not_ready`).

Missing channel-specific data returns `400` (`contact_has_no_email`, `subject_required`, `contact_has_no_linkedin`, `contact_has_no_phone`); a body that fails validation returns `400 invalid_body`; and a contact that is not in your workspace returns `404`. For example:

```json
{ "error": { "code": "bad_request", "message": "contact_has_no_email", "details": null } }
```

## More from Inbox

- [Get a contact's timeline](https://warmerly.com/docs/inbox/get-a-contact-s-timeline): Returns the full conversation with a contact across all channels, in chronological order (the most recent…
- [List threads](https://warmerly.com/docs/inbox/list-threads): Returns email threads (grouped by threadKey + accountId) with aggregate counts, for building a mailbox-style…
- [Get a thread](https://warmerly.com/docs/inbox/get-a-thread): Returns the raw messages in a single email thread, chronological order (the most recent 200). {key} is the…
