The model at a glance

  1. An organization (the sponsor) creates a trust space, which gets its own private root and issuing CA.
  2. In the space it creates a service (an API) with route templates (the routes it is willing to share) and pairs one or more gateways.
  3. It sends an invitation to a partner organization with a scope drawn from the templates.
  4. The partner accepts, binding a workload. Acceptance creates a grant: the only cross-organization edge.
  5. The workload enrolls a locally generated key and receives a short-lived certificate whose single URI SAN is its workload identity URI.
  6. Grant changes produce new policy revisions. Each gateway fetches a signed manifest, enforces it on every request, and returns signed acknowledgments and receipts.
  7. Each change is an operation you can follow until every gateway has applied it.

Organizations and partners

An organization is a tenant. Every organization has its own members and roles (see Organization and roles). The same organization can be a sponsor of its own services and a partner (consumer) on someone else’s. A partner sees only its side of explicitly shared relationships: the services it was granted, never the sponsor’s other partners.

Organizations have a kind of customer or sample. Sample organizations are created by Try the Orders API and are always labelled “(sample)”. An organization created by an invitation to a new partner starts with no members and is unclaimed until someone accepts the invitation (see claiming).

Trust spaces

A trust space groups services that share a CA hierarchy in one environment (sandbox or production). Creating a space provisions, through the isolated signer:

  • a private root (path length 1), the trust anchor whose fingerprint the portal shows;
  • an online issuing CA (path length 0) that signs workload leaves;
  • a separate manifest-signing key used only to sign policy manifests.

There is no trust between spaces or between customers. Space names are unique per organization and environment.

Services and route templates

A service is an API behind one or more of your gateways. Its route templates are the upper bound of what you can ever grant on it; every grant’s scope must fit inside them. A template has a name, methods and a path, and may be flagged restricted as a label for humans (the flag does not change matching).

Route templates (CreateService.route_templates)
[ { "name": "Read orders", "methods": [ "GET" ], "path": "/orders/*" }, { "name": "Submit orders", "methods": [ "POST" ], "path": "/orders" }, { "name": "Admin export (restricted)", "methods": [ "GET" ], "path": "/admin/*", "restricted": true } ]

How routes match

Route matching rules
RuleBehaviour
Exact path/orders matches only /orders (a single trailing slash is ignored).
Wildcard/orders/* matches /orders and every descendant such as /orders/1001/lines, but not /orders-archive.
MethodsOne or more of GET HEAD POST PUT PATCH DELETE OPTIONS. A HEAD request is allowed wherever GET is granted.
Query stringIgnored for matching.
Ambiguous pathsRefused (deny ambiguous_route): encoded %2F, %5C, %00 or %2E, backslashes, . or .. segments, empty segments, or invalid percent-encoding.
Allowed charactersRule paths match ^/[A-Za-z0-9._~\-/]*(/\*)?$, at most 200 characters, with no // or dot segments.

Invitations

An invitation offers a scoped grant on one service to one intended organization. It carries a one-time secret (mtinv_…) that is shown once to the sponsor and stored only as a hash. It expires after expires_in_hours (default 168 hours, maximum 720). Redeeming it is atomic: two concurrent acceptances yield exactly one grant.

Invitation states
StateMeaningNext
pendingSent, not yet answered.accepted, declined, canceled, expired
acceptedRedeemed; a grant exists.None (terminal)
declinedThe recipient declined with the secret.None (terminal)
canceledThe sponsor withdrew the invitation.None (terminal)
expiredPast expires_at without an answer.None (terminal)

Grants and the grant state machine

A grant authorizes one workload of the consumer organization to call specific routes and methods of one sponsor service. It has a scope ({"v":1,"routes":[…]}), an optional expires_at, a state and an integer revision that increases on every change. Changes require If-Match with the current revision.

Grant states
StateEnforcementCapacityTransitions to
pendingDenied.None.active, revoked, expired
activeAllowed on its scope.Consumes a production connection.suspended, revoked, expired
suspendedDenied (grant_suspended), reversible.Slot stays reserved.active, revoked, expired
revokedDenied; every live leaf revoked; re-enrollment blocked.Released.None (terminal)
expiredDenied (grant_expired).Released.None (terminal)

Current build

Accepting an invitation creates the grant directly in active. Grants with an expires_at are moved to expired by the per-minute scheduler.

Reason codes for suspend and revoke are contract_ended, security_incident and owner_request.

Workloads and workload identity

A workload is the partner’s calling software: a service, job or pod. It belongs to the consumer organization and is bound to an attestation at acceptance time:

  • sandbox_token: sandbox only. A partner admin approves enrollment in the browser and the CLI redeems a single-use token.
  • oidc_jwt: an exact issuer, audience and subject from an OIDC workload identity provider the consumer organization approved, such as a Kubernetes service account. Required in production.

Every certificate issued to a workload carries exactly one URI SAN, its workload identity URI:

Workload identity URI
urn:mutualtrust:workload:<environment>:<consumer org id>:<workload id> urn:mutualtrust:workload:sandbox:org_01jcqa7m3a2b7c9d4e6f8g1h3j:wl_01jcqb3p1y2z4a6b8c0d2e4f6g

Gateways authorize on this URI and the issuing CA, never on the subject CN or O, which are informational. The URI’s environment must match the gateway’s environment.

Issuers and the CA hierarchy

Per-space CA hierarchy
IssuerProfileConstraintsSandbox validity
Rootmt.ca.root.v1CA, pathLen 1, keyCertSign + cRLSign90 days
Issuing CAmt.workload.clientauth.v1CA, pathLen 0, keyCertSign + cRLSign60 days
Workload leafmt.workload.clientauth.v1CA:false, digitalSignature, clientAuth24 hours

Subjects read “Mutual Trust SANDBOX TEST Root · <space>” / “… Issuing CA · <space>” with O = your organization and OU = the space ID. Leaf validity is bounded by the grant’s expiry and the issuing CA’s validity. Export the public chain with GET /v1/spaces/{id}/trust-bundle.pem. The full leaf profile is in Wire formats.

Policy revisions and epochs

The control plane compiles a policy document per service from authoritative state: trusted issuing CAs, one rule per active grant and issuer, and a deny set of suspended or withdrawn grants and revoked serials that are still within validity. Each distinct document gets the next (epoch, revision) for the service; publishing is skipped when nothing changed, so revisions only move when enforcement would.

  • Revision increases monotonically within an epoch. Gateways reject a lower revision (downgrade) and a same-revision manifest with a different hash (replay conflict).
  • Epoch starts at 1 and changes only through an authenticated recovery action (for example after a database restore), so that gateways never accept an older state.
  • The policy_hash is the SHA-256 of the canonical JSON of the policy document.

Manifests

A manifest is the policy document wrapped in a compact JWS (ES256, typ: mt.manifest.v1+jws) signed with the space’s manifest key and scoped to one tenant, environment, service and gateway. It is valid for 300 seconds after issue. Gateways refresh every 15 seconds, accept a cached manifest until exp plus a 30-second clock allowance, and then fail closed. The verification key is pinned during pairing. See Manifest JWS.

Receipts

For every request a gateway signs a receipt (mt.receipt.v1+jws) with its own pairing key. A receipt records two separate verdicts, TLS (verified, failed or absent) and authorization (allow or deny with a reason), plus the gateway, policy revision, grant, principal, serial, method, normalized route and time. Request bodies, headers and payloads are never sent.

Operations: configured, delivered, applied

Every grant or certificate change returns an operation_id. GET /v1/operations/{id} reports progress per paired gateway:

Operation evidence states
StateMeaning
ConfiguredThe change is committed in the control plane (effective_control_plane_time). The operation is publishing until a policy revision that includes it exists.
DeliveredThe gateway fetched a manifest at or above the target revision (delivered_at).
AppliedThe gateway returned a signed acknowledgment that it applied that revision (applied_at, apply_latency_seconds).
Offline (pending)The gateway has not checked in for 5 minutes. It will fail closed when its cached manifest expires.
VerifiedFor a service as a whole: the readiness checklist has seen a real allowed request and a denied control request with verified TLS.

Evidence is per gateway

A last applied revision is evidence about that one gateway only, never evidence of enforcement everywhere. Offline gateways are always listed as pending.