Skip to main content

Open Approval Card

POST 

/api/support/agent/tickets/:ticket/approvals

Opens an approval card on a ticket: a proposal a human must decide before the AI agent acts. A ticket has at most one open card — any card still pending or snoozed on the ticket is marked superseded (reason new_card). The new card gets the next per-ticket version. The ticket's owner gets a portal alert (and a push notification on their installed app) when they are a human; otherwise every agent who can decide cards does. No email is sent. Once the card is decided or superseded, its alerts are marked read for everyone. An internal approval_requested event is recorded.

Required scope: support:write

Grant this scope to your token under Settings → Developer → Personal Access Tokens.

A reply card's payload.draft_body is also written into the ticket's shared reply draft so it is ready to send — unless a human is already holding that draft, whose words are never overwritten.

The AI agent may only open a card on a ticket it owns — otherwise 409 not_owner. Any human agent may open one on any ticket.

Path parameters

  • ticket (integer) — the ticket id.

Request body

  • kind (string, required) — one of: reply, question, fix, merge, repair, status, escalate, error
  • title (string, required, max 160)
  • body (string, required, max 20000) — the proposal in plain text. Attach long reports and link them from evidence.
  • confidence (string, optional, nullable) — high, medium or low
  • payload (object, optional, nullable) — what the card proposes:
    • payload.draft_body (string, max 65000) — required when kind is reply: the reply to send
    • payload.status_after (string, nullable) — the status to set once the reply is sent: open, in_progress, waiting_on_customer, awaiting_release, resolved, closed
    • payload.cc[] (array of email addresses, max 20) — extra recipients of the reply
    • payload.choices[] (array, 1–10) — required when kind is question; each {key (string, required, max 40, unique), label (string, required, max 500), recommended (boolean, optional)}
    • payload.allow_text (boolean, nullable) — a question card may also be answered in free text
    • payload.status (string) — required when kind is status: the status it proposes (open, in_progress, waiting_on_customer, awaiting_release, resolved, closed)
  • evidence[] (array, optional, max 50) — each {label (string, required, max 200), url (string, nullable, max 2000), attachment_id (integer, nullable)}
  • files[] (array, optional, max 10) — files the card carries: a report, HTML mockups, screenshots, a PDF. Each {filename (string, required, max 255), content_type (string, required), content_base64 (string, required — the file's bytes, base64-encoded), label (string, optional, max 200 — defaults to the filename)}. content_type must be one of: text/html, image/png, image/jpeg, image/gif, image/webp, application/pdf, text/plain, text/markdown, application/json, text/csv. Each file may be at most 10 MB decoded, and all of a card's files at most 25 MB together. Invalid base64, a type outside that list, or a size over either limit is a 422 and nothing is stored. Files are internal to the support desk: they are never shown to, or downloadable by, the customer. Each file is appended to the card's evidence (after any evidence[] you send) as {label, attachment_id, filename, content_type, size, kind, download_url} — read it with Get Approval Card File.
  • run_id (integer, optional, nullable) — the AI run that produced the card; must be a run on this ticket
  • diff_from_id (integer, optional, nullable) — an earlier card on the same ticket this one revises

Returns 201 with the new card (fields as in List Approval Cards).

Authentication: Bearer token with the support:write scope, or an authenticated session, from a caller with an active support role that can work tickets (the viewer role is read-only). No tenant context — this endpoint is central.

If this ticket was merged into another ticket, the request is refused with a 422 whose merged_into (id, number) names the live ticket — send the action there instead.

Request​

Responses​

Created

Response Headers
    Content-Type