Security and keys
Perkamo separates trusted backend operations from browser or mobile integration work. Server API keys can write events, read customers, redeem rewards and upload config depending on scopes. Browser clients must never receive server API keys.
Server API keys
Store server keys only in backend environment variables or a secrets manager.
Create, rotate and revoke keys in Server keys.
env
PERKAMO_SECRET_KEY=sk_live_...Create one key per integration when possible. Rotation and revocation are safer when checkout, CRM sync and reporting do not share a single key.
Mutating server API requests must also be signed. The JavaScript SDK signs the event ingestion methods it exposes automatically. For raw HTTP integrations to POST /v1/identify, POST /v1/events, POST /v1/events:batch, POST /v1/client-tokens, POST /v1/rewards/redeem or POST /v1/admin/config/{module}, send:
http
x-perkamo-api-key: sk_live_...
x-perkamo-timestamp: 1780425600
x-perkamo-signature: v1=<hmac-sha256-hex>If you call the HTTP API directly, build the signature input from the exact request you are sending:
text
v1.{unix_timestamp}.{HTTP_METHOD}.{path_and_query}.{sha256_hex(raw_body)}Then sign that text with HMAC-SHA256 using the server API key. The timestamp must be within the configured replay window.
Scopes
Server keys can be scoped to:
| Scope | Allows |
|---|---|
events:write | POST /v1/identify, POST /v1/events, POST /v1/events:batch |
customer:read | GET /v1/customer/{user_id}, GET /v1/customers, GET /v1/program, GET /v1/usage |
customer:adjust | POST /v1/customer/{user_id}/adjust |
rewards:redeem | POST /v1/rewards/redeem |
admin:config | POST /v1/admin/config/{module} |
POST /v1/client-tokens requires both events:write and customer:read.
Client-token boundary
Do not bundle server API keys or signing secrets in browser, mobile or widget code. Frontend code receives only short-lived client tokens from your backend. Your backend either self-signs with a Perkamo signing key or calls POST /v1/client-tokens from trusted server code.
Client-safe /v1/client/* routes are authorized by those client tokens. The token subject is bound to the customer and scopes/events are clamped to the signing key policy.
Allowed websites are configured in Perkamo as Space-level exact origins checked on browser requests:
https://app.example.comhttps://shop.example.com
Manage allowed websites in Security. Enter exact origins only — no CSP directives, paths or wildcard domains.
Set the CSP header on the embedding site
Allowed websites are Perkamo's half of the policy. The website that embeds the SDK needs its own Content-Security-Policy header so the browser is permitted to reach the Perkamo API. Configure this on your own site, not in Perkamo:
http
Content-Security-Policy: connect-src 'self' https://api.perkamo.com;If your site already sets connect-src, append https://api.perkamo.com to the existing directive instead of replacing it. Without this header the browser blocks calls to Perkamo even when the origin is on the allowed websites list.
Data minimization
Send only facts Perkamo needs for rules, audit and support. Avoid card data, passwords, authentication tokens and unnecessary personal data.
Console account security
Perkamo Console supports password sign-in and Google OpenID Connect. Google sign-in is completed server-side, accepts verified Google identities only and never exposes provider secrets or authorization codes to the Console frontend.
Remote MCP OAuth
Hosted MCP access uses OAuth authorization code with PKCE instead of server API keys in AI client configuration. MCP clients discover metadata at /.well-known/oauth-authorization-server and connect to /mcp with a bearer access token. Perkamo displays the client name, callback host and requested scopes before issuing an authorization code.
MCP access tokens are opaque, short-lived and revocable. Refresh tokens rotate on use. Tokens inherit the Console user's current permissions across accessible Spaces; deactivated users and removed memberships stop authorizing MCP calls. They do not bypass owner, admin or viewer role checks. The Space selected during authorization is a default only. Explicit spaceId inputs are authorized independently for every tool call.
New OAuth clients default to mcp:read for inspection and migration planning. Grant mcp:write only for operator-supervised sessions that may emit events, redeem rewards or upload config versions. Live Space mutations require confirmProduction: true after the user reviews the named target Space. Test Space mutations do not require repetitive confirmation.
The npm MCP adapter uses a Space server API key instead of Console OAuth. It is therefore limited to the keyed Space and the key's explicit API scopes. Keep the adapter on stdio where possible. Its optional HTTP transport requires a separate bearer token when bound outside loopback, validates the Host header and limits request size and concurrent sessions. Set a bearer token on loopback too when other local processes are outside your trust boundary.
Retry safety
- Retry network failures, timeouts and
5xxwith the same transaction id. - Do not retry
400,401or403automatically. - Use exponential backoff for
429. - Treat
duplicate: trueas a successful replay.