Embed plane
What an embed token reaches: one tenant's keys and nothing else.
packages/api/src/embed/embed.controller.ts by packages/docs/tools/generate-reference.mjs. Every example is a real exchange recorded against the control plane by packages/api/src/testing/reference-examples.spec.ts, with ids from that run. Credentials in the formats this product issues (kr_, krsk_, krses_, JWTs) and values under credential-named fields (password, *_secret, *_token, *_key, lookup_hash) are elided at record time; the recorded file and every page of this site are swept for credential shapes (kr_, krsk_, krses_, JWTs, URLs carrying a password, password fields) before either is accepted. Do not edit by hand: src/reference.spec.ts regenerates it and fails on a difference.The embed plane (report section 7.1's second column): our customer's customer, in a browser, managing their own keys.
There is no tenant_id in this file, and there must never be one. Not in
a path, not in a query, not in a body, not in a header. The tenant comes from
the signed token and reaches the database through TenantScopedRepository,
which has no method that takes one — that is what makes horizontal tenant
escalation structurally impossible rather than a WHERE clause somebody has
to remember. embed-isolation.spec.ts asserts it over the live route table,
so a route added later is covered by construction rather than by review.
The same argument applies one level up and is why nothing here reads
project_id or env either: all four scope columns come from the token.
GET /v1/embed/session
What the component renders its chrome from: whose keys these are, which
environment, what this session may do, and when the token dies so the
customer's getToken() can be called before it does.
Answers 200 on success.
Authentication.
- An embed token minted by
POST /v1/embed_tokens, bound to one tenant.
Example.
curl https://keyring-api.belghalem.fr/v1/embed/session \
-H "Authorization: Bearer $EMBED_TOKEN" \
-H "Origin: https://app.acme.example"HTTP/1.1 200 OK
Content-Type: application/json
{
"object": "embed_session",
"project": {
"id": "01a0ade7-b8fb-7711-bb1a-7d1bd5962995",
"name": "Payments API",
"slug": "payments-api"
},
"env": "test",
"test_mode": true,
"tenant": {
"id": "01a0ade7-b909-7ae2-9477-aa287f446aad",
"external_id": "cus_8f3k2",
"name": "Globex Corporation"
},
"scopes": [
"keys:read",
"keys:write",
"key_scope:orders:read"
],
"expires_at": "2026-09-17T05:52:20.000Z",
"expires_in": 300
}GET /v1/embed/keys
Answers 200 on success.
Authentication.
- An embed token minted by
POST /v1/embed_tokens, bound to one tenant.
Query. Validated by this schema, from the control plane's own source:
const ListKeys = z.object({
include_revoked: z
.enum(['true', 'false'])
.default('false')
.transform((value) => value === 'true'),
limit: z.coerce.number().int().min(1).max(100).default(50),
});Example.
curl https://keyring-api.belghalem.fr/v1/embed/keys \
-H "Authorization: Bearer $EMBED_TOKEN" \
-H "Origin: https://app.acme.example"HTTP/1.1 200 OK
Content-Type: application/json
{
"object": "list",
"data": [
{
"object": "api_key",
"id": "01a0ade7-bae9-777c-a8d4-df6181e44b11",
"project_id": "01a0ade7-b8fb-7711-bb1a-7d1bd5962995",
"tenant_id": "01a0ade7-b909-7ae2-9477-aa287f446aad",
"env": "test",
"display_prefix": "kr_test_VB2fZo",
"name": "Staging",
"scopes": [
"orders:read"
],
"meta": {},
"rate_limits": null,
"expires_at": null,
"revoked_at": null,
"revoked_reason": null,
"quarantined_at": null,
"quarantine_reason": null,
"rotated_from": null,
"created_at": "2026-09-17T05:47:20.168Z",
"last_used_at": null
},
{
"object": "api_key",
"id": "01a0ade7-b916-78a6-801e-79f4ba8233fb",
"project_id": "01a0ade7-b8fb-7711-bb1a-7d1bd5962995",
"tenant_id": "01a0ade7-b909-7ae2-9477-aa287f446aad",
"env": "test",
"display_prefix": "kr_test_KVME4u",
"name": "CI",
"scopes": [
"orders:read",
"orders:write"
],
"meta": {},
"rate_limits": null,
"expires_at": null,
"revoked_at": null,
"revoked_reason": null,
"quarantined_at": null,
"quarantine_reason": null,
"rotated_from": null,
"created_at": "2026-09-17T05:47:19.700Z",
"last_used_at": null
}
]
}POST /v1/embed/keys
Answers 201 on success.
Authentication.
- An embed token minted by
POST /v1/embed_tokens, bound to one tenant.
Body. Validated by this schema, from the control plane's own source:
const CreateKey = z.object({
name: Name.optional(),
scopes: Scopes.optional(),
});Example.
curl https://keyring-api.belghalem.fr/v1/embed/keys \
-X POST \
-H "Authorization: Bearer $EMBED_TOKEN" \
-H "Origin: https://app.acme.example" \
-H "Content-Type: application/json" \
-d '{
"name": "Staging",
"scopes": [
"orders:read"
]
}'HTTP/1.1 201 Created
Content-Type: application/json
{
"object": "api_key",
"id": "01a0ade7-bae9-777c-a8d4-df6181e44b11",
"project_id": "01a0ade7-b8fb-7711-bb1a-7d1bd5962995",
"tenant_id": "01a0ade7-b909-7ae2-9477-aa287f446aad",
"env": "test",
"display_prefix": "kr_test_VB2fZo",
"name": "Staging",
"scopes": [
"orders:read"
],
"meta": {},
"rate_limits": null,
"expires_at": null,
"revoked_at": null,
"revoked_reason": null,
"quarantined_at": null,
"quarantine_reason": null,
"rotated_from": null,
"created_at": "2026-09-17T05:47:20.168Z",
"last_used_at": null,
"key": "kr_test_VB2fZo…",
"key_shown_once": true
}POST /v1/embed/keys/:id/rotate
Answers 200 on success.
Authentication.
- An embed token minted by
POST /v1/embed_tokens, bound to one tenant.
Path parameters. id.
Body. Validated by this schema, from the control plane's own source:
const RotateKey = z.object({
overlap_hours: z.number().min(0).max(168).default(24),
});Example.
curl https://keyring-api.belghalem.fr/v1/embed/keys/01a0ade7-bae9-777c-a8d4-df6181e44b11/rotate \
-X POST \
-H "Authorization: Bearer $EMBED_TOKEN" \
-H "Origin: https://app.acme.example" \
-H "Content-Type: application/json" \
-d '{
"overlap_hours": 24
}'HTTP/1.1 200 OK
Content-Type: application/json
{
"object": "api_key",
"id": "01a0ade7-baf5-7459-9f5e-bb2eb81bd93c",
"project_id": "01a0ade7-b8fb-7711-bb1a-7d1bd5962995",
"tenant_id": "01a0ade7-b909-7ae2-9477-aa287f446aad",
"env": "test",
"display_prefix": "kr_test_afB2o_",
"name": "Staging",
"scopes": [
"orders:read"
],
"meta": {},
"rate_limits": null,
"expires_at": null,
"revoked_at": null,
"revoked_reason": null,
"quarantined_at": null,
"quarantine_reason": null,
"rotated_from": "01a0ade7-bae9-777c-a8d4-df6181e44b11",
"created_at": "2026-09-17T05:47:20.179Z",
"last_used_at": null,
"key": "kr_test_afB2o_…",
"key_shown_once": true,
"previous_key": {
"object": "api_key",
"id": "01a0ade7-bae9-777c-a8d4-df6181e44b11",
"project_id": "01a0ade7-b8fb-7711-bb1a-7d1bd5962995",
"tenant_id": "01a0ade7-b909-7ae2-9477-aa287f446aad",
"env": "test",
"display_prefix": "kr_test_VB2fZo",
"name": "Staging",
"scopes": [
"orders:read"
],
"meta": {},
"rate_limits": null,
"expires_at": "2026-09-18T05:47:20.179Z",
"revoked_at": null,
"revoked_reason": null,
"quarantined_at": null,
"quarantine_reason": null,
"rotated_from": null,
"created_at": "2026-09-17T05:47:20.168Z",
"last_used_at": null
}
}POST /v1/embed/keys/:id/revoke
Idempotent, for the same reason the control plane's revoke is.
Answers 200 on success.
Authentication.
- An embed token minted by
POST /v1/embed_tokens, bound to one tenant.
Path parameters. id.
Body. Validated by this schema, from the control plane's own source:
const RevokeKey = z.object({ reason: z.string().min(1).max(500).optional() });Example.
curl https://keyring-api.belghalem.fr/v1/embed/keys/01a0ade7-baf5-7459-9f5e-bb2eb81bd93c/revoke \
-X POST \
-H "Authorization: Bearer $EMBED_TOKEN" \
-H "Origin: https://app.acme.example" \
-H "Content-Type: application/json" \
-d '{}'HTTP/1.1 200 OK
Content-Type: application/json
{
"object": "api_key",
"id": "01a0ade7-baf5-7459-9f5e-bb2eb81bd93c",
"project_id": "01a0ade7-b8fb-7711-bb1a-7d1bd5962995",
"tenant_id": "01a0ade7-b909-7ae2-9477-aa287f446aad",
"env": "test",
"display_prefix": "kr_test_afB2o_",
"name": "Staging",
"scopes": [
"orders:read"
],
"meta": {},
"rate_limits": null,
"expires_at": null,
"revoked_at": "2026-09-17T05:47:20.186Z",
"revoked_reason": null,
"quarantined_at": null,
"quarantine_reason": null,
"rotated_from": "01a0ade7-bae9-777c-a8d4-df6181e44b11",
"created_at": "2026-09-17T05:47:20.179Z",
"last_used_at": null
}GET /v1/embed/keys/:id/usage
Answers 200 on success.
Authentication.
- An embed token minted by
POST /v1/embed_tokens, bound to one tenant.
Path parameters. id.
Query. Validated by this schema, from the control plane's own source:
const Usage = z.object({
days: z.coerce.number().int().min(1).max(90).default(30),
});Example.
curl https://keyring-api.belghalem.fr/v1/embed/keys/01a0ade7-b916-78a6-801e-79f4ba8233fb/usage?days=7 \
-H "Authorization: Bearer $EMBED_TOKEN" \
-H "Origin: https://app.acme.example"HTTP/1.1 200 OK
Content-Type: application/json
{
"object": "usage",
"key_id": "01a0ade7-b916-78a6-801e-79f4ba8233fb",
"days": 7,
"data": [
{
"day": "2026-09-17",
"requests": 2,
"errors": 0
}
]
}Shared validators
Defined once in packages/api/src/validation.ts and used by the schemas above.
const Name = z.string().min(1).max(200);const Scopes = z.array(z.string().min(1).max(200)).max(64);