{"openapi":"3.1.0","info":{"title":"Corva API","version":"v1","description":"Connect a business's website to its Corva AI assistant: chat, leads, visitors and voice. Every call is made from your server with the business's API key."},"servers":[{"url":"https://corva.tiruvi.site"}],"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","description":"ck_… from Corva → Settings → Website & API keys"}}},"paths":{"/api/v1/health":{"get":{"summary":"Check your key and what you can use","description":"The first call to make. Confirms the key, and says which features this business has — call it when your site starts, and hide the voice button when `features.voice` is false.","security":[{"apiKey":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"ok":true,"business":"Tumble Days","assistant":"Tumbly","phoneNumber":"+91 40 7573 2715","knowledgeDocuments":2,"features":{"chat":true,"leads":true,"voice":true,"voiceSecure":true},"apiVersion":"v1"}}}},"400":{"description":"The request is wrong — the message says how."},"401":{"description":"Missing, invalid or revoked API key."},"429":{"description":"Too many requests — 120 a minute per key."}}}},"/api/v1/chat":{"post":{"summary":"Talk to the business's AI agent","description":"Send one customer message, get the agent's reply. The agent answers only from the business's knowledge (managed in Corva), keeps within its limits, and hands over to the team when it should. Keep one `sessionId` per chat.\n\nWhen it has everything for a booking or a callback it returns a `proposal` instead of making it: show the details on a card with Confirm and Edit, and send the answer to `POST /api/v1/chat/confirm`. Until then nothing is booked. A new message replaces an unanswered card.\n\nWith `stream: true` the answer is `text/event-stream`: `delta` events ({ text }) as the reply is written, a `proposal` event when a card should show, then `done` with the same body as the JSON answer (or `error`).","security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["sessionId","message"],"properties":{"sessionId":{"description":"string — Your id for this chat, 6–80 of [A-Za-z0-9_-]. Reuse it for every message in the chat."},"message":{"description":"string — What the customer typed. Up to 2,000 characters."},"visitorId":{"description":"string — Your visitor cookie value, to join the chat to their visit."},"customer":{"description":"object — { name?, phone?, email? } — what you already know about them."},"stream":{"description":"boolean — Answer as server-sent events, to show the reply as it is written."}}},"example":{"sessionId":"chat_8c1f2a","message":"Pick up 3 shirts tomorrow 8–10 AM from B-402 Palm Grove, Sector 70. I'm Riya, 98765 43210","visitorId":"v_3f9c0a1b2c3d4e5f6a7b8c9d"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"conversationId":"0b7c…","reply":"Please check the details and tap Confirm.","heldBy":null,"actions":[],"escalation":null,"closed":false,"proposal":{"id":"5f0e…","kind":"booking","noun":"pickup","details":{"name":"Riya","phone":"98765 43210","address":"B-402 Palm Grove, Sector 70, Gurugram","services":["Laundry"],"date":"2026-10-01","timeSlot":"8–10 AM","notes":"3 shirts"}}}}}},"400":{"description":"The request is wrong — the message says how."},"401":{"description":"Missing, invalid or revoked API key."},"429":{"description":"Too many requests — 120 a minute per key."}}},"get":{"summary":"Replies from a person who took the chat over","description":"When a person on the team takes a chat over, `POST /api/v1/chat` returns `heldBy` and no `reply`. Poll this every few seconds for what they write.","security":[{"apiKey":[]}],"parameters":[{"name":"sessionId","in":"query","required":true,"description":"The chat's sessionId.","schema":{"type":"string"}},{"name":"after","in":"query","required":false,"description":"Only messages after this ordinal. Start at -1.","schema":{"type":"number"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"heldBy":"Kavya Rao","ended":false,"messages":[{"ordinal":4,"from":"Kavya Rao","text":"Hi Riya, I can help with that."}]}}}},"400":{"description":"The request is wrong — the message says how."},"401":{"description":"Missing, invalid or revoked API key."},"429":{"description":"Too many requests — 120 a minute per key."}}}},"/api/v1/chat/confirm":{"post":{"summary":"The customer's Confirm or Edit on a card","description":"Confirm makes what the card shows: the customer's record, a lead with an owner on the team, a follow-up on that person's list, a confirmation email to the customer and a note to the owner. The `reply` is the line to show in the chat. Edit tells the agent they want to change something — show the `reply` and let them type. Confirming the same card again returns the first result with `duplicate: true`.","security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["sessionId","proposalId","approved"],"properties":{"sessionId":{"description":"string — The chat's sessionId."},"proposalId":{"description":"string — `proposal.id` from the chat reply."},"approved":{"description":"boolean — true for Confirm, false for Edit."},"visitorId":{"description":"string — Your visitor cookie, to join the booking to their visit."}}},"example":{"sessionId":"chat_8c1f2a","proposalId":"5f0e…","approved":true,"visitorId":"v_3f9c0a1b2c3d4e5f6a7b8c9d"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"conversationId":"0b7c…","reply":"Done — your pickup is booked. Your reference is **TD-7K3QX9**. Kavya from our team will call you shortly to confirm. A confirmation is on its way to your inbox.","proposal":{"id":"5f0e…","status":"confirmed"},"receipt":{"reference":"TD-7K3QX9","owner":"Kavya Rao","emailed":true},"duplicate":false}}}},"400":{"description":"The request is wrong — the message says how."},"401":{"description":"Missing, invalid or revoked API key."},"429":{"description":"Too many requests — 120 a minute per key."}}}},"/api/v1/leads":{"post":{"summary":"Send a booking, callback request or enquiry","description":"For your own forms, or your own AI's actions. Corva finds or creates the customer by phone, opens (or updates) their lead with an owner on the team, puts a follow-up on that person's list, emails the customer a confirmation and tells the owner. Safe to retry: sending the same `reference` again returns the first result with `duplicate: true`.","security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["kind","name","phone"],"properties":{"kind":{"description":"\"pickup\" | \"callback\" | \"enquiry\" — What they asked for."},"name":{"description":"string — Their name."},"phone":{"description":"string — Their mobile, any common Indian format."},"email":{"description":"string — Where the confirmation goes. Strongly recommended."},"reference":{"description":"string — Your reference for this request — also the idempotency key."},"services":{"description":"string[] — What needs doing."},"address":{"description":"string — For a pickup or visit."},"pickupDate":{"description":"string — YYYY-MM-DD."},"timeSlot":{"description":"string — e.g. \"8–10 AM\"."},"preferredTime":{"description":"string — For a callback, e.g. \"today after 6 PM\"."},"topic":{"description":"string — What they want to talk about."},"notes":{"description":"string — Anything else."},"promoCode":{"description":"string — An offer code they used."},"visitorId":{"description":"string — Your visitor cookie, to join the request to their visit."},"sessionId":{"description":"string — The chat it came from, if any."}}},"example":{"kind":"pickup","name":"Riya Sharma","phone":"98765 43210","email":"riya@example.com","services":["Laundry: Wash, Fold & Ironing"],"address":"B-402, Palm Grove, Sector 70, Gurugram","pickupDate":"2026-10-04","timeSlot":"8–10 AM","reference":"TD-7K3QX9","visitorId":"v_3f9c0a1b2c3d4e5f6a7b8c9d","sessionId":"chat_8c1f2a"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"reference":"TD-7K3QX9","customerId":"a734…","leadId":"c505…","followUp":{"id":"0472…","assignee":"Kavya Rao","dueAt":"2026-10-03T05:30:00.000Z"},"emailed":{"customer":true,"team":true},"duplicate":false}}}},"400":{"description":"The request is wrong — the message says how."},"401":{"description":"Missing, invalid or revoked API key."},"429":{"description":"Too many requests — 120 a minute per key."}}}},"/api/v1/chats":{"post":{"summary":"Mirror your own chat's transcript","description":"If your site runs its own chat assistant, send the whole transcript after each reply. Corva keeps one conversation per `sessionId` (replacing the transcript each time), so the team can read every chat live and see where a request came from.","security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["sessionId","messages"],"properties":{"sessionId":{"description":"string — Your chat id."},"visitorId":{"description":"string — Your visitor cookie."},"messages":{"description":"{ role: \"user\" | \"assistant\", text: string }[] — The whole conversation so far."}}},"example":{"sessionId":"chat_8c1f2a","visitorId":"v_3f9c0a1b2c3d4e5f6a7b8c9d","messages":[{"role":"user","text":"Do you clean silk sarees?"},{"role":"assistant","text":"Yes — they go to our premium dry-cleaning."}]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"conversationId":"e57e…","turns":2}}}},"400":{"description":"The request is wrong — the message says how."},"401":{"description":"Missing, invalid or revoked API key."},"429":{"description":"Too many requests — 120 a minute per key."}}}},"/api/v1/visits":{"post":{"summary":"Record a visitor, with their cookie consent","description":"Tell Corva a visitor is on the site. With `consent: \"necessary\"` only the visitor id is kept. With `\"all\"` (they accepted analytics cookies), the page, referrer and utm_ campaign are kept too, and show on the customer's record once they identify themselves. Always send the consent your banner actually recorded.","security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["visitorId","consent"],"properties":{"visitorId":{"description":"string — Your first-party visitor id (8–80 chars)."},"consent":{"description":"\"necessary\" | \"all\" — What they chose on your cookie banner."},"type":{"description":"string — \"page_view\" (default) or \"consent\"."},"path":{"description":"string — Only kept with consent \"all\"."},"referrer":{"description":"string — Only kept with consent \"all\"."},"utm":{"description":"object — utm_source, utm_medium, utm_campaign… Only kept with consent \"all\"."}}},"example":{"visitorId":"v_3f9c0a1b2c3d4e5f6a7b8c9d","consent":"all","type":"page_view","path":"/","referrer":"https://instagram.com","utm":{"utm_source":"instagram"}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"recorded":true}}}},"400":{"description":"The request is wrong — the message says how."},"401":{"description":"Missing, invalid or revoked API key."},"429":{"description":"Too many requests — 120 a minute per key."}}}},"/api/v1/voice-sessions":{"post":{"summary":"Start a voice call from the visitor's browser","description":"Your server asks for a token (the API key must never reach the browser), and hands `token` and `bridgeUrl` to the page, which opens a WebSocket to the bridge and speaks to the assistant. Tokens last five minutes and work for one call. See “Voice calls in the browser” below for the protocol.","security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":[],"properties":{"visitorId":{"description":"string — Your visitor cookie."},"name":{"description":"string — Their name, if known — the assistant greets them by it."},"phone":{"description":"string — Their number, if known — joins the call to their record."}}},"example":{"visitorId":"v_3f9c0a1b2c3d4e5f6a7b8c9d","name":"Riya Sharma","phone":"9876543210"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"token":"eyJicmFuZElkIjoi…","expiresInSeconds":300,"bridgeUrl":"wss://voice.example.com","agentName":"Tumbly"}}}},"400":{"description":"The request is wrong — the message says how."},"401":{"description":"Missing, invalid or revoked API key."},"429":{"description":"Too many requests — 120 a minute per key."}}}}}}