Start in 5 minutes
Install an adapter, get a key from the dashboard, verify a request, and see it in the usage chart.
By the end of this page your API answers 200 to a kr_test_ key, 401 to no key, and the request shows on the key's usage chart in the dashboard.
Install an adapter
Not on npm yet
The @keyring/* packages are not published to the npm registry. Until they
are, build them from the repository and install the tarballs. The overrides
block is required because each adapter names its sibling packages by exact
version.
From a clone of the Keyring repository:
npm ci
npx nx run-many -t build -p @keyring/core,@keyring/cache,@keyring/sdk,@keyring/express
mkdir -p /path/to/your-app/vendor
for p in core cache sdk express; do
(cd packages/$p && npm pack --pack-destination /path/to/your-app/vendor)
doneSwap express for fastify, nest or next to build the adapter you use. Then, in your app's package.json:
{
"dependencies": {
"@keyring/express": "file:./vendor/keyring-express-0.1.0.tgz"
},
"overrides": {
"@keyring/core": "file:./vendor/keyring-core-0.1.0.tgz",
"@keyring/cache": "file:./vendor/keyring-cache-0.1.0.tgz",
"@keyring/sdk": "file:./vendor/keyring-sdk-0.1.0.tgz"
}
}Node 22 or later is required.
Get a key from the dashboard
Sign up at keyring.belghalem.fr and create a workspace. Creating it shows your secret key once: a krsk_live_… credential your server uses to talk to the control plane. Copy it now; it is never shown again.
Then, in the dashboard:
- Projects → New project. A project is one API of yours. Copy its id.
- Tenants → New tenant. A tenant is one customer organisation. Give it your own id for them as
external_id. - API keys → Mint a key. Pick the project, the tenant and test mode. The
kr_test_…key is shown once.
Set three variables in your app's environment. KEYRING_BASE_URL is the control plane your server polls; for the hosted product that is https://keyring-api.belghalem.fr, and for a self-hosted one it is your own api domain.
KEYRING_SECRET_KEY=krsk_live_...
KEYRING_PROJECT_ID=...
KEYRING_BASE_URL=https://keyring-api.belghalem.frVerify a request
Every sample below is executed against the real packages by packages/docs/src/samples.spec.ts before it is published.
import express from 'express';
import { keyring } from '@keyring/express';
const liveOrders = [{ id: 'ord_live_1', total: 4200 }];
const testOrders = [{ id: 'ord_test_1', total: 100 }];
const app = 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,
degraded: req.keyring?.degraded,
orders: req.keyring?.orders,
}),
);
app.listen(Number(process.env.PORT ?? 3000), '127.0.0.1', () => {
process.stdout.write('listening\n');
});Start it and call it with the test key:
curl -H "Authorization: Bearer kr_test_..." http://127.0.0.1:3000/v1/orders{
"tenant": "01a0...",
"env": "test",
"degraded": false,
"orders": [{ "id": "ord_test_1", "total": 100 }]
}The handler was given the test list because the key is a test key. Mint a live key for the same tenant and the same handler returns the live list. Call it with no key:
curl http://127.0.0.1:3000/v1/orders{ "error": { "code": "invalid_key", "message": "Invalid API key." } }Every denial looks like this one. The reason a key was refused travels to your usage data, never to the caller.
The first requests after a cold start
The SDK polls its policy set 5 seconds apart, and on the default
stale-then-open mode a process that has not loaded its first snapshot admits
any well-formed key unverified until it does. Expect the first two or three
requests after a fresh start to answer 200 with tenant: null. When
Keyring is down has the full table, and
a money route sets onUnavailable: 'closed'.
See it in the usage chart
Open API keys in the dashboard and click the key. The Usage section is a per-day chart of requests and errors for that key over the last 30 days, and the request you just made is in it once the SDK's telemetry batch lands: the SDK flushes every second or every 1,000 events, whichever comes first.
The same numbers are one call away:
curl -H "Authorization: Bearer krsk_live_..." \
"https://keyring-api.belghalem.fr/v1/keys/$KEY_ID/usage?days=7"{
"object": "usage",
"key_id": "01a0...",
"days": 7,
"data": [{ "day": "2026-09-15", "requests": 1, "errors": 0 }]
}There is no per-request explorer yet. Request logs says what is there today.