An API that behaves like infrastructure.
Bearer-key REST under /v1, typed errors, signed webhooks, and a widget you embed with one script tag.
curl https://YOUR_API_HOST/v1/agents \
-H "Authorization: Bearer YOUR_API_KEY"REST
JSON over /v1
Webhooks
9 signed events
Widget
one script tag
Try the API without leaving the page.
Pick an endpoint. The request is shown in cURL, JavaScript and Python, with the response it returns. Examples are abridged.
GET/v1/agentsAuth: API key
Every agent in your workspace, with its public key and the version that is live.
curl https://YOUR_API_HOST/v1/agents \
-H "Authorization: Bearer YOUR_API_KEY"[
{
"id": "0192f3c0-6b1a-7c52-9f0e-3a8d5c1e7b24",
"name": "Support Concierge",
"slug": "support-concierge",
"description": null,
"status": "published",
"public_key": "pk_live_…",
"is_public": true,
"current_version_id": "0192f3c1-0d4e-7a10-8b63-5e2f9a4c1d07",
"draft_version": 15,
"created_at": "2026-08-12T09:14:03Z",
"updated_at": "2026-10-05T16:41:22Z"
}
]Example response, abridged to one agent.
Put it on your website with one tag.
The widget has no dependencies and runs in a Shadow DOM, so your site's CSS can't break it. The public key is safe to leave in client-side HTML.
<script
src="https://YOUR_WEB_HOST/widget.js"
data-agent="pk_your_agent_public_key"
></script>Know the moment something happens.
Register an endpoint and Vicero sends a signed POST for the events you choose. Pick one to see what arrives.
message.created fires when a message is added to a conversation, from a visitor, the agent or an operator.
{
"event": "message.created",
"org_id": "0192f2a8-77d3-7f04-b1e9-4c05a3d8e620",
"data": {
"conversation_id": "0192f401-3b7e-7c19-a6d2-95e4b0f1c836",
"channel": "whatsapp",
"message": {
"role": "user",
"content": "Do you ship to Chennai?"
}
}
}Example payload. The envelope is the same for every event; the contents of data vary.
Check the signature first
Compute an HMAC-SHA256 of the raw request body with your endpoint secret and compare it, in constant time, to the header. Do it before parsing the JSON.
import { createHmac, timingSafeEqual } from "node:crypto";
export function verify(rawBody, signature, secret) {
const expected = createHmac("sha256", secret).update(rawBody).digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(signature);
// Check length first: timingSafeEqual throws when lengths differ.
return a.length === b.length && timingSafeEqual(a, b);
}Typed errors
Every failure returns an error with a code, a message and details, never a stack trace.
Rate limits
Public endpoints are rate limited, and the limits are documented.
Streaming
Server-sent events stream tokens as they are written, and a WebSocket drives the live inbox.