Skip to Content
Authentication

Authentication

Every request to a public Cloove API is authenticated with an API key passed as a bearer token:

Authorization: Bearer clv_live_sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

You create and manage keys in the Developer portal  under Developer → API keys, or programmatically via the Developer Portal API.

A key’s secret is shown only once, at creation (and on an explicit, password-protected reveal). Store it in a secrets manager - never commit it to source control or ship it in a browser or mobile client.

Key format

Keys are structured strings so you can recognize them at a glance:

clv_<environment>_<type>_<random>
SegmentValuesMeaning
clv-Identifies a Cloove key.
<environment>test · liveThe environment the key operates in.
<type>sk · pkSecret key (server-side) or public identifier.
<random>32 chars (secret)Opaque random string.

Example (test secret key):

clv_test_sk_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6

Authenticate with the secret key (sk). The environment is inferred from the prefix - a clv_test_… key only ever touches test data, and a clv_live_… key only touches production.

Scopes

Each key is granted a set of scopes that gate exactly what it can do. A request to an endpoint whose scope the key doesn’t hold returns 403 missing_scope.

Scopes are namespaced as resource:action (or resource:subresource:action). As a convenience, a namespace’s parent :read scope grants every child read scope in that namespace - for example, vox:read grants vox:calls:read, vox:numbers:read, and vox:agents:read. A parent read scope never grants a write or create scope.

ScopeGrants
vox:readAll Vox read access (calls, numbers, agents)
vox:calls:readRead voice calls
vox:calls:createPlace outbound calls
vox:agents:readRead AI agents
vox:numbers:readRead voice numbers
messaging:readAll messaging read access
messaging:conversations:readRead WhatsApp conversations
messaging:messages:readRead messages
messaging:messages:sendSend text and template messages
contacts:readRead contacts/customers
contacts:writeCreate and update contacts
products:readRead products
products:writeCreate and update products
orders:readRead orders/sales
orders:writeRecord orders/sales
wallet:readRead wallet balance
payouts:readRead payout (bank) accounts
payouts:writeManage payout accounts
wallet:withdrawals:readRead withdrawals
wallet:withdrawals:createInitiate withdrawals
webhooks:readRead webhook configuration
webhooks:writeManage webhook endpoints

Grant a key the least privilege it needs. A backend that only places calls needs vox:calls:create (and perhaps vox:calls:read), nothing more.

Access controls

Beyond scopes, a key can be locked down further when you create or update it:

  • Allowed IP ranges - restrict use to specific IPs or CIDR ranges. Requests from other addresses get 403 ip_not_allowed.
  • Allowed origins - restrict by Origin/Referer host. Other origins get 403 origin_not_allowed.
  • Expiry - set an expires_at; the key stops working after that time (401 expired_api_key).

Finance write scopes require an IP allowlist on live keys. Any live key granted payouts:write or wallet:withdrawals:create must define at least one allowed IP range - key creation is rejected otherwise. Initiating withdrawals additionally requires a per-key withdrawal policy. See Wallet & payouts.

Developer portal authentication

The endpoints under /api/developer that manage keys, apps, and webhook endpoints are not authenticated with an API key. They use your dashboard session (a JWT bearer token) plus the MANAGE_DEVELOPER_KEYS permission and an active business context. This keeps key management gated behind a real, logged-in operator. See the Developer Portal API.

Last updated on