Geldstuck API keys come in publishable/secret pairs, one per tenant. Both halves are required on every request - the pk_ identifies the tenant, and the sk_ authenticates it.

Anatomy of a key

sk_live_51HxR9z7kZ4M3yB2wQpT8vNjKc6Y7xW9aP5D
│  │    │
│  │    └── Random 32-char body
│  └────── Environment: live or test
└───────── Key type: pk (publishable) or sk (secret)

Creating keys

Every tenant starts with one key pair. Create additional keys from the dashboard or via API - one per service, one per environment is a good default.
curl https://api.geldstuck.com/v1/tenants/$TENANT_ID/api-keys \
  -H "x-api-key: $GELDSTUCK_PUBLIC_KEY" \
  -H "x-api-secret: $GELDSTUCK_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"label": "billing-worker"}'
Response:
{
  "id": "key_01HX3ZDE...",
  "label": "billing-worker",
  "publicKey": "pk_live_51H...",
  "secretKey": "sk_live_51H...",
  "createdAt": "2026-04-22T10:00:00.000Z",
  "status": "active"
}
secretKey is returned only on creation. We store a hash, not the key itself - so if you lose it, you’ll need to regenerate.

Scoping keys

Label your keys by service so you can revoke with surgical precision:
LabelExample use
web-apiYour Node.js API calling Geldstuck
kyc-workerBackground worker handling KYC webhooks
admin-scriptsOperator scripts run from a bastion
ciEnd-to-end tests in CI

Rotating & revoking

1

Regenerate

POST /tenants/:tenantId/api-keys/:keyId/regenerate returns a new pk_/sk_ pair. The old pair stays live for 10 minutes to let in-flight deploys complete.
2

Revoke

POST /tenants/:tenantId/api-keys/:keyId/revoke invalidates the key pair immediately. Use this when a key is leaked.
Both operations emit webhook events (api_key.regenerated, api_key.revoked) so your ops tooling can track key lifecycles.

Rate limits

Rate limits apply per key, not per tenant. Creating separate keys for high-throughput services means they won’t compete for quota. See rate limits.