https://app.vorel.ai/api/v1/*. It’s the same surface our @vorel/sdk TypeScript client uses, and the same surface your custom integrations should target.
If you are connecting an AI client rather than writing an integration, see MCP.
Quickstart
1
Generate an API key
Sign in at
app.vorel.ai, navigate to Settings → Integrations → API keys, click Create API key. Pick the scopes your integration needs: read, leads:write, appointments:write, offerings:write, conversations:write, crm:write, assistant:read. Copy the key; it’s shown only once (scrypt-hashed in storage).The key format is vapk_live_<48 hex chars> (58 chars total). See Authentication for the full lifecycle.2
Make your first request
3
Browse the full reference
The API Reference tab in this docs site auto-renders from our live OpenAPI spec: every endpoint, every parameter, every response shape, with interactive “try it” examples per route.
What the API exposes
Conversations
Read inbound conversations across voice + chat. List, get-by-id, create (pre-create from your
CRM webhook), update.
Leads
Read + write leads. Update qualification state, attach attributes, trigger handoff, mark stale.
Appointments
Read + write appointments. Schedule, reschedule, cancel, complete. Lifecycle webhooks emit on
every transition.
Offerings
Read + write your catalog (properties / services / treatments / menu items, vertical-specific).
Soft-delete supported.
Analytics
GET /v1/analytics/weekly-rollup: aggregate metrics for the prior N days. Point your own reporting at this.CRM proxy
POST /v1/crm/create-record: write into your tenant’s connected CRM via Vorel’s per-tenant
driver layer. Same path the agent uses.Conventions
Auth
All endpoints requireAuthorization: Bearer <api_key>. Keys are tenant-scoped; one key only sees its own tenant’s data, enforced via Postgres RLS.
Endpoints that mutate state require a write scope (leads:write, appointments:write, offerings:write, conversations:write). Endpoints that only read accept the read scope. A key without the matching scope returns a 403 forbidden envelope.
Response shapes
Successful responses are JSON. List endpoints use cursor pagination:next_cursor and has_more are top-level fields alongside data (not nested under a pagination object). Pass next_cursor back as ?cursor=<uuid> to fetch the next page; has_more is false and next_cursor is null when you’ve reached the end.
Single-resource endpoints return the resource directly.
Error envelope
Every error returns a consistent shape:unauthorized, forbidden, rate_limited, bad_request, not_found, conflict, internal_error. The HTTP status code matches the semantic.
Idempotency
POST /v1/crm/create-record accepts an idempotency_key field in the request body. The value is forwarded into the per-tenant CRM driver so the underlying CRM can dedupe its own write. Other write endpoints don’t currently accept an idempotency key; safe-retry semantics there rely on the resource’s natural unique constraints (e.g. (tenant_id, channel, customer_identifier) for conversations).
Webhooks
The API also emits outbound webhooks to URLs you register at/(dashboard)/settings/integrations/webhooks. 19 event types spanning leads, conversations, bookings, calls, outbound attempts, SLA breaches, CSAT and catalog changes. See Webhooks for the full table. Bodies are HMAC-SHA256 signed via X-Webhook-Signature; the envelope id field doubles as the consumer’s idempotency key.
See Webhooks for the full spec.
Rate limits
API requests are gated by a layered rate-limit stack. The most-restrictive applicable layer wins:
The limiter is fail-open: a cache blip admits the request rather than 429-ing every caller. Hitting a limit returns
429 rate_limited with Retry-After + X-RateLimit-Limit + X-RateLimit-Remaining + X-RateLimit-Reset headers. See Rate limits for the detailed stack.
SDKs
TypeScript / JavaScript
@vorel/sdk is a full-coverage, typed client with zero runtime deps. Today the REST API plus
the live OpenAPI spec are the supported integration path; a published @vorel/sdk package is
on the roadmap.OpenAPI (any language)
Live OpenAPI 3.1 spec. Import into Postman / Insomnia / Bruno, or generate a client in any
language via
openapi-generator / oazapfts / etc.Common integration patterns
Push a lead from your website form
Push a lead from your website form
Call
POST /v1/conversations to pre-create the conversation from your form’s
customer-identifier (phone/email), then POST /v1/leads to attach the qualification data. The
next time the customer calls or WhatsApps, Vorel matches them to the existing conversation by
(channel, customer_identifier). No fragmentation.Get notified when a new lead qualifies
Get notified when a new lead qualifies
Subscribe to the
lead.qualified webhook event. Vorel POSTs to your URL with the lead row + the
conversation’s last 10 messages. HMAC-signed; verify the signature before acting.Send a booking reminder
Send a booking reminder
Build this as a trigger rule rather than in code. The
booking.created
event carries the scheduled start, so a rule with relative timing fires a set number of hours
before the appointment. If you would rather own the send, subscribe to booking.created and call
POST /v1/conversations/{id}/send on your own schedule.Re-engage stale leads
Re-engage stale leads
GET /v1/leads?stale_for_days=3 returns qualified leads whose conversation has gone quiet for
more than N days. Pair it with POST /v1/conversations/{id}/send. The filter already scopes to
qualified leads, so no separate status filter is needed, and none is supported today.Weekly analytics digest
Weekly analytics digest
GET /v1/analytics/weekly-rollup on a Monday schedule, formatted and sent wherever you want it.
Vorel also ships its own daily digest if you do not need a custom format.Status
The API is live and stable. Allv1/* endpoints have stable contracts; we’ll version-bump (/v2) before any breaking change.
Public status page: app.vorel.ai/status. Expect ~99.9% on the API surface (per our SLOs).