All docs

API / Authentication

Authenticate a headless agent

The agent authentication API is live at https://api.muniment.ai. Discover its contract, enroll an organization-owned agent, exchange a signed proof for a short-lived bearer, and revoke that authority when it is no longer needed.

Discover the contract

Fetch the live muniment.agent-auth/1 discovery document before enrolling or exchanging a token. It supplies the issuer, enrollment endpoint, token endpoint, gateway audience, supported profiles, signing algorithm, and lifetime limits.

shell
curl --fail-with-body \
  https://api.muniment.ai/.well-known/muniment-agent-auth

RFC 9728 standardizes OAuth protected-resource metadata. This gateway publishes the Muniment discovery document named above; use its path and returned values exactly rather than deriving a different well-known path or schema.

Enroll an agent

A freshly authenticated organization owner first creates the agent principal. Keep the returned agent ID and owner approval ID for the enrollment request.

shell
curl --fail-with-body \
  --request POST \
  --header "Authorization: Bearer ${MUNIMENT_OWNER_BEARER}" \
  --header "Content-Type: application/json" \
  --data '{
    "display_name": "build-agent",
    "owner_user_id": "<owner-user-uuid>"
  }' \
  https://api.muniment.ai/v1/agents

Generate an Ed25519 key pair in the agent's credential store, then submit its public JWK. Choose fresh, opaque profile and key identifiers that match the discovery contract.

shell
curl --fail-with-body \
  --request POST \
  --header "Authorization: Bearer ${MUNIMENT_OWNER_BEARER}" \
  --header "Content-Type: application/json" \
  --data '{
    "contract_version": "muniment.agent-auth/1",
    "agent_id": "<agent-id>",
    "profile_id": "<new-profile-id>",
    "profile_type": "agent_key",
    "public_key": {
      "kty": "OKP",
      "crv": "Ed25519",
      "kid": "<key-id>",
      "x": "<43-character-base64url-public-key>"
    },
    "owner_approval_id": "<owner-approval-id>"
  }' \
  https://api.muniment.ai/v1/auth/agent/enrollments

The response displays the enrollment secret once. Build the AgentEnrollmentConsumeRequest below and replace the illustrative NumericDates with current integer Unix seconds. Compute SECRET as unpadded base64url of SHA-256 over the ASCII enrollment secret. Join the following lines with LF, with no final LF, sign those exact UTF-8 bytes with the submitted Ed25519 private key, and put the unpadded base64url signature in key_proof.signature. For both proof types, choose a fresh unique jti; require iat and nbf no more than 60 seconds ahead, exp no more than 60 seconds behind, exp > nbf, and exp-iat <= 300. These boundaries are inclusive.

exact signing transcript
MUNIMENT-AGENT-ENROLLMENT-V1
POST
/v1/auth/agent/enrollments/consume
<enrollment-id>
<SECRET>
<profile-id>
<key-id>
<iat-decimal>
<nbf-decimal>
<exp-decimal>
<fresh-unique-jti>
shell
curl --fail-with-body \
  --request POST \
  --header "Content-Type: application/json" \
  --data '{
    "contract_version": "muniment.agent-auth/1",
    "enrollment_id": "<enrollment-id>",
    "enrollment_secret": "<display-once-enrollment-secret>",
    "key_proof": {
      "alg": "EdDSA",
      "profile_id": "<profile-id>",
      "key_id": "<key-id>",
      "iat": 1700000000,
      "nbf": 1700000000,
      "exp": 1700000300,
      "jti": "<fresh-unique-jti>",
      "signature": "<unpadded-base64url-ed25519-signature>"
    }
  }' \
  https://api.muniment.ai/v1/auth/agent/enrollments/consume

Exactly one concurrent consumer succeeds. An expired, revoked, replayed, or already consumed enrollment fails closed.

Exchange for a bearer

Build the KeyExchangeRequest below. Its signed_body contains exactly grant_type,requested_token_type, and the discovered audience. Canonicalize that object with RFC 8785 JCS, hash its UTF-8 bytes with SHA-256, and set BODY to the digest's unpadded base64url encoding. Join the following lines with LF, with no final LF, sign those exact UTF-8 bytes with the enrolled Ed25519 key, and place the unpadded base64url signature in key_proof.signature. Replace the illustrative NumericDates with current integer Unix seconds. Federated profiles use the alternative federated request published by the contract.

exact signing transcript
MUNIMENT-AGENT-KEY-V1
POST
/v1/auth/agent/token
<BODY>
<profile-id>
<key-id>
<discovered-gateway-audience>
<iat-decimal>
<nbf-decimal>
<exp-decimal>
<fresh-unique-jti>
shell
curl --fail-with-body \
  --request POST \
  --header "Content-Type: application/json" \
  --data '{
    "contract_version": "muniment.agent-auth/1",
    "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
    "subject_token_type": "urn:muniment:params:oauth:token-type:agent-key-assertion",
    "requested_token_type": "urn:ietf:params:oauth:token-type:access_token",
    "audience": "<discovered-gateway-audience>",
    "signed_body": {
      "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
      "requested_token_type": "urn:ietf:params:oauth:token-type:access_token",
      "audience": "<discovered-gateway-audience>"
    },
    "key_proof": {
      "alg": "EdDSA",
      "profile_id": "<profile-id>",
      "key_id": "<key-id>",
      "iat": 1700000000,
      "nbf": 1700000000,
      "exp": 1700000300,
      "jti": "<fresh-unique-jti>",
      "signature": "<unpadded-base64url-ed25519-signature>"
    }
  }' \
  https://api.muniment.ai/v1/auth/agent/token

The returned EdDSA bearer has only model:invoke scope and a maximum lifetime of 600 seconds. There is no refresh token. Exchange another fresh, replay-safe signed proof when the bearer expires.

Call the gateway

Send the short-lived bearer in the HTTP authorization header. Never put it in a URL or request body.

shell
curl --fail-with-body \
  --header "Authorization: Bearer ${MUNIMENT_AGENT_BEARER}" \
  --header "Content-Type: application/json" \
  --data '{"model":"<entitled-model>","messages":[{"role":"user","content":"Reply with one word."}]}' \
  https://api.muniment.ai/v1/chat/completions

Admission checks the current organization, agent principal, profile, and revocation epoch. For verified CrewAI and PydanticAI setup, and for the three supported wire protocols, continue to model-tool connection recipes.

Receipt attribution

An admitted call produces tenant-scoped receipt provenance attributed from the validated server-side agent identity. Caller-supplied organization, user, role, grant, entitlement, budget, or provider-key values cannot establish authority. This contract does not publish receipt response fields or a receipt-read endpoint.

Revoke access

A freshly authenticated organization owner can revoke one profile, revoke an agent and all of its credentials, or advance the organization epoch to invalidate all existing agent sessions.

one profile
curl --fail-with-body \
  --request POST \
  --header "Authorization: Bearer ${MUNIMENT_OWNER_BEARER}" \
  https://api.muniment.ai/v1/agents/<agent-id>/profiles/<profile-id>/revoke
one agent
curl --fail-with-body \
  --request POST \
  --header "Authorization: Bearer ${MUNIMENT_OWNER_BEARER}" \
  https://api.muniment.ai/v1/agents/<agent-id>/revoke
organization emergency control
curl --fail-with-body \
  --request POST \
  --header "Authorization: Bearer ${MUNIMENT_OWNER_BEARER}" \
  https://api.muniment.ai/v1/agents/revocations/epoch

Revocation is checked against live authority; a bearer with a stale profile, principal, or organization epoch is denied.

Credential safety

Treat the owner bearer, enrollment secret, private key, signed assertion, and agent bearer as identity credentials. Keep them out of source control, command history, support messages, fixtures, and application logs. Store the private key in the agent's credential store, redact authorization headers, and never substitute an OpenAI or other provider key. Provider credentials remain server-side.

This reference documents the live gateway API only. It does not claim public availability for a Muniment CLI, editor extension, Desktop app, Mobile app, or admin UI.

Search docs

Early access

One governed workspace for every model

See which work produced each model bill, with grants, routing, and records in one place.