---
title: "Start an outbound ticket"
method: POST
path: "/tickets/compose"
tags: ["Tickets"]
---

# Start an outbound ticket

`POST /tickets/compose`

## Request

- Base URL: `https://there-there.app/api`
- URL: `https://there-there.app/api/tickets/compose`
- Auth: HTTP bearer

Starts a new conversation with a customer, the API equivalent of "Create ticket" in the app. The first message is outbound and is queued for delivery to the recipients, sent by the user the token belongs to. Workflows, AI title generation and notifications all run as they do for any new ticket. The channel must be an email channel with verified DNS records; a channel the token cannot reach is a 404.

## Headers

- `X-Workspace-Id` integer

## Request body

- object
  - `channel` string, required: Channel ULID. Must be an email channel that is ready to send.
  - `subject` string, required
  - `to` string[], required: Recipients. The first one becomes the ticket's contact.
  - `cc` string[]
  - `bcc` string[]
  - `message` object, required
    - `body` string, required: HTML body of the outbound message.
    - `attachment_ids` string[]: Upload tokens from POST /attachments. Embed a token as <img src="cid:TOKEN"> in the body to render it inline.
  - `tags` string[]: Tag names to put on the ticket. Matched on the tag name, ignoring casing and surrounding whitespace. A name that matches no tag in the workspace is created, but only for a token belonging to a workspace admin; for anyone else it is a 422. Two names that only differ in punctuation cannot both exist, so asking for one the workspace already occupies is a 422 as well.
  - `custom_fields` object[]: Custom field values to set on the new ticket. Every field has to be available on the chosen channel. Resolve the ulids with GET /custom-fields.
    - `ulid` string, required
    - `value` string, nullable: The text for a text field, or null. Must be null for select fields.
    - `option_ulids` string[]: Option ULIDs for a select field. Must be empty for text fields.

## Response `201`

Ticket created and the outbound message queued

- object
  - `data` Ticket
    - `id` integer
    - `ulid` string
    - `number` integer
    - `subject` string
    - `status` 'open' | 'waiting' | 'closed' | 'spam'
    - `channel` Channel
      - `id` integer
      - `ulid` string
      - `name` string
      - `type` 'email' | 'widget'
      - `color` string
      - `email_address` string, nullable
    - `assignee` User
      - `id` integer
      - `name` string
      - `email` string, email
      - `avatar_url` string, nullable
      - `timezone` string, nullable
    - `assigned_team` Team
      - `id` integer
      - `ulid` string
      - `name` string
      - `description` string, nullable
      - `logo_url` string, nullable
      - `member_count` integer
    - `contact` Contact
      - `id` integer
      - `ulid` string
      - `name` string, nullable
      - `email` string, email
      - `avatar_url` string, nullable
      - `company` ContactCompany
        - `ulid` string
        - `name` string
        - `domain` string, nullable
      - `ticket_count` integer, nullable
      - `last_activity_at` string, date-time, nullable
      - `notes` string, nullable
    - `tags` Tag[]
      - `id` integer
      - `ulid` string
      - `name` string
      - `color` string
    - `custom_fields` TicketCustomField[]: Every custom field that applies to this ticket's channel, whether or not it holds a value. Returned on GET /tickets/{ticket} and on every ticket write response; omitted from the paginated list.
      - `ulid` string
      - `name` string
      - `type` 'text' | 'single_select' | 'multi_select'
      - `value` string, nullable: Set for text fields only; null for the two select types.
      - `selected_option_ulids` string[]: Empty for text fields and for select fields with no value.
      - `options` TicketCustomFieldOption[]: The options an admin defined, in the order they arranged them. Empty for text fields.
        - `ulid` string
        - `name` string
        - `color` string, nullable
        - `icon` string, nullable
    - `latest_message_preview` string, nullable
    - `summary` string, nullable
    - `title` string, nullable
    - `from_address` string, nullable
    - `created_at` string, date-time
    - `updated_at` string, date-time
    - `last_activity_at` string, date-time

## Other responses

- `404`: No such channel for this token
- `422`: Validation failed

---

[API](https://skmtc.dev/there-there/apis/there-there-api.md) · [All operations](https://skmtc.dev/there-there/apis/there-there-api/llms.txt) · [OpenAPI document](https://skmtc.dev/there-there/apis/there-there-api/revisions/1811fb0febc1?raw)
