# Create forward by conversation

> POST /v1/conversations/{id}/forwards · Core resources API

Source: https://developer.kustomer.com/api/core-resources/create-forward-by-conversation

```http
POST https://{orgname}.api.kustomerapp.com/v1/conversations/{id}/forwards
Authorization: Bearer <API key>
```

## Authorization

Requires any one of these roles: `org.permission.conversation_forward.create`; or legacy `org.user.conversation_forward`. The API key or user must hold at least one of them. Legacy roles predate permission sets and still work.

Creates a forward to send through email. Forwards will send all messages in a conversation.

### NOTE
> To schedule the forward for delivery, create a forward with a `sendAt` property.

## About Conversation forwards

A forward sends a copy of an entire conversation by email to someone outside it, such as a vendor, a warehouse or another department. It starts as a draft and is sent when you give it a send time.

Agents forward a conversation from the agent desktop when someone who isn't on the thread needs the full history, for example a shipping partner who has to investigate a lost package. A forward belongs to one [conversation](https://developer.kustomer.com/api/core-resources#conversations) and its customer, and it emails all of that conversation's messages to the addresses you choose. Forwards are listed on the conversation they came from.

#### Lifecycle

A forward works like a [draft](https://developer.kustomer.com/api/core-resources#drafts): you create it, adjust it, and then send it.

| `status` | Meaning |
| --- | --- |
| `draft` | Created without `sendAt`. Nothing has been sent, and you can still edit it. |
| `scheduled` | Has a `sendAt` and is waiting to go out. |
| `sent` | Sent. |
| `failed` | Sending failed. |

Include `sendAt` when you create the forward to send it, or create it without one and set `sendAt` later with [`PUT /v1/forwards/{id}`](https://developer.kustomer.com/api/core-resources/update-draft-forward). Kustomer validates the email fields when a forward is scheduled.

#### Key fields

`channel` is always `email`. `to` is a list of `{ email, name }` recipients and `from` is the `{ email, name }` sender, which should be one of your org's email accounts; [`GET /v1/outboundAccounts`](https://developer.kustomer.com/api/core-resources/get-outbound-accounts) lists them. `app` picks the sending integration (`gmail` or `postmark`). `subject`, `body` and `replyTo` work as they do for an email draft; `body` is the text you add for the recipient. `attachments` adds files that you upload through the [forward attachment endpoints](https://developer.kustomer.com/api/core-resources#forwards-attachments).

#### Which endpoint to use

| To | Call |
| --- | --- |
| Forward a conversation by email | [`POST /v1/conversations/{id}/forwards`](https://developer.kustomer.com/api/core-resources/create-forward-by-conversation) |
| See every forward made from a conversation | [`GET /v1/conversations/{id}/forwards`](https://developer.kustomer.com/api/core-resources/get-all-forwards-by-conversation) |

To read, edit or schedule a single forward after creating it, use [`GET`](https://developer.kustomer.com/api/core-resources/get-draft-forward-by-id) and [`PUT /v1/forwards/{id}`](https://developer.kustomer.com/api/core-resources/update-draft-forward). Creating a forward needs the conversation-forward permission (`org.permission.conversation_forward.create`), and listing forwards needs draft read access.

Related: [Drafts](https://developer.kustomer.com/api/core-resources#drafts), [Conversations](https://developer.kustomer.com/api/core-resources#conversations), [Forward attachments](https://developer.kustomer.com/api/core-resources#forwards-attachments)

### Recipes

#### 1. Forward a conversation to a vendor by email

Send a shipping partner, warehouse or other department the full history of a conversation, without adding them to the customer thread.

**Step 1.** [`GET /v1/outboundAccounts`](https://developer.kustomer.com/api/core-resources/get-outbound-accounts.md). Pick the address to send from: an account with `channel` `email`, whose `account` is the address.

```bash title="cURL"
curl "https://api.kustomerapp.com/v1/outboundAccounts" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY"
```

```bash title="kusty"
kusty api GET /v1/outboundAccounts \
  | jq -r '.data[] | select(.attributes.channel == "email") | .attributes.account'
```

**Step 2.** [`POST /v1/conversations/{id}/forwards`](https://developer.kustomer.com/api/core-resources/create-forward-by-conversation.md). Create the forward with a `sendAt` to send it. Kustomer emails all of the conversation's messages to the `to` addresses, with your `body` as the covering text. `channel` is always `email`, and `app` is the sending integration, `gmail` or `postmark`. Kustomer validates the email fields when the forward is scheduled.

```bash title="cURL"
curl --request POST "https://api.kustomerapp.com/v1/conversations/$CONVERSATION_ID/forwards" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY" \
  --header "Content-Type: application/json" \
  --data "{\"channel\": \"email\", \"app\": \"postmark\", \"from\": {\"email\": \"$FROM_EMAIL\", \"name\": \"Acme Support\"}, \"to\": [{\"email\": \"claims@carrier.example\", \"name\": \"Carrier claims\"}], \"subject\": \"Lost package, order 4417\", \"body\": \"Please open a trace for this shipment. The customer's messages are below.\", \"sendAt\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}"
```

```bash title="kusty"
kusty api POST /v1/conversations/$CONVERSATION_ID/forwards \
  --field channel=email --field app=postmark \
  --field from.email=$FROM_EMAIL --field from.name="Acme Support" \
  --field to.0.email=claims@carrier.example --field to.0.name="Carrier claims" \
  --field subject="Lost package, order 4417" \
  --field body="Please open a trace for this shipment. The customer's messages are below." \
  --field sendAt=$(date -u +%Y-%m-%dT%H:%M:%SZ)
```

**Step 3.** [`GET /v1/conversations/{id}/forwards`](https://developer.kustomer.com/api/core-resources/get-all-forwards-by-conversation.md). Check the result. Each forward's `status` moves from `scheduled` to `sent`, or to `failed` if sending didn't work.

```bash title="cURL"
curl "https://api.kustomerapp.com/v1/conversations/$CONVERSATION_ID/forwards" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY"
```

```bash title="kusty"
kusty api GET /v1/conversations/$CONVERSATION_ID/forwards --all \
  | jq -r '[.data.id, .data.attributes.status, (.data.attributes.to | map(.email) | join(","))] | @tsv'
```

> Forwarding sends customer content outside your team, so make sure the recipient is right. Creating a forward needs `org.permission.conversation_forward.create`.

#### 2. Forward a conversation with a file attached

Include a document such as a shipping label or an invoice when you forward a conversation, by preparing the forward as a draft first.

**Step 1.** [`POST /v1/conversations/{id}/forwards`](https://developer.kustomer.com/api/core-resources/create-forward-by-conversation.md). Create the forward without `sendAt`. It stays a `draft`, nothing is sent, and you can still change it. Keep `data.id`.

```bash title="cURL"
curl --request POST "https://api.kustomerapp.com/v1/conversations/$CONVERSATION_ID/forwards" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY" \
  --header "Content-Type: application/json" \
  --data "{\"channel\": \"email\", \"app\": \"postmark\", \"from\": {\"email\": \"$FROM_EMAIL\"}, \"to\": [{\"email\": \"$VENDOR_EMAIL\"}], \"subject\": \"Invoice dispute, order 4417\", \"body\": \"The invoice in question is attached.\"}"
```

```bash title="kusty"
kusty api POST /v1/conversations/$CONVERSATION_ID/forwards \
  --field channel=email --field app=postmark --field from.email=$FROM_EMAIL \
  --field to.0.email=$VENDOR_EMAIL --field subject="Invoice dispute, order 4417" \
  --field body="The invoice in question is attached." \
  | jq -r .data.id
```

**Step 2.** [`POST /v1/forwards/{id}/attachments`](https://developer.kustomer.com/api/core-resources/create-forward-attachment.md). Create an attachment record on the forward with the file's `name`, `contentType` and size in bytes as `contentLength`. The response's `links.related` is a short-lived signed URL.

```bash title="cURL"
curl --request POST "https://api.kustomerapp.com/v1/forwards/$FORWARD_ID/attachments" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY" \
  --header "Content-Type: application/json" \
  --data "{\"name\": \"invoice-4417.pdf\", \"contentType\": \"application/pdf\", \"contentLength\": $(wc -c < invoice-4417.pdf)}"
```

```bash title="kusty"
kusty api POST /v1/forwards/$FORWARD_ID/attachments \
  --field name=invoice-4417.pdf --field contentType=application/pdf \
  --field contentLength:=$(wc -c < invoice-4417.pdf) \
  | jq -r .data.links.related
```

**Step 3.** Upload the file to that URL right away with a single `PUT`. Don't send your Kustomer `Authorization` header to it.

```bash title="cURL"
curl --upload-file invoice-4417.pdf "$UPLOAD_URL"
```

**Step 4.** [`PUT /v1/forwards/{id}`](https://developer.kustomer.com/api/core-resources/update-draft-forward.md). Send the forward by giving it a `sendAt`. Its `status` becomes `scheduled` and then `sent`.

```bash title="cURL"
curl --request PUT "https://api.kustomerapp.com/v1/forwards/$FORWARD_ID" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY" \
  --header "Content-Type: application/json" \
  --data "{\"sendAt\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}"
```

```bash title="kusty"
kusty api PUT /v1/forwards/$FORWARD_ID --field sendAt=$(date -u +%Y-%m-%dT%H:%M:%SZ)
```

### Example object

A real record from [`GET /v1/conversations/{id}/forwards`](https://developer.kustomer.com/api/core-resources/get-all-forwards-by-conversation.md):

```json
{
  "id": "58210c6c2a8b9910002f6730",
  "type": "forward",
  "attributes": {
    "app": "postmark",
    "channel": "email",
    "from": {
      "name": "Sales",
      "email": "sales@example.com"
    },
    "to": [
      {
        "name": "Billing",
        "email": "billing@email.com"
      }
    ],
    "body": "",
    "payload": {
      "draftJs": {
        "blocks": [
          {
            "data": {},
            "entityRanges": [],
            "inlineStyleRanges": [],
            "depth": 0,
            "type": "unstyled",
            "text": "",
            "key": "dv926"
          }
        ],
        "entityMap": {}
      }
    },
    "status": "draft",
    "createdAt": "2016-11-07T23:21:16.945Z",
    "updatedAt": "2016-11-08T18:49:32.730Z",
    "modifiedAt": "2016-11-08T18:49:32.730Z"
  },
  "relationships": {
    "org": {
      "data": {
        "type": "org",
        "id": "57f29863a1dbf61100e6aa92"
      },
      "links": {
        "self": "/v1/orgs/57f29863a1dbf61100e6aa92"
      }
    },
    "customer": {
      "data": {
        "type": "customer",
        "id": "58210c3db0f09110006b7953"
      },
      "links": {
        "self": "/v1/customers/58210c3db0f09110006b7953"
      }
    },
    "createdBy": {
      "data": {
        "type": "user",
        "id": "57fd2d309d0ef811009cfdd6"
      },
      "links": {
        "self": "/v1/users/57fd2d309d0ef811009cfdd6"
      }
    },
    "modifiedBy": {
      "data": {
        "type": "user",
        "id": "58190b991f2932100010d683"
      },
      "links": {
        "self": "/v1/users/58190b991f2932100010d683"
      }
    },
    "conversation": {
      "data": {
        "type": "conversation",
        "id": "58210c3d728107110018662f"
      },
      "links": {
        "self": "/v1/conversations/58210c3d728107110018662f"
      }
    }
  }
}
```

Fields:

- `attributes.app` (string): The integration that sends the email: `gmail` or `postmark`.
- `attributes.channel` (string): Always `email`.
- `attributes.from` (object): The sender, as `{ email, name }`. Use one of your org's email accounts, which `GET /v1/outboundAccounts` lists.
- `attributes.to` (array): The recipients, each `{ email, name }`, up to 100. Each receives a copy of the conversation's messages.
- `attributes.body` (string): Your own text for the recipients, shown with the forwarded conversation, up to 10,240 characters. Empty here because nothing has been written yet.
- `attributes.payload` (object): Rich-text editor state saved by the agent desktop while an agent writes the forward. Integrations can leave it out and send `body`.
- `attributes.status` (string): `draft` until you give it a `sendAt`, then `scheduled`, and finally `sent` or `failed`.
- `relationships.customer` (object): The customer of the forwarded conversation.
- `relationships.createdBy` (object): The user or API key that created the forward.
- `relationships.conversation` (object): The conversation being forwarded. All of its messages are included in the email.

### Relationships

- Points to **Customers** via `relationships.customer`: The customer whose conversation a forward copies, taken from the conversation.
- Points to **Conversations** via `relationships.conversation`: The conversation a forward copies. A conversation can be forwarded many times, and each forward is listed on it.
- Points to **Attachments** via `relationships.attachments` (list): Files added to a forward with `POST /v1/forwards/{id}/attachments`. Each one is uploaded to its signed URL before the forward is sent.

### Permissions

Fewest roles for a read-only integration: `org.permission.draft.read`. For every endpoint: `org.permission.conversation_forward.create`, `org.permission.draft.read`.

## Path parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Conversation ID. |

## Request body

Content type: `application/json` (required)

- `channel` (string, required): One of: `email`.
- `app` (string): One of: `gmail`, `postmark`.
- `customer` (string<object-id>)
- `status` (string): One of: `draft`, `sent`, `failed`.
- `sendAt` (string<date-time-math>)
- `to` (array<object>): (max items 100)
  - `email` (string<email-relaxed>, required): (min length 3; max length 256)
  - `name` (string): (min length 1)
- `from` (object)
  - `email` (string<email-relaxed>, required): (min length 3; max length 256)
  - `name` (string): (min length 1)
- `body` (string): (max length 10240)
- `subject` (string): (min length 1)
- `replyTo` (string<email-relaxed>): (min length 3; max length 256)
- `template` (string<object-id>, nullable)
- `payload` (object)
- `attachments` (array<object>)
  - `id` (string<object-id>, required)
  - `name` (string, required)
  - `contentType` (string, required)
  - `contentLength` (number, required)

Example:

```json
{
  "channel": "email",
  "app": "gmail",
  "customer": "string",
  "status": "draft",
  "body": "Example text",
  "subject": "Example title"
}
```

## Responses

### 200

OK

- `data` (object, required)
  - `id` (string, required)
  - `type` (string, required)
  - `attributes` (object, required)
    - `app` (string, required)
    - `channel` (string, required)
    - `status` (string, required)
    - `from` (object, required)
    - `to` (array<object>, required)
    - `createdAt` (string, required)
    - `updatedAt` (string, required)
    - `modifiedAt` (string, required)
  - `relationships` (object, required)
    - `org` (object, required)
    - `customer` (object, required)
    - `conversation` (object, required)
    - `createdBy` (object, required)
    - `modifiedBy` (object, required)
    - `attachments` (array<object>)

```json
{
  "data": {
    "id": "5823e4d3bff98a100085320e",
    "type": "forward",
    "attributes": {
      "app": "postmark",
      "channel": "email",
      "status": "draft",
      "from": {
        "name": "Support",
        "email": "support@example.com"
      },
      "to": [
        {
          "name": "Billing",
          "email": "billing@email.com"
        }
      ],
      "createdAt": "2016-11-10T03:09:07.575Z",
      "updatedAt": "2016-11-10T03:09:07.575Z",
      "modifiedAt": "2016-11-10T03:09:07.575Z"
    },
    "relationships": {
      "org": {
        "data": {
          "type": "org",
          "id": "57f29863a1dbf61100e6aa92"
        },
        "links": {
          "self": "/v1/orgs/57f29863a1dbf61100e6aa92"
        }
      },
      "customer": {
        "data": {
          "type": "customer",
          "id": "58210c3db0f09110006b7953"
        },
        "links": {
          "self": "/v1/customers/58210c3db0f09110006b7953"
        }
      },
      "conversation": {
        "data": {
          "type": "conversation",
          "id": "58210c3db0f09110006b7954"
        },
        "links": {
          "self": "/v1/conversation/58210c3db0f09110006b7954"
        }
      },
      "createdBy": {
        "data": {
          "type": "user",
          "id": "58190b991f2932100010d683"
        },
        "links": {
          "self": "/v1/users/58190b991f2932100010d683"
        }
      },
      "modifiedBy": {
        "data": {
          "type": "user",
          "id": "58190b991f2932100010d683"
        },
        "links": {
          "self": "/v1/users/58190b991f2932100010d683"
        }
      }
    }
  }
}
```

### 400

Bad Request

### 401

Unauthorized

### 403

Forbidden

### 404

Not Found

## Example request

```bash
curl --request POST \
  --url 'https://api.kustomerapp.com/v1/conversations/5faaf4a6ea0cb48cd0801bbf/forwards' \
  --header "Authorization: Bearer $KUSTOMER_API_KEY" \
  --header 'Content-Type: application/json' \
  --data '{
  "channel": "email",
  "app": "gmail",
  "customer": "string",
  "status": "draft",
  "body": "Example text",
  "subject": "Example title"
}'
```
