Keyring
Test mode for your API.
Everything a public API needs between the key and the handler: test mode, keys, rate limits, idempotency and usage, as one middleware in your own process and one dashboard. Never a proxy in front of it.
MIT SDKs for Express, Fastify, NestJS and Next.js. EU-only control plane. Not on npm yet.
import { keyring } from '@keyring/express';
app.use(
keyring({ resources: { orders: { live: liveOrders, test: testOrders } } }),
);
app.get('/v1/orders', (req, res) =>
res.json({
tenant: req.keyring?.tenantId,
env: req.keyring?.env,
orders: req.keyring?.orders,
}),
);A test key gets the test list, a live key gets the live list, and no key gets a 401. Executed against the real packages before every deploy of this site.
In your process, not in front of it
Verification is a hash and a map lookup against a policy set the SDK keeps in memory and polls every 5 seconds. No proxy, no gateway, no network call on the request path. Our outage is not yours.
Test mode that cannot leak
The environment is inside the key. A kr_test_ key reaches only the test resources you declared once, and code far from the request reads currentEnv() instead of a flag somebody forgot.
One dashboard for both of you
Projects, tenants, keys, rotation with overlap, revoke with a receipt, usage, and a hash-chained audit log. Drop the embeddable component into your own app and your customers manage their own keys.
Two keys, one endpoint
Your customer gets a kr_test_ key and a kr_live_ key. Both hit the same route. The middleware verifies either from memory and hands your handler the resources for that environment. Test traffic is free and never counted toward billing.
kr_test_…200
orders: the test list
kr_live_…200
orders: the live list
no key401
every denial looks the same
What ships today
Keys per tenant
192 bits, a checksum, shown once. Scopes, expiry, rotation with up to 7 days of overlap.
Rate limits on the key
Sliding or fixed windows, per key or per tenant, in standard headers. Test traffic never spends a live quota.
Idempotency
Stripe's semantics on an Idempotency-Key header, scoped per tenant so a rotation cannot double-charge.
Revoke and wait
Revocation lands within one poll. With wait=true the response is a receipt from every node that polls.
Usage per key and per tenant
Every request the middleware handles is reported, batched, and charted per day and per month.
An audit log you can verify
Every mutation in the same transaction as the change, hash-chained, verified in front of you.
When Keyring is down
Every node keeps verifying from its cache. What an unknown key does then is a decision you make per route, and the default admits one after 60 seconds of staleness so that an outage of ours is invisible to your customers. A money route sets closed. The full table, state by state, is written down rather than promised.
Not yet
- The packages are not on npm. They install from tarballs you build.
- There is no per-request explorer. Usage is per key per day and per tenant per month.
- The edge runtime is refused, not degraded.
- Python and Go SDKs are planned. The conformance fixtures they will pass exist today.
Built for
AI agents and LLM APIs
A test key the agent can explore with, safe retries, a budget it cannot overrun.
SaaS APIs
Test mode without a second deployment, limits per plan, rotation your customers do themselves.
Marketplaces
Per-tenant budgets that survive rotation, nodes that cache only the tenants they serve.
Partner APIs
Scoped keys per partner, a receipt for every revocation, an audit log for their security team.
EU only, in EUR
The hosted control plane runs in the EU, with no US control plane, replica or failover. That is architectural, not a deployment option. The same recipe deploys on your own Coolify server as four resources on one Docker network.