POST /api/v1/chat
/ Send a message. Get back the reply, streamed, plus signals about what the customer wants.
Request
| Field | Type | Required | Description |
|---|---|---|---|
| agentId | string | Yes | The agent's public ID |
| message | string | Yes | The customer's message. 4,000 characters max |
| sessionId | string | No | Your own ID for this browser session. Auto-generated if omitted |
| visitorId | string | No | Stable hashed ID for a known user. Enables cross-session memory on Scale and Delegate plans. 1 to 255 characters |
| history | array | No | { role: "user" | "assistant", content: string }[]. Last 10 turns used, the rest dropped |
const res = await fetch("https://app.humaner.ai/api/v1/chat", {
method: "POST",
headers: {
Authorization: "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
agentId: "ag_demo123",
sessionId: crypto.randomUUID(),
message: "Where is my order?",
}),
});
// Responses stream as SSE — { delta } chunksResponse: SSE stream
The response is text/event-stream. Each event is JSON on a "data:" line. Render text as delta events arrive, then read the final event for usage, metadata, and handoff.
Event 1..N: text deltas
data: {"delta":"Your order shipped "}
data: {"delta":"this morning..."}
Final event
{
"usage": {
"inputTokens": 1240,
"outputTokens": 87,
"grounded": true,
"sessionId": "sess_xxx",
"visitorId": null,
"model": "claude-sonnet-4-6",
"routedModel": "sonnet",
"cacheHit": false,
"langCacheSimilarity": 0.72,
"cacheReadInputTokens": 890,
"cacheCreationInputTokens": null
},
"metadata": {
"intent": "order_status",
"confidence": 0.94,
"escalate": false,
"urgency": "low",
"medicalTopic": false,
"cancellationIntent": false,
"suggestedProductId": null,
"bookingContext": null,
"modelUsed": "sonnet",
"cacheHit": false,
"verticalVersion": "1.2.0"
},
"handoff": null
}Terminal event
data: [DONE]Reading metadata
| Field | When set | What to do |
|---|---|---|
| intent | Always. One of a per-vertical taxonomy (order_status, return_request, etc.) | Render UI for the intent, or ignore it |
| suggestedProductId | Retail. An upsell was identified | Show a cross-sell card, or ignore it |
| escalate: true | The turn was ungrounded, or the model asked for a handoff | Check the handoff object. A ticket may already exist |
| cancellationIntent: true | The customer wants to cancel | Trigger your own retention flow |
| bookingContext | Dates, room, or class details were extracted | Pre-fill your booking flow |
| urgency: "critical" | Emergency pattern match | Alert your team now |
| medicalTopic: true | A medical question (Wellness vertical) | Add a disclaimer in your own UI |
The handoff object
Non-null only when the agent could not resolve the turn. Shape: { humanDesk: boolean, email: string | null }. humanDesk is true when a ticket-creation flow should show, which needs Human Desk enabled on a Refined+ plan. email is a fallback contact address.
Errors
| Status | Meaning |
|---|---|
| 400 | Invalid JSON body, or agentId / message missing |
| 401 | Missing or invalid API key, or no Origin header and no key |
| 403 | Origin not on the allowed-domains list, or the plan lacks API access |
| 404 | Agent not found |
| 413 | message over 4,000 characters |
| 429 | Message quota exceeded, or rate limit hit (Retry-After header set) |
| 502 | The model call failed |
| 503 | Anthropic not configured, or the model is temporarily overloaded |