Skip to content

Create a ticket with the API

By Jon Henshaw2 min readUpdated

Your app’s backend can open a support ticket on a customer’s behalf with a workspace API key. This is the server-to-server path: the customer does not need to be signed in, and you identify them by email (and, ideally, your own account id).

Before you start

  • Create a key under Settings → Integrations → API keys — see Create and manage API keys.
  • Your base URL is your portal host: https://{slug}.essential.support (or your custom domain). Send every request there.

The request

Send a POST to /api/tickets with your key as a Bearer token and a JSON body:

curl -X POST https://{slug}.essential.support/api/tickets \
  -H "Authorization: Bearer es_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "dana@customer.com",
    "externalId": "u_9",
    "name": "Dana Lee",
    "subject": "Invoice charged twice",
    "message": "I was billed twice this month.",
    "type": "Billing",
    "priority": "high"
  }'

Body fields

  • subject (required) — the ticket title.
  • message (required) — the first message, as plain text. For rich content send messageHtml or messageLexical instead; at least one non-empty message is required.
  • email (required) — the customer’s email. It finds or creates the customer and is treated as verified, because your key vouches for it.
  • externalId (optional, recommended) — your own stable customer id. When present it is the primary identity key, so a customer’s email can change without creating a duplicate.
  • name (optional) — the customer’s display name.
  • type (optional) — a ticket type by name (e.g. Billing) or by id. Call GET /api/ticket-types to list them.
  • priority (optional) — high, med, or low.
  • locale (optional) — the customer’s language (e.g. es), used for auto-translation of replies.

Setting the type and priority

Both type and priority are validate-or-ignore: a value Essential Support does not recognize is silently dropped rather than returning an error, so a stale type name never blocks ticket creation. priority is honored only on this API-key path — end users cannot set their own priority — and an unknown value falls back to med. Setting a priority here also stops AI auto-triage from overriding your choice.

A successful response

On success you get 201 Created with the ticket in the read-back shape. Store the ref (a short, human-facing code such as A7K2M9Q) or the id so you can link back and read updates later.

{
  "ticket": {
    "id": "66b2f0a1c3d4e5f6a7b8c9d0",
    "number": 1042,
    "ref": "A7K2M9Q",
    "subject": "Invoice charged twice",
    "status": "open",
    "createdAt": "2026-08-09T14:03:00.000Z",
    "lastMessageAt": "2026-08-09T14:03:00.000Z",
    "aiAnswerPending": false,
    "priority": "high",
    "source": "api",
    "customer": {
      "id": "66b2efaa1122334455667788",
      "email": "dana@customer.com",
      "externalId": "u_9",
      "name": "Dana Lee"
    }
  }
}

Errors

  • 400 — Subject and message are required (a required field is missing or empty).
  • 400 — A valid customer email is required.
  • 401 — API key required or Invalid API key (missing, wrong, or revoked key).
  • 429 — Rate limit exceeded (over 120 requests per minute for that key).

Was this article helpful?

Thanks for your feedback.

Source: https://help.essential.support/integrations/create-a-ticket-with-the-api/