Skip to main content

Hosts

Do not put /v1 in KUPE_BASE_URL. Paths on this site are {base}/v1/....

Headers (diff)

Auth header

Kupe App accepted either x-api-key: <opaque> or a dashboard JWT. Kupe Hub accepts one header on every /v1 route:
Project keys start with sk-kupe- and are scoped to one org and one project. Hub sessions may send a Supabase user JWT instead (auth: jwt on GET /v1/me). Voice clone / patch / delete require JWT. See Authentication. Kupe App keys are not valid on x.kupe.in. Create a new key in Hub: project → API keys.

Identity model

Resolve IDs once, then reuse them:

CORS and create_call

Kupe App POST /api/call/create_call is on the auth exclude list (middleware skips JWT/x-api-key), then the handler resolves identity itself (x-api-key or Bearer) and rejects unknown Origin via validate_origin. Browser apps had to be on the CORS allow-list (api.kupe.in plus verified custom domains). Kupe outbound is a normal authenticated /v1 route. Send the Bearer key; there is no Origin gate on the public API the way Kupe App implemented create_call.

Public vs provider webhooks

Kupe App left telephony answer URLs unauthenticated on purpose (/api/call/incoming_call, /api/call/plivo-incoming_call, /api/call/plivo-hangup, Exotel/Elison variants). Kupe does the same for provider callbacks (/v1/telephony/plivo/inbound, /v1/plivo/webhooks/ucc, …). Those paths are not in the public OpenAPI and you should not call them from your app — Plivo/Twilio/Exotel call them. Your app should only call documented /v1/... routes with a Bearer key.