API
API reference
Auto-generated from the live OpenAPI spec served by the product app, always in sync, because the spec is the source of truth.
Quick start
Everything you need before you call your first endpoint.
Authentication
All requests use a Bearer token. Create one in the app under Settings → API & Webhooks (workspace owners and admins only) and send it on every request:
Authorization: Bearer xyra_live_…Keys are workspace-scoped and can be rotated or revoked at any time. Never embed a key in client-side code.
API access is included on the Edge, Prime and Infinite plans.
Rate limits
Every response carries the standard X-RateLimit-* headers. Default ceilings:
- • 600 read requests / minute per API key
- • 120 write requests / minute per API key
- • Over the limit:
429withRetry-After
Need higher? Email hello@xyrachat.com , we'll raise it.
Webhooks
Subscribe an HTTPS endpoint to any of 17 events, such as message.received or bot.handoff. Every delivery is signed:
X-Xyra-Signature: t=1760000000,v1=5f2c…Signing, retries and the full event list are below.
Your first request
List the most recent conversations in your workspace:
curl -X GET https://app.xyrachat.com/api/v1/conversations \
-H "Authorization: Bearer $XYRA_API_KEY" \
-H "Accept: application/json"You should get a JSON list back. If not, the error body tells you what to fix.
Webhooks
Signed deliveries, retried until they land.
Add an endpoint under Settings → API & Webhooks. Its signing secret is shown once, when you create it, so store it straight away.
Headers on every delivery
X-Xyra-Signature- t=<unix seconds>,v1=<hex HMAC-SHA256>
X-Xyra-Timestamp- the same unix seconds as t
X-Xyra-Event- the event name, e.g. message.received
X-Xyra-Event-Id- unique per event, the same on every retry
Retries carry the same X-Xyra-Event-Id, so store it and ignore an id you have already processed.
Verifying the signature
Compute an HMAC-SHA256, keyed with the endpoint's signing secret, over <t>.<raw request body>, and compare it with v1. Reject deliveries whose t is more than 5 minutes old.
import crypto from "node:crypto";
// rawBody: the body exactly as received, not parsed
function verifyXyraWebhook(rawBody, signatureHeader, secret) {
const parts = Object.fromEntries(
signatureHeader.split(",").map((p) => p.split("="))
);
const t = Number(parts.t);
// Reject anything older (or newer) than 5 minutes
if (!t || Math.abs(Date.now() / 1000 - t) > 300) return false;
const expected = crypto
.createHmac("sha256", secret)
.update(`${t}.${rawBody}`)
.digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(parts.v1 ?? "");
return a.length === b.length && crypto.timingSafeEqual(a, b);
}Delivery and retries
- • Your endpoint has 10 seconds to respond.
- • Any
2xxcounts as delivered. - •
410 Gonestops delivery and pauses the endpoint. - • Any other
4xxis not retried. - • A
5xxor a timeout is retried after 30 s, 1 min, 5 min, 30 min, 2 h, 6 h, 12 h and 24 h.
All 17 events
Messages
message.receivedmessage.sent
Conversations
conversation.openedconversation.closedconversation.assignedconversation.unassigned
Contacts
contact.createdcontact.updatedcontact.taggedcontact.opted_out
Bot
bot.handoffbot.lead_capturedbot.link_clickedbot.qualified
Workspace
broadcast.completedchannel.disconnectedautomation.fired
Full reference
Every endpoint, every model.
Browse, search and try schemas below, themed to feel like the rest of Xyra Chat.