Hosts
Do not put
/v1 in KUPE_BASE_URL. Paths on this site are {base}/v1/....
Headers (diff)
Auth header
Kupe App accepted eitherx-api-key: <opaque> or a dashboard JWT.
Kupe Hub accepts one header on every /v1 route:
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.
