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 API access.
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/event-definitions, GET /v1/usage |
customer:adjust | POST /v1/customer/{user_id}/adjust |
customer:delete | DELETE /v1/customer/{user_id} |
rewards:redeem | POST /v1/rewards/redeem |
admin:config | POST /v1/admin/config/{module} |
POST /v1/client-tokens requires both events:write and customer:read.
API activity and request IDs
Open Operations → API activity to review event-contract diagnostics and verify that a server request reached Perkamo. The feed shows the time, parameterized route template, HTTP status, server key, duration and x-request-id, including requests rejected for a missing scope or invalid signature. Request times use the browser's local time zone and include its zone label. Program Events links to this operational view but remains focused on contract configuration.
The path does not include route parameter values such as customer identifiers. For a recognized server-key request, Perkamo also stores bounded request and response JSON snapshots so validation and event-contract problems can be diagnosed. Credential-like fields are recursively redacted and oversized values or collections are truncated. Query strings and request headers are not stored. Customer-erasure operations never retain request or response snapshots. Other payload snapshots are visible only to Space admins and owners; viewers retain request metadata without body access. Do not send secrets or unnecessary personal data in event context. Records are retained for 30 days. Requests made without a recognized server key cannot be assigned safely to a Space and therefore do not appear; use the x-request-id from the API response when contacting support.
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 Client 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.
Customer erasure is backend-only. Give customer:delete only to the service that owns the source-of-truth account lifecycle; do not grant it to browser tokens, analytics jobs or general event producers.
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.