POST /api/v1/handoff/ticket
/ Create a Human Desk ticket from your own UI, outside the chat stream's automatic handoff.
Request
| Field | Type | Required | Description |
|---|---|---|---|
| agentId | string | Yes | The agent's public ID |
| visitorEmail | string | Yes | A valid email for follow-up |
| sessionId | string | No | Ties the ticket to an existing conversation. Auto-generated if omitted |
| note | string | No | 4,000 characters max. Extra context for your team |
| history | array | No | { role: "user" | "assistant", content: string }[], last 12 turns used. Summarized into a subject and urgency automatically |
const res = await fetch("https://app.humaner.io/api/v1/handoff/ticket", {
method: "POST",
headers: {
Authorization: "Bearer hm_live_xxxxxxxx",
"Content-Type": "application/json"
},
body: JSON.stringify({
agentId: "AGENT_ID",
visitorEmail: "customer@example.com",
note: "Customer needs a refund on order #4521"
})
});Response
200 OK
{
"ok": true,
"ticketId": "tkt_abc123",
"liveChat": { "enabled": false }
}liveChat.enabled is only ever true for tickets from the hosted widget, on Scale or Delegate with live chat on. API-sourced tickets always get the async email flow.
Errors
| Status | Meaning |
|---|---|
| 400 | agentId missing, or visitorEmail missing or invalid |
| 401 | Missing or invalid API key, or no Origin header and no key |
| 403 | Origin not allowed, or Human Desk is off for the organization |
| 404 | Agent not found |
| 429 | Rate limit hit (Retry-After header set) |
| 500 | Ticket creation failed. Safe to retry |