Skip to content
Vicero

An API that behaves like infrastructure.

Bearer-key REST under /v1, typed errors, signed webhooks, and a widget you embed with one script tag.

List your agents
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.

Request
curl https://YOUR_API_HOST/v1/agents \
  -H "Authorization: Bearer YOUR_API_KEY"
Response
200 OK
[
  {
    "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.

Paste before </body>
<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.

POST https://your-app.example/hooks/vicero
{
  "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.

Verify in Node
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.