Identity Plane APIs
Platform version: v10.2.0. Edition: Enterprise. Status: available, and inert on every deployment until an organization opts in.
These two endpoints arrived together in v10.2.0 and are best read as a pair. The admin API writes an organization's identity settings row; the CAEP receiver does nothing at all until that row opts the organization in. Neither endpoint changes what any request is authorized to do. They belong to the ADR-065 identity plane, which in v10.2.0 records and does not enforce; see Identity Compatibility Mode for what that plane observes and what it will mean at v11.
The generated reference is vendored from the community mirror's specs, and both of these endpoints are Enterprise-only, so they do not appear there. This page is their authoritative reference.
Shared Signals / CAEP push receiver
POST /api/v1/identity/caep/events
A Shared Signals Framework push receiver on the agent. An identity provider that supports Continuous Access Evaluation delivers a signed Security Event Token (SET) here when a session is revoked or credentials change, and AxonFlow drops the affected cached identity data so the next governed request re-resolves it.
When the route exists
The route is registered only on a process that can act on it. An agent registers it when it has wired the tenant OIDC configuration, the identity attribute resolver and the organization settings store together. Anywhere else, including every Community build, the path is not registered at all and a request to it receives the agent's ordinary 404. That is deliberate: a transmitter configured against a deployment that cannot act sees the failure in its own delivery log rather than a receiver that accepts and silently discards.
A process that does not register it logs the reason once at startup:
[IDENTITY-CAEP] no Shared Signals receiver registered: this process did not wire all of the tenant OIDC configuration, the identity attribute resolver and the org settings store, so no realm declares a Shared Signals channel
A process that does register it logs:
[IDENTITY-CAEP] Shared Signals push receiver registered at POST /api/v1/identity/caep/events; a tenant's OIDC realm declares the channel once its identity settings opt in
Registration is not the same as being on. With the route registered but no organization opted in, every delivery is refused: no realm declares the channel, so the issuer resolves to nothing. Turn it on for an organization with the identity settings API below.
Authentication
The transmitter authenticates with the organization's ordinary agent client credential, the same Authorization: Basic base64(clientId:clientSecret) pair the agent's other authenticated routes take. No separate credential type is introduced.
The organization is the authenticated one, never a claim inside the token. A SET that names some other organization does not reach that organization's data; the token is evaluated only against the realms of the credential that carried it.
POST /api/v1/identity/caep/events
Authorization: Basic <base64 clientId:clientSecret>
Content-Type: application/secevent+jwt
eyJhbGciOiJSUzI1NiIsInR5cCI6InNlY2V2ZW50K2p3dCIsImtpZCI6...
The body is the compact-serialized SET. It must be between 1 and 65536 bytes; anything larger is refused without being parsed.
Responses
| Status | Meaning |
|---|---|
202 Accepted | The SET was validated and applied, or recognized as a duplicate of one already applied. The body is empty, per RFC 8935. |
400 Bad Request | The delivery is wrong and will stay wrong. Do not redeliver. |
401 Unauthorized | The client credential was missing or invalid. |
403 Forbidden | The transmitter is not permitted to send this event to this organization. Do not redeliver. |
503 Service Unavailable | AxonFlow could not act on a SET it has no reason to reject. Redeliver. |
Errors carry the RFC 8935 body shape:
{
"err": "invalid_issuer",
"description": "the issuer is declared by no trust realm in this organization"
}
The err values are invalid_request, invalid_key, invalid_issuer, invalid_audience, authentication_failed, access_denied and temporarily_unavailable.
The 400/403-versus-503 split is the contract that matters to a transmitter, and it is drawn on one question: is redelivering this SET pointless, or might it work? A malformed token, an undeclared issuer, a bad signature and an unknown event type are all permanent and answer in the 400 family. A cache AxonFlow could not clear is temporary and answers 503, and its jti is deliberately not remembered, so the transmitter's retry is processed rather than answered as a duplicate. A revocation must never be acknowledged as applied when it was not.
What a delivery is checked against
In order, and every event in a SET is validated before any is applied:
- the media type is
application/secevent+jwt; - the token is a well-formed JWS whose header declares
typ=secevent+jwt, so anid_tokencannot be replayed as a SET; - the issuer resolves to a trust realm in the authenticated organization, before any key is fetched. An undeclared issuer costs no outbound request;
- that realm has opted in to Shared Signals, and the token's algorithm is on the realm's allow-list;
- the audience matches the organization's configured
caep_audience; - the signature verifies against the realm's own JWKS, which is the SSO configuration the realm was derived from;
- freshness,
jtiand replay dedupe; - event types are known, and subjects are
iss_subfrom the realm's own issuer. An email, phone, opaque or foreign-issuer subject is refused rather than ignored.
Every refusal is logged as [IDENTITY-CAEP] ... refused stage=<stage> and counted.
Metrics
Two Prometheus counters, on the agent's existing metrics endpoint:
| Metric | Labels | Meaning |
|---|---|---|
axonflow_identity_caep_push_total | outcome (applied, duplicate, refused), stage (the check that refused) | push deliveries |
axonflow_identity_caep_invalidations_total | scope (subject, org) | cache invalidations performed |
A scope="org" invalidation means the directory could not map the subject to a user, so the organization's whole cached set was dropped. That over-invalidates on purpose: the alternative is under-invalidating a revocation.
What it does not do
- It does not revoke AxonFlow-minted per-user tokens. Those carry AxonFlow's own
jtiand are governed by the existing revocation surfaces. A Shared Signals event is a statement about the IdP's realm. - It grants nothing and denies nothing. Its whole effect is to drop cached identity data early, so the next request resolves fresh instead of waiting out a TTL.
Per-organization identity settings
GET /api/v1/admin/organizations/{org_id}/identity-settings
PUT /api/v1/admin/organizations/{org_id}/identity-settings
DELETE /api/v1/admin/organizations/{org_id}/identity-settings
On the customer portal, behind the admin API. This is an operator decision about a tenant, so it deliberately sits on no tenant-session route: it is registered under the same admin middleware as the rest of the /api/v1/admin/... family, which in SaaS production requires the X-Admin-API-Key header. Treat that key as described under Admin API key auth.
The record
{
"success": true,
"settings": {
"org_id": "acme",
"compat_mode": "shadow",
"caep_enabled": true,
"caep_audience": "https://agent.acme.example/api/v1/identity/caep/events",
"updated_at": "2026-08-31T09:14:02Z",
"propagation": "the agent and the orchestrator re-read this row on a per-organization TTL (AXONFLOW_IDENTITY_ORG_SETTINGS_TTL_SECONDS, default 60s); a change is honoured within that bound"
}
}
| Field | Meaning |
|---|---|
compat_mode | off, shadow, enforce, or null. null means this organization has expressed no preference and follows the deployment's AXONFLOW_IDENTITY_COMPAT_MODE. |
caep_enabled | whether this organization's OIDC realm declares a Shared Signals channel. Requires caep_audience. |
caep_audience | the audience value a SET must carry for this organization. |
propagation | how long a change takes to be honoured. The response says it rather than making the caller look it up. |
How the row interacts with the deployment switch
A record wins, in both directions. An organization with compat_mode: "shadow" is observed even on a deployment whose process-wide flag is unset, and an organization with compat_mode: "off" is exempt even on a deployment running enforce. An organization with no row, or a row whose compat_mode is null, follows the process flag exactly as it did before this endpoint existed.
This is what makes a staged rollout possible one tenant at a time rather than one reason code at a time. It does not change what shadow and enforce mean; read Identity Compatibility Mode before setting any organization to enforce.
If the settings row cannot be read, the deployment's own declaration is used rather than a guess at the organization's, and the failure is counted. The last successfully read row is served through a database outage, so a hiccup never flips an organization's mode mid-incident.
Requests
GET returns 200 with the record, or 404 if the organization has no row (which is not an error: it means the organization follows the process flag).
PUT replaces the record:
PUT /api/v1/admin/organizations/acme/identity-settings
X-Admin-API-Key: <key>
Content-Type: application/json
{
"compat_mode": "shadow",
"caep_enabled": true,
"caep_audience": "https://agent.acme.example/api/v1/identity/caep/events"
}
400 if compat_mode is outside off/shadow/enforce, if caep_enabled is true without a caep_audience, or if the body is malformed. A misspelled mode is rejected, never coerced, on the same reasoning as the environment variable: an operator who typed enfore must not be left believing their tenant enforces.
404 if the organization does not exist.
DELETE removes the record and answers 204. The organization reverts to following the process flag within the propagation bound.
Storage
The row lives in identity_org_settings, added by migration enterprise/146, org-scoped under row-level security. It is an Enterprise table; a Community deployment federates no identity provider and holds no such row, and the process-wide flag is the whole answer there.
Related
- Identity Compatibility Mode: what the identity plane records, which divergences to expect, and what
enforcerefuses. - Enterprise API Surface: the auth model for every Enterprise API family.
- v10.2.0 release notes.
- SSO Configuration: the OIDC configuration a CAEP-capable realm is derived from.
