Authentication and keys

Bearer API keys, scopes, live and test environments, App pinning, IP allowlists, expiry, rotation, and what happens when a key's owner leaves.

Every request is authenticated with an API key, sent as a bearer token:

GET /backend/v2/me HTTP/1.1
Host: app.gauge.chat
Authorization: Bearer pulse_k_live_9c2Rk1...

A request without a key, or with an unknown, revoked or expired one, gets 401 unauthorized.

Who can create keys

  • The workspace must be on a paid plan. The API is available on Growth and Scale. On Free, every request answers 402 plan_required (Plans).
  • The member must be allowed to manage API keys. Keys are created in Developers → API keys by a member whose role includes the API keys permission.

Keys belong to a person

A key is not a free-floating credential. It acts as the member who created it:

  • It can only do what that member can do in the console. A key never sees a conversation its member could not open, so a key made by an Agent who sees only their own conversations sees only those.
  • Contacts are the exception the console already makes: every member with contact access sees the whole workspace's contacts, and so does their key.
  • If the member is deactivated or removed, every key they made stops working at once with 401 key_owner_inactive. Create a new key under an active member and swap it in.

Plan for people leaving

Create integration keys from a member who will stay, such as an owner or a dedicated integration seat, and keep a note of who owns which key. The API keys list shows each key's creator.

Scopes

A key carries a list of scopes; each endpoint needs one. The scope a route needs is shown on every reference page (x-scopes). A key's power is its scopes and its member's role, together: a scope the member's role cannot use grants nothing.

ScopeLets the keyNeeds this in the member's role
conversations:readList and open conversations the member can seeConversations · view
conversations:writeChange status, assignee and tags; mark readConversations · view, create, edit
messages:readRead message history and delivery status, and download a message's filesConversations · view
messages:writeSend messages and templates as the memberConversations · view, create
contacts:readList, search and open contactsContacts · view
contacts:writeCreate, edit, upsert, tag and merge contacts. Erasing one (DELETE) also needs the member to hold the erasure right (Owner or Admin)Contacts · view, create, edit
connections:readSee connected channels and what each can sendConversations · view
templates:readSee approved WhatsApp templatesConversations · view
media:readGet short-lived links to files you uploaded with POST /v2/mediaConversations · view
media:writeUpload files to attach to messagesConversations · view, create
webhooks:readList webhook endpoints and their delivery stateSettings · view
webhooks:writeCreate, change, test and rotate webhook endpoints; redeliver eventsSettings · view, edit
events:readList and read the last 30 days of eventsSettings · view

Write includes read. messages:write also grants messages:read.

Wildcards. *:read grants every area's :read scope, and *:write grants every area scope. They are capped at use to exactly what the member holds, so a wildcard can never reach further than the member's role.

Spending scopes. sms-send and voice-dial are reserved for SMS and calls over the API, which open after a compliance review. They are granted only by name: no wildcard, and no key created as "full access", ever includes them.

You cannot grant what you do not have. When you create a key, the console offers only the scopes your own role can use. Asking for more over the console API answers 400 validation_failed with "Your role cannot grant: …".

When a key calls a route without the scope it needs, the answer is 403 insufficient_scope, and error.details.required names the missing scope.

Version 1 scopes

Keys made for /v1 carry v1 scopes such as contacts:rw or support:read. They keep working on /v1. A v1 <area>:rw scope also counts as <area>:write on /v2.

Environments

Every key is live or test, fixed when it is created and visible in its prefix:

Live keyTest key
Prefixpulse_k_live_pulse_k_test_
ReachesYour real workspace dataSandbox data only
GET /v2/me key.environmentlivetest

Test keys

A test key works only on endpoints that support the sandbox. Elsewhere it answers 403 forbidden with reason: sandbox_key_not_supported; nothing it does can reach a real customer. Test keys are accepted by /v2/me, /v2/connections, /v2/templates and the Support API.

Test keys are refused on every messaging and webhook route: contacts, conversations, messages, media, /v2/webhook-endpoints and /v2/events. There is no sandbox send: a send always reaches a real customer, so it needs a live key. To try a send safely, send to your own number or address on a live key.

Key prefixes

Keys are issued as pulse_k_live_… and pulse_k_test_… today. A gauge_live_ / gauge_test_ prefix is planned; when it ships, existing keys keep working unchanged.

Pinning a key to an App

If you use the Support API, you can pin a key to one App (a support project). A pinned key sees only that App's data: on /v2/connections, only the App's chat line. On /v2 a key may be pinned to one App; a key pinned to several answers 403 forbidden with reason: key_pinned_to_projects. GET /v2/me returns the pin as key.pinnedAppId.

A pinned key can read /v2/me and /v2/connections, and manage the webhook endpoints and events of its own App. It is refused on the messaging routes (contacts, conversations, messages, media, templates) with 403 forbidden and reason: key_pinned_to_projects: a contact or a conversation belongs to no single App. Use an unpinned key for messaging.

IP allowlist

Give a key a list of up to 20 IPv4 or IPv6 addresses or CIDR ranges (203.0.113.7, 198.51.100.0/24, 2001:db8::/32), and it works only from those addresses. A request from anywhere else answers 403 forbidden with reason: ip_not_allowed. An empty list means any address.

Expiry

A key can expire after 30, 60, 90 or 365 days, or never. After its expiry it answers 401 unauthorized. Expiring keys are a good default for anything that is not a long-lived server integration.

Rotating a key

Rotate (roll) a key from its row in Developers → API keys. Rolling issues a new secret for the same key: same name, scopes, pin, allowlist and usage history. You choose how long the old secret keeps working alongside the new one:

OverlapUse it when
0 hoursThe key leaked. The old secret stops at once.
1 hourYou can redeploy within the hour.
24 hoursA normal scheduled rotation.
72 hoursSeveral systems share the key and take time to update.

During the overlap both secrets authenticate. Deploy the new one, then let the old one lapse.

To stop a key for good, revoke it. Revocation is immediate and cannot be undone.

Keeping keys safe

  • Keep keys on your server. Never ship one in a browser bundle, a mobile app, or a public repository.
  • One key per integration, so you can rotate or revoke one without breaking the others.
  • Grant the fewest scopes that work, and add an IP allowlist for fixed servers.
  • Every request a key makes is in Developers → Logs for 14 days, by key, status and request id.

Authentication errors

Statuserror.codereasonMeaning
401unauthorizedNo key, or an unknown, revoked, expired or rolled-out key
401key_owner_inactivekey_owner_inactiveThe key's member is no longer active
402plan_requiredThe workspace is not on Growth or Scale
403workspace_suspendedThe workspace is suspended; contact Gauge support
403forbiddenip_not_allowedThe request came from outside the key's allowlist
403forbiddensandbox_key_not_supportedA test key on an endpoint without sandbox support
403forbiddenkey_pinned_to_projectsA pinned key on an endpoint that cannot honour the pin
403insufficient_scopeThe key, or its member's role, lacks the route's scope

The full list is in Errors.

On this page