Документація з інтеграції
Ідентифікатор бізнесу та секрет вебхука знаходяться в Налаштування → Кінцеві точки вебхука.
Увійдіть, щоб отримати ідентифікатор бізнесу та секретний ключОгляд
Every business has its own webhook secret and its own set of endpoints, identified by the business id in the URL. Copy the exact URLs and the secret from Settings → Webhook endpoints. There are no shared or global endpoints: a request is only ever attributed to the business named in the URL, and it must be signed with that business's secret.
If you sync your agent from Settings we configure the voice platform for you — the sections below are for reference, for custom integrations, and for testing. All examples use https://ordervoice.aarnikainnovations.com; on a self-hosted deployment substitute your own origin.
Автентифікація та захист від повторного відтворення
Two schemes are accepted on every inbound endpoint. Shared secret: send your webhook secret verbatim in x-vapi-secret (this is what Vapi does). HMAC: sign the raw request body with HMAC-SHA256 keyed by your secret, hex-encoded, in x-webhook-signature, and send the current Unix time in seconds in x-ov-timestamp. The timestamp must be within ±5 minutes of our clock, and a given signature is accepted once — a replay inside the window answers 409.
x-webhook-signature: hex(hmac_sha256(raw_body, <your-webhook-secret>)) x-ov-timestamp: <unix seconds, required with x-webhook-signature>
Unsigned requests are never accepted. An unknown business id, a missing secret and a wrong secret all answer the same 401, so the endpoint cannot be used to discover which ids exist.
Vapi
Set your assistant's server URL to your business endpoint and its server secret to your webhook secret. Vapi sends the secret verbatim in the x-vapi-secret header on every request.
POST https://ordervoice.aarnikainnovations.com/api/webhooks/vapi/<business-id> x-vapi-secret: <your-webhook-secret>
We handle the status-update, end-of-call-report and tool-calls server messages. The agent's create_order, create_reservation, take_message, lookup_order, cancel_order and transfer tools post through this same URL; we reply with the confirmation text the agent reads back to the caller. Message types we don't use are acknowledged with 200 and { "ok": true, "ignored": true }.
Загальні кінцеві точки HMAC
For any other platform, or your own code, post directly to the five event endpoints:
POST https://ordervoice.aarnikainnovations.com/api/public/webhook/<business-id>/call-started POST https://ordervoice.aarnikainnovations.com/api/public/webhook/<business-id>/call-ended POST https://ordervoice.aarnikainnovations.com/api/public/webhook/<business-id>/order-created POST https://ordervoice.aarnikainnovations.com/api/public/webhook/<business-id>/reservation-created POST https://ordervoice.aarnikainnovations.com/api/public/webhook/<business-id>/message-taken
Aliases. id is accepted in place of call_id, order_id, reservation_id or message_id; from and to in place of from_number and to_number.
Ping. A signed body of { "type": "ping" } to call-started answers { "ok": true, "pong": true } without creating anything — this is what the "Test webhook" button in Settings sends.
Коди стану та обмеження швидкості
200 handled (the JSON body says what happened); 400 the body isn't valid JSON, or a required field is missing; 401 the signature, secret, timestamp or business id doesn't check out; 403 the business is suspended; 404 the URL is malformed (the id isn't a UUID); 409 replayed signature; 413 body over 1 MB; 429 rate limited — back off and retry after the retry-after seconds; 500 something failed on our side (the body is { "ok": false, "error": "internal" }; retry later).
Rate limits. Inbound webhooks: 120 requests burst, refilling 4 per second, per business per source IP; and 600 burst / 20 per second per business across all sources. Public status pages (/order/…, /booking/…): 60 burst, 1 per second per IP. The contact form: 5 per IP, refilling one every 10 minutes.
Приклад: замовлення створено
SECRET="your-webhook-secret"
BODY='{
"call_id": "call_abc123",
"order_id": "ord_789",
"customer_name": "Maria",
"customer_phone": "+14155550123",
"channel": "pickup",
"items": [
{ "name": "Margherita", "quantity": 2,
"modifiers": [{ "group": "Size", "name": "Large" }] }
],
"notes": "Ring the doorbell"
}'
TS=$(date +%s)
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$SECRET" -hex | sed 's/^.* //')
curl -X POST "https://ordervoice.aarnikainnovations.com/api/public/webhook/<business-id>/order-created" \
-H "Content-Type: application/json" \
-H "x-webhook-signature: $SIG" \
-H "x-ov-timestamp: $TS" \
-d "$BODY"Items are matched against your live catalog and priced server-side in your currency, including your tax, fee and rounding rules. Every order starts as pending; when an item or modifier doesn't match your catalog the order is kept but starts as needs_review so nothing is silently lost. A status field in the payload is ignored — status is only ever changed from the dashboard. channel is optional: pickup, delivery, dine_in or other; add service_address for delivery.
Duplicate deliveries (the same order_id for the same business) are idempotent: the second delivery is acknowledged with { "ok": true, "duplicate": true } and creates nothing. The same order_id at a different business is a different order.
Приклад: бронювання створено
{
"reservation_id": "res_456",
"customer_name": "Sam",
"customer_phone": "+14155559876",
"party_size": 4,
"reserved_for": "<ISO 8601 with offset, e.g. 2026-10-01T19:30:00-07:00>",
"duration_minutes": 90,
"resource": "Window table",
"service_name": "Dinner",
"notes": "Window table if possible"
}reserved_for is ISO 8601. Include a timezone offset; if it is missing we interpret the time in your business's timezone. duration_minutes, resource and service_name are optional (the sector default duration applies). Bookings start as confirmed, and duplicates are idempotent per business exactly like orders.
Приклад: повідомлення прийнято
{
"message_id": "msg_321",
"customer_name": "Dana",
"customer_phone": "+14155551234",
"topic": "Catering quote for 40",
"message": "Looking for a quote for a Saturday lunch, 40 people.",
"contact": "Sales"
}Creates a message in your inbox and emails it to the contact the agent picked (Settings → Agent behavior). contact is matched by label against your configured contacts; unknown labels fall back to the owner. Idempotent per message_id.
Події дзвінків
call-started expects call_id, from_number and to_number. call-ended adds duration_seconds, transcript, language, status and optionally a recordingUrl (played back in the dashboard when recording is enabled for the business). Phone numbers are normalised to E.164 using the business's country.
Events may arrive out of order: if call-ended lands before call-started, the two are merged into one call by call_id within your business. Repeated call-started deliveries for the same call_id are idempotent.
Ваш власний оркестратор (LiveKit, Exotel, Gnani, Bolna)
OrderVoice is the brain; the audio pipeline can be anyone's. A self-hosted LiveKit + Sarvam worker, Exotel AI, an Exotel + Gnani enterprise stack or a Bolna agent all use the same three calls, authorised with the business's webhook secret as a bearer token. Pick the stack under Settings → Phone → Voice stack.
- Read the agent spec before each call (it is rebuilt from the live menu, hours and settings on every fetch):
GET /api/agent/<business_id>/config Authorization: Bearer <webhook secret> { "agent": { "systemPrompt", "greeting", "endCallMessage", "idleMessages", "language", "transferDestinations", … }, "speech": { "engine": "sarvam", "sarvam": { "speaker": "anushka", "languageCode": "hi-IN" } }, "tools": [ { "name": "create_order", "description", "parameters", "method": "POST", "url": ".../api/webhooks/tool/<business_id>/create_order" } ], "events": { "callStarted": ".../call-started", "callEnded": ".../call-ended" } } - Call tools when the model asks for one. The body is the tool's arguments; the reply carries the handler's JSON plus
result, the sentence the agent should read back. Nothing is confirmed to the caller that the backend did not confirm first.POST /api/webhooks/tool/<business_id>/create_reservation Authorization: Bearer <webhook secret> Content-Type: application/json { "customer_name": "Ravi", "party_size": 4, "reserved_for": "2026-10-12T19:30", "call_id": "abc" } → { "ok": true, "reservationId": "…", "result": "Booked: table for 4 on Sunday 12 October at 7:30 PM. Reference 3F9A2C." } - Report the call so the dashboard, CRM and analytics see it: POST
call-startedwhen it connects andcall-endedwith the transcript, duration and outcome (see Call events above). Bolna agents do this automatically through their webhook.
Вихідні: ваша POS, PMS або CRM
Set an endpoint under Settings → Integrations and every order, booking and message the agent captures is POSTed there as JSON, signed with the same webhook secret in X-Webhook-Signature (sha256 HMAC of the raw body, hex) with the send time in X-Webhook-Timestamp. A Zapier, Make or n8n catch-hook works as-is; a direct endpoint should verify the signature, reject timestamps older than a few minutes, and return 2xx.
POST <your endpoint>
X-Webhook-Event: order.created | reservation.created | reservation.updated | message.created | test.ping
X-Webhook-Signature: <hex hmac-sha256 of body>
X-Webhook-Timestamp: <unix seconds>
{
"event": "message.created",
"business_id": "<business-id>",
"restaurant_id": "<business-id>",
"sent_at": "<ISO 8601>",
"data": {
"message_id": "…", "customer_name": "Dana", "customer_phone": "+14155551234",
"topic": "Catering quote for 40", "message": "…", "contact": "Sales"
}
}business_id is the canonical tenant id; restaurant_id carries the same value and stays for integrations written before the product served more than restaurants. Order payloads include currency and line_total_cents per item; booking payloads include ends_at, duration_minutes and resource. Deliveries show under Settings → Webhook endpoints with provider outbound.
Повторні спроби та відтворення
A delivery that fails (timeout, connection error or a 5xx/429 from your endpoint) is retried automatically on a backoff schedule — immediately, then after 5 s, 30 s, 5 min, 30 min, 2 h, 8 h and 12 h — up to 8 attempts over roughly a day. A 4xx other than 429 is not retried. After the last attempt the delivery is marked failed and stays visible under Settings → Webhook endpoints, where you can replay it with one click once your endpoint is back. Payloads are identical on replay, so keep your handler idempotent on order_id / reservation_id / message_id.
Посилання на статус клієнта та SMS
Every order and booking has an unguessable public link — https://ordervoice.aarnikainnovations.com/order/<token> and https://ordervoice.aarnikainnovations.com/booking/<token> — that shows the customer its live status, your phone number and address, and (for bookings) an add-to-calendar and self-cancel option. The dashboard shows the link on each record; with SMS enabled it is texted to the customer automatically, and the delivery state (queued, sent, failed, skipped) appears on the record as sms_status. The links are never indexed by search engines and are rate-limited per IP.
Що нового
Review release: SMS, transfers, billing, per-sector pages
- SMS confirmations, order-ready and booking reminders (Twilio, when configured) with a public status link.
- Warm transfer with a summary, voicemail, after-hours mode and holiday hours.
- Look-up, reschedule and cancel tools for bookings; guest self-cancel page with add-to-calendar.
- Per-tenant tax, currency and rounding rules; money shown in your market's currency everywhere.
- Self-serve billing (Stripe): plan, invoices and overage in Billing.
- Retention control (retention_days), per-caller erasure, recording toggle and consent disclosure.
- Two-factor sign-in (TOTP), magic-link sign-in, resend verification, sector chosen at sign-up.
- Outbound webhooks now carry business_id and an x-ov-timestamp replay-protection header; 3 delivery attempts before a manual replay.
- New message-taken outbound event; rate limits documented; retry policy documented.
- Public per-sector landing pages (/for/…), a status page (/status), an honest integrations list and an ROI calculator.
- Privacy Policy and Terms updated: subprocessors, retention, governing law, DPA, SLA reference.
Knowledge Lab security
- Per-lab security policy and pgcrypto encryption of document chunk text.
- Hybrid search fix for document-grounded answers.
Nine sectors, markets and languages
- Sector registry: restaurants, clinics, salons, real estate, retail, home services, hotels, logistics and Standalone.
- Market picker with local plan prices; language prefix in every URL.
- Privacy Policy gained per-market rights sections.
Потрібна допомога?
Every delivery — accepted or rejected — is listed under Settings → Webhook endpoints with its status and error, so you can see exactly what we received. If something still doesn't line up, write to support@aarnikainnovations.com or use the contact form.