Support API

Signed integration tokens

An integration token tells Gauge who your user is and which Integration of your App they are on (for example customer or salon). Your server mints it; the widget, WebView or portal passes it on.…

An integration token tells Gauge who your user is and which Integration of your App they are on (for example customer or salon). Your server mints it; the widget, WebView or portal passes it on. Gauge verifies it on every session open.

Use it instead of the older identityHash for anything new. identityHash keeps working, but only on your App's default integration, and it never unlocks actions that read a customer's data (order lookups, payouts). A token does.

Mint one (your server)

Node (npm install @gauge/support):

import { mintIntegrationToken } from '@gauge/support';

const token = await mintIntegrationToken(process.env.GAUGE_IDENTITY_SECRET, {
  appId: process.env.GAUGE_APP_ID, // Console → Apps → your App → Install
  userId: 'u_1029',                // YOUR user id
  integration: 'customer',         // the Integration key
  attrs: { plan: 'pro' },          // optional, verified attributes
});

Python (pip install gauge-support):

import os
from gauge_support import mint_integration_token

token = mint_integration_token(
    os.environ["GAUGE_IDENTITY_SECRET"],
    app_id=os.environ["GAUGE_APP_ID"],
    user_id="u_1029",
    integration="customer",
    attrs={"plan": "pro"},
)

Never send the secret to a browser or ship it in an app. Mint a new token for every session open.

What is inside

A compact JWT: header {"alg":"HS256","typ":"JWT"}, HMAC-SHA256 with a token key derived from your App's identity secret: tokenKey = hex(HMAC-SHA256(key = "gauge.integration-token.v1", message = secret)) (lowercase hex, used as the HS256 secret). The SDK helpers do this for you; with another JWT library, pass integrationTokenKey(secret) / integration_token_key(secret) as its secret. Never sign with the raw identity secret: a token signed that way is refused (bad_signature), because an identityHash your server hands out is an HMAC under that same secret.

ClaimMeaning
issYour App id
subYour user id. Gauge keys the conversation and the customer record on it
keyThe Integration key (^[a-z][a-z0-9_]{0,31}$)
attrsOptional. Up to 16 flat values (string ≤ 200, number, boolean). Assistant rules and SLA tiers read them, and only from a verified token
name, emailOptional, shown to your team
iat, expEpoch seconds. exp - iat ≤ 600
jtiSingle-use nonce (≤ 128 chars). The SDK helpers set a random one for every token. See Replay

Rules Gauge applies, in this order: alg must be HS256 · signature (current secret, or the previous one while a rotation overlap is open) · no unknown claims · life ≤ 600 s · not expired (60 s grace) · iat not in the future (60 s grace) · iss is this App · key is the integration being opened · the user is granted that integration · jti not used before.

Replay: one token, one session open

A token is a bearer credential for up to 10 minutes. So that a copied token (a log line, a proxy, a browser extension) can't open a verified chat as your user and reach their orders or payouts, a token that carries a jti is single-use: the first session open consumes it, and any later open with the same token (from any browser) is refused with token_replayed. Gauge only consumes a jti after the signature checks out, so a forged token can't burn one of yours.

  • mintIntegrationToken (JS) and mint_integration_token (Python) always add a random jti (pass your own with jti if you need to correlate). The console's Test as … tokens carry one too.
  • In the widget, use getToken (it fetches a fresh token on every open and re-open). A static token works once: the widget's later re-reads with the same token are refused and it keeps the session it already has, but a page that re-initialises with the same token will not reopen.
  • Backward compatibility during P1: a token without jti (hand-signed with another JWT library) is still accepted and is not replay-checked. Add a random jti now; a later release will require it.

Why a token was refused

The error message starts with the code. The console's Token checker (Developers → Support) decodes a pasted token and tells you which rule failed. It never shows the secret or the user's data.

CodeHTTPFix
malformed401Not a JWT, or a claim Gauge doesn't know. Use the SDK helper
bad_alg401Header must be {"alg":"HS256","typ":"JWT"}
bad_signature401Wrong secret, or the token was edited. Re-sign after rotating
expired401Mint a new token per session open
not_yet_valid401Your server clock is ahead. Sync it (NTP)
too_long401Keep exp - iat at 600 s or less
wrong_app401iss is another App's id
wrong_key401The token names a different integration than the one being opened
revoked401The user's grants changed after the token was minted. Mint again
token_replayed401This token (its jti) already opened a session. Mint a fresh token per open (getToken)
unknown_integration404No integration with that key on the App
integration_not_granted403The user isn't granted that integration. Add it with customer sync
sandbox_only401A console test token was used on a live integration

Grants

On an App with more than one integration, a user may open only the integrations listed for them:

PUT /v1/support/customers/by-ref/u_1029
{ "email": "layla@example.com", "projectIds": ["<appId>"], "integrationKeys": { "<appId>": ["customer"] } }

An empty list means the default integration only. Removing a key ends the user's live chats on it at their next message, and refuses tokens minted before the change. A user Gauge has never seen (no customer record) is bound by the key your server signed.

Rotating the secret

Generate a new secret in the console. The old one keeps verifying during the overlap window, so roll your servers onto the new one inside it.

Testing

verifyIntegrationToken (JS) and verify_integration_token (Python) apply the same rules and return the same codes, which is handy in your own tests. Both SDKs pass the shared vectors in packages/sdk-testvectors/integration-token.json, which the Gauge server generates. In the console, Test as <integration> mints a token for draft and sandbox integrations only.

On this page