Clients & templates
Who holds your keys, how you limit them, and how to restrict where they can call from.
A client is a consumer of your API — a customer, a partner integration, an internal service, a device. Keys belong to a client, so revoking the client revokes everything it holds, and usage rolls up per client rather than per opaque key.
Clients live inside one environment. A client in
staging is a different object from one in production.
Types
Metadata only, but it makes the dashboard legible once you have a few hundred:
person · company · service · device · internal
Creating one
curl -X POST "https://apikee.example.com/api/v1/client?project_env=payments-api-production" \
-H "x-api-key: apikee_..." \
-H "content-type: application/json" \
-d '{
"name": "Acme mobile app",
"type": "company",
"templateId": "tpl_partner",
"ipWhitelist": ["203.0.113.0/24"],
"metadata": { "accountId": "acct_912" },
"keys": [{ "name": "default", "expiresAt": "2027-01-01T00:00:00Z" }]
}'The response contains the raw keys once. Store them then — the database keeps only a hash and a display prefix.
You can pass an array instead of an object to create up to 100 clients in one call.
IP allow-lists
Each client may carry up to 100 rules, as plain addresses or CIDR blocks, IPv4 or IPv6:
{ "ipWhitelist": ["203.0.113.9", "198.51.100.0/24", "2001:db8::/32"] }An empty list means no restriction. A non-empty list is enforced as check 6 during
validation and fails closed — a request from outside the list
is 403, and a malformed rule never silently widens access.
Templates
A template is a named bundle of rate limits that many clients share. Change the template and every client on it moves together — useful for tiers.
| Field | Meaning |
|---|---|
name, description | How it appears in the dashboard |
maxClients | Cap on clients assigned to this template |
rateLimitHour | Requests allowed per hour |
rateLimitDay | Per day |
rateLimitWeek | Per week |
rateLimitMonth | Per month |
All four windows are optional and enforced independently. Leaving one unset means that window is unlimited.
Limits apply as check 8 during validation, so a throttled caller gets 429 with a
Retry-After header. Because it is the last check, an invalid key is rejected
before it can consume any of a tenant's budget.
curl "https://apikee.example.com/api/v1/client/templates?project_env=payments-api-production" \
-H "x-api-key: apikee_..."A client's template must live in the same environment — referencing one from
elsewhere returns 404.
Metadata
Both clients and keys take arbitrary JSON, bounded at 8 KiB and 5 levels deep.
Prototype-polluting keys (__proto__, constructor, prototype) are rejected.
Use it to hold your own identifiers so you do not need a mapping table:
{ "metadata": { "stripeCustomer": "cus_123", "tier": "partner", "region": "eu" } }Metadata is not a secret store. It is returned by the API, shown in the dashboard, and — unless you leave redaction at its default — visible to the AI assistant. Do not put credentials in it.
Lifecycle
| Action | Effect |
|---|---|
| Disable a client | Every key it holds fails at check 5 (403) |
| Delete a client | Keys go with it |
| Revoke one key | Only that key stops working |
Revocation is immediate in server mode. In local mode there is no central record to revoke against — which is the main reason to connect the platform.

