The API key layer for your SaaS
Stop rewriting
API key management.
Keys, rotation, rate limits and usage for your public API, plus the two that nobody else ships: a real test mode and idempotent retries. One middleware in your own process, never a proxy in front of your API.
1First call
Your handler runs
2Retry after a timeout
Your handler does not run
Two requests, one order, one charge.
- Verification makes no network call
- A revoke lands within one 5 second poll
- SDKs under the MIT license
The problem
Every public API rebuilds the same layer
Hashing, rotation with an overlap, limits per plan, usage per customer. Each team writes it once, under deadline, and then maintains it for good. The two hardest parts usually never get built at all.
Key management becomes its own project
Minting, hashing, scopes, expiry, rotation with an overlap and revocation arrive as one middleware and one dashboard.
Customers test against production
Every tenant gets a kr_test_ key for the same endpoint. It reaches only the test resources you declared.
A retry charges twice
A replay of the same Idempotency-Key returns the stored response, and your handler does not run again.
What you get
The whole key layer, and the two parts nobody ships
Test mode that cannot leak
The environment lives inside the key. A test key and a live key hit the same route on the same deployment, and your handler receives the resources for that environment. Test traffic is free.
Retries that never charge twice
The semantics are the ones Stripe made standard, on an Idempotency-Key header. Records are scoped per tenant and never per key, so a retry that arrives after a key rotation still replays.
- kr_live_9fXa…rotating, 24 h left
- kr_live_Lm2q…active
- kr_live_04Zt…revoked
Keys, rotation and revocation
Keys carry scopes and an expiry, and show once. Rotation keeps the old key working for an overlap of up to 7 days. A revoke lands within one poll, and the API can wait and return a receipt.
Limits per key and per tenant
Sliding or fixed windows, reported in standard RateLimit headers. A limit per tenant is shared by every key that customer holds, and test traffic never spends a live quota.
Usage you can answer a ticket with
Requests and errors per key per day, and requests per tenant per month, in the dashboard and the API. Your customers manage their own keys from a component inside your app.
Architecture
In your process, never in front of it
A gateway is a network hop on every request and a single point of failure that is not yours. Keyring is an SDK. Verification is a hash, a map lookup and a constant time compare against policy the SDK keeps in memory.
Your customer
POST /v1/orders
kr_live_9fXa…
Your process
Keyring middleware
hash, map lookup, compare
Your handler
req.keyring?.orders
Keyring control plane, EU only
Policy is polled in the background, off the request path.
every 5 seconds
- 0 calls
- to our network to verify a request
- 3.2 μs
- median verification with 10,000 keys cached
- 5 seconds
- between policy polls, in the background
A key with rate limits makes one call per request, bounded at 500 milliseconds, and a request that carries an Idempotency-Key makes one too. Verification never leaves your process. When our control plane is down every node keeps verifying from its cache, and the docs state what each feature does then.
Read what runs whereThe key layer every API team rewrites, mounted in one line. Every request stays in your process.
Who it is for
Any SaaS that exposes an API
SaaS APIs
The public API beside your product. Keys per customer, limits per plan and a test mode, without a gateway to run.
Partner APIs
A few integrations of high value. Scoped keys per partner, a receipt for every revocation and an audit log for their security team.
Marketplaces
Many tenants with many keys each. A budget per tenant that every one of their keys shares and that survives a rotation.
Agents and LLM APIs
The sharpest case. An agent explores with a test key, its retries replay, and its loop stops at the budget you set.
How it works
Three steps, one deployment
- 1
Mount one middleware
Declare your live and test resources once. Adapters exist for Express, Fastify, NestJS and the Next.js App Router, and the plain SDK covers anything else in four calls.
- 2
Mint two keys per customer
One kr_test_ key and one kr_live_ key, from the dashboard or from the embeddable component your customers use inside your own app.
- 3
Delete your own key code
Verification, scopes, limits, replays and usage now happen before your handler runs. You watch requests and errors per key per day.
server.ts
Express
import { keyring } from '@keyring-dev/express';
app.use(
keyring({
resources: {
orders: { live: liveOrders, test: testOrders },
},
}),
);
app.post('/v1/orders', (req, res) =>
res.status(201).json(req.keyring?.orders.create(req.body)),
);The packages are not on npm yet and the repository is private for now. Access is granted by hand, and the quickstart says how to ask.
Open source where it counts
The half that runs in your process is yours to read
The eight packages that ship into your process carry the MIT license, and you get their source with access. The control plane, the dashboard and the hashing pepper are closed. Every line that sits between a request and your handler is one you can read.
- 192 bits
- of entropy in every key, shown once and stored as a hash
- 8 packages
- under the MIT license, from the core to the adapters
- 7 days
- of overlap at most when a key rotates, 24 hours by default
- 10 seconds
- at most before a revoke returns its receipt
- Nobody can recover a key in plaintext. Not you, not us, not support.
- Every change to a key, tenant, project or member writes a hash chained audit row in the same transaction.
- When the control plane is down, the docs state what fails open, state by state.
Pricing
Billed per active tenant, in EUR
You pay for the customers who made live requests this month. Test mode is free and never counted. The price list is published at launch.
Hosting
EU only, by architecture
The hosted control plane runs in the EU only, with no US replica and no US failover. That is architecture, not a setting. The same recipe runs on your own server.
FAQ
Short answers
No. It is an SDK that runs in your process. Verification makes no network call, so an outage of our control plane does not stop your API verifying keys. It does stop rotations and revocations landing, and it refuses requests that carry an Idempotency-Key unless you set that mode to open.
Every node keeps verifying from its cached policy. The one thing an outage takes by default is idempotency: a request that carries an Idempotency-Key is answered 503 until the control plane is back, unless you set that mode to open. What an unknown key does then depends on the mode you chose for the route and on the state of the cache. The docs carry the full table, and a route that moves money sets the closed mode.
That is the shape the docs lead with. A kr_test_ key and a kr_live_ key hit the same endpoint and reach different resources.
If your process dies after your handler committed and before the record was written, the retry executes again. That is true of every idempotency layer shaped like a middleware, and the docs describe the standard mitigation.
Within one poll, which is 5 seconds by default. We measured between 4.4 and 4.9 seconds. Revoking with the wait option returns a receipt once every polling node has acknowledged, or after 10 seconds with the receipt marked incomplete.
Billing counts active tenants per month from live traffic only, in EUR. Test traffic is never counted. The price list is published at launch, and nothing charges a card today.
In the EU, only. There is no US control plane, replica or failover, by architecture. You can also run the same recipe on your own server.
Not yet. The repository is private for now and access is granted by hand. With access you build the packages and install the tarballs, and the quickstart walks through it.
Express, Fastify, NestJS on either platform adapter, and the Next.js App Router on the Node runtime. The edge runtime is refused at build time. Python and Go ports are planned and not yet started, and the conformance fixtures they will pass exist today.
Not yet. Requests and errors per key per day, and per tenant per month, are in the dashboard and the API.
Read how it works before you trust it
The docs are public, the samples in them run against the real packages, and the limits of every guarantee are written down.
- Test mode is free
- SDKs under the MIT license
- Runs on your own server too