Polivor

API reference

Per-action authority for AI agents acting on delegated financial authority. Version 0.1.0. The source is the OpenAPI 3.1 file.

Authentication

Send an API key as Authorization: Bearer <key>. Key format pv_test__; roles admin, agent, enforcer. Each operation lists the roles that may call it. The key set is public only for GET /.well-known/jwks.json.

Base URLs

  • https://api.polivor.com
  • https://api.staging.polivor.com

Operations

mcp

POST /mcp

Model Context Protocol server with the tools authorize and get_decision (role agent)

Roles: agent. Operation id mcpMessage.

MCP over Streamable HTTP, answered as plain JSON (no event stream, no sessions): one JSON-RPC 2.0 message per POST. Supported methods: initialize, ping, tools/list and tools/call; notifications get 202. Protocol versions 2025-06-18, 2025-03-26 and 2024-11-05. The tool authorize takes the fields of AuthorizeRequest plus a required idempotency_key; get_decision takes decision_id. A tool result carries the same JSON as the REST response (as structuredContent and as text); a business error is a tool result with isError: true holding a problem details object. Same API keys, roles and rate limits as /v1. Requests with an Origin header are refused (MCP clients are programs, not web pages). GET is not supported (405).

NameInRequiredTypeDescription
MCP-Protocol-Versionheaderno2025-06-18, 2025-03-26, 2024-11-05Sent by clients after initialize

Request body (JSON, required): JsonRpcMessage

StatusMeaningBody
200A JSON-RPC response (a result, or an error object)JsonRpcMessage
202A notification was received (no response body)
400Problem details with a stable code
401Problem details with a stable code
403Problem details with a stable code
429Problem details with a stable code

authorize

POST /v1/authorize

Request authority for one action (role agent)

Roles: agent. Operation id authorize.

400 IDEMPOTENCY_KEY_REQUIRED when the header is missing. 409 IDEMPOTENCY_KEY_REUSED when the key was used with a different body (or by another agent), and IDEMPOTENCY_KEY_EXPIRED once the 24 h retention is over. A replay returns the stored response unchanged. REQUIRE_APPROVAL reserves no budget; budget is reserved when the approval is granted.

NameInRequiredTypeDescription
no

Request body (JSON, required): AuthorizeRequest

StatusMeaningBody
200ALLOW (with authorization) or DENYAuthorizeResponse
202REQUIRE_APPROVAL, decision is pendingAuthorizeResponse
400Problem details with a stable code
401Problem details with a stable code
403Problem details with a stable code
409Problem details with a stable code
422Problem details with a stable code
429Problem details with a stable code

POST /v1/simulate

Dry run of the same decision as authorize. No writes, no budget reserved, no authorization, no evidence (role admin)

Roles: admin. Operation id simulate.

Request body (JSON, required): SimulateRequest

StatusMeaningBody
200Simulated decisionSimulateResponse
400Problem details with a stable code
401Problem details with a stable code
403Problem details with a stable code
404Problem details with a stable code
422Problem details with a stable code

GET /v1/decisions/{id}

Decision status; authorization once approved (roles agent, admin)

Roles: agent, admin. Operation id getDecision.

NameInRequiredTypeDescription
no
StatusMeaningBody
200DecisionDecisionStatus
401Problem details with a stable code
403Problem details with a stable code
404Problem details with a stable code

authorization

POST /v1/authorizations/{id}/execution

Enforcement point reports a terminal execution result (role enforcer)

Roles: enforcer. Operation id reportExecution.

One terminal report per authorization. 409 ALREADY_REPORTED for a second one, 410 REPORT_WINDOW_CLOSED more than 24 h after the authorization expired. REJECTED and FAILED release the reserved budget; EXECUTED keeps it consumed.

NameInRequiredTypeDescription
no

Request body (JSON, required): ExecutionReport

StatusMeaningBody
200RecordedAuthorizationStatus
401Problem details with a stable code
403Problem details with a stable code
404Problem details with a stable code
409Problem details with a stable code
410Problem details with a stable code

POST /v1/authorizations/{id}/not-executed

Release an unreported authorization and its reserved budget (role admin)

Roles: admin. Operation id markNotExecuted.

Only after the authorization has expired (409 AUTHORIZATION_STILL_VALID before), because until then the enforcement point could still use it.

NameInRequiredTypeDescription
no
StatusMeaningBody
200ReleasedAuthorizationStatus
401Problem details with a stable code
403Problem details with a stable code
404Problem details with a stable code
409Problem details with a stable code

identity

POST /v1/principals

Roles: admin. Operation id createPrincipal.

Request body (JSON, required): PrincipalCreate

StatusMeaningBody
201CreatedPrincipal
400Problem details with a stable code
401Problem details with a stable code
403Problem details with a stable code
422Problem details with a stable code

GET /v1/agents

Roles: admin. Operation id listAgents.

StatusMeaningBody
200Agents with their versionsarray of Agent
401Problem details with a stable code
403Problem details with a stable code

POST /v1/agents

Roles: admin. Operation id createAgent.

Request body (JSON, required): AgentCreate

StatusMeaningBody
201CreatedAgent
400Problem details with a stable code
401Problem details with a stable code
403Problem details with a stable code
422Problem details with a stable code

POST /v1/agents/{id}/versions

Roles: admin. Operation id registerAgentVersion.

NameInRequiredTypeDescription
no

Request body (JSON, required): object

StatusMeaningBody
201RegisteredAgent
400Problem details with a stable code
401Problem details with a stable code
403Problem details with a stable code
404Problem details with a stable code
409Problem details with a stable code
422Problem details with a stable code

POST /v1/agents/{id}/suspend

Roles: admin. Operation id suspendAgent.

NameInRequiredTypeDescription
no
StatusMeaningBody
200SuspendedAgent
401Problem details with a stable code
403Problem details with a stable code
404Problem details with a stable code

mandate

GET /v1/mandates

Roles: admin. Operation id listMandates.

StatusMeaningBody
200Mandatesarray of Mandate
401Problem details with a stable code
403Problem details with a stable code

POST /v1/mandates

Create a native Financial Mandate (validated against financial-mandate/v0)

Roles: admin. Operation id createMandate.

Request body (JSON, required): MandateBody

StatusMeaningBody
201Created as DRAFT, version 1Mandate
400Problem details with a stable code
401Problem details with a stable code
403Problem details with a stable code
422Problem details with a stable code

POST /v1/mandates/import/ap2

Import an AP2 open payment mandate into a DRAFT native mandate (adapter; body at most 64 KB)

Roles: admin. Operation id importAp2Mandate.

Accepts an AP2 v0.2 Open Payment Mandate (vct mandate.payment.open.1) as an SD-JWT signed ES256 by a key of a trusted issuer (POST /v1/trusted-issuers). The signature, every disclosure and the expiry are checked. What AP2 states precisely is copied (per-payment maximum as integer minor units and its currency, the validity window); everything else is listed in the report as not enforced natively or as still to complete. Principal and agent come from the request.

Constraints Polivor cannot enforce. AP2 says a constraint a verifier does not understand must fail evaluation, and a native mandate is looser than the credential wherever it cannot enforce one. So an import that carries payees, a budget, recurrence, payment instruments, PISPs, a reference or a minimum amount is refused (422 AP2_UNENFORCED_CONSTRAINTS, one error per type) until the request names each of them in acknowledge_unenforced; constraint types AP2 does not define at all are never imported (422 AP2_UNKNOWN_CONSTRAINT). Issuer keys are the ones registered for the issuer plus, if it has a jwks_url, the set published there at the time of the import (AP2_ISSUER_KEYS_UNAVAILABLE if that cannot be fetched). The DRAFT cannot be activated until a new version with the missing fields is created (POST /v1/mandates/{id}/versions). The raw credential and its hash are kept.

Request body (JSON, required): object

StatusMeaningBody
201DRAFT mandate and what was done with each part of the credentialAp2ImportResult
400Problem details with a stable code
401Problem details with a stable code
403Problem details with a stable code
404Problem details with a stable code
409Problem details with a stable code
422Problem details with a stable code

GET /v1/trusted-issuers

Roles: admin. Operation id listTrustedIssuers.

StatusMeaningBody
200Trusted issuers of this tenantarray of TrustedIssuer
401Problem details with a stable code
403Problem details with a stable code

POST /v1/trusted-issuers

Register an issuer whose AP2 credentials may be imported (public keys only)

Roles: admin. Operation id registerTrustedIssuer.

Give the issuer's public P-256 keys (jwks), the HTTPS URL where it publishes them (jwks_url), or both. A URL is fetched when a credential is imported and is never cached, so a rotated or withdrawn key takes effect immediately. The URL must be public (no private or internal addresses), is not followed through redirects, and must serve at most 10 public keys, each with a kid.

Request body (JSON, required): any or any

StatusMeaningBody
201RegisteredTrustedIssuer
400Problem details with a stable code
401Problem details with a stable code
403Problem details with a stable code
422Problem details with a stable code

GET /v1/mandates/{id}

The version in force, or any other version with ?version=n (versions are immutable and stay readable)

Roles: admin. Operation id getMandate.

NameInRequiredTypeDescription
no
versionquerynointeger (minimum 1)
StatusMeaningBody
200Mandate with all versions readableMandate
401Problem details with a stable code
403Problem details with a stable code
404Problem details with a stable code

POST /v1/mandates/{id}/versions

Create version n+1 (versions are immutable)

Roles: admin. Operation id createMandateVersion.

NameInRequiredTypeDescription
no

Request body (JSON, required): MandateBody

StatusMeaningBody
201New versionMandate
400Problem details with a stable code
401Problem details with a stable code
403Problem details with a stable code
404Problem details with a stable code
409Problem details with a stable code
422Problem details with a stable code

POST /v1/mandates/{id}/activate

Roles: admin. Operation id activateMandate.

NameInRequiredTypeDescription
no
StatusMeaningBody
200Problem details with a stable code
401Problem details with a stable code
403Problem details with a stable code
404Problem details with a stable code
409Problem details with a stable code
422Problem details with a stable code

POST /v1/mandates/{id}/suspend

Roles: admin. Operation id suspendMandate.

NameInRequiredTypeDescription
no
StatusMeaningBody
200Problem details with a stable code
401Problem details with a stable code
403Problem details with a stable code
404Problem details with a stable code
409Problem details with a stable code

POST /v1/mandates/{id}/resume

Roles: admin. Operation id resumeMandate.

NameInRequiredTypeDescription
no
StatusMeaningBody
200Problem details with a stable code
401Problem details with a stable code
403Problem details with a stable code
404Problem details with a stable code
409Problem details with a stable code

POST /v1/mandates/{id}/revoke

Final; cannot be undone

Roles: admin. Operation id revokeMandate.

NameInRequiredTypeDescription
no
StatusMeaningBody
200Problem details with a stable code
401Problem details with a stable code
403Problem details with a stable code
404Problem details with a stable code
409Problem details with a stable code

beneficiary

GET /v1/beneficiaries

Roles: admin. Operation id listBeneficiaries.

StatusMeaningBody
200Allowlistarray of Beneficiary
401Problem details with a stable code
403Problem details with a stable code

POST /v1/beneficiaries

Roles: admin. Operation id createBeneficiary.

Request body (JSON, required): BeneficiaryCreate

StatusMeaningBody
201CreatedBeneficiary
400Problem details with a stable code
401Problem details with a stable code
403Problem details with a stable code
409Problem details with a stable code
422Problem details with a stable code

PATCH /v1/beneficiaries/{id}

Roles: admin. Operation id updateBeneficiary.

NameInRequiredTypeDescription
no

Request body (JSON, required): BeneficiaryUpdate

StatusMeaningBody
200UpdatedBeneficiary
400Problem details with a stable code
401Problem details with a stable code
403Problem details with a stable code
404Problem details with a stable code
422Problem details with a stable code

policy

GET /v1/policies

Roles: admin. Operation id listPolicies.

StatusMeaningBody
200Policy versionsarray of PolicyVersion
401Problem details with a stable code
403Problem details with a stable code

POST /v1/policies

Create a DRAFT policy version from template parameters or raw Cedar; validated against the Cedar schema

Roles: admin. Operation id createPolicy.

Request body (JSON, required): PolicyCreate

StatusMeaningBody
201DRAFT versionPolicyVersion
400Problem details with a stable code
401Problem details with a stable code
403Problem details with a stable code
422Problem details with a stable code

POST /v1/policies/{version}/publish

Publish; immutable afterwards. Rejected if a permit rule references signals

Roles: admin. Operation id publishPolicy.

NameInRequiredTypeDescription
versionpathyesinteger (minimum 1)
StatusMeaningBody
200Now the active versionPolicyVersion
401Problem details with a stable code
403Problem details with a stable code
404Problem details with a stable code
409Problem details with a stable code
422Problem details with a stable code

evidence

GET /v1/evidence

Roles: admin. Operation id listEvidence.

NameInRequiredTypeDescription
from_seqquerynointeger (minimum 0)
limitquerynointeger (minimum 1, maximum 1000, default 100)
StatusMeaningBody
200Evidence rows in sequence orderarray of EvidenceRow
401Problem details with a stable code
403Problem details with a stable code

GET /v1/evidence/export

Bundle for a range - rows, JWS, chain hashes and JWKS - verifiable offline

Roles: admin. Operation id exportEvidence.

At most 10000 rows per export (422 RANGE_TOO_LARGE otherwise).

NameInRequiredTypeDescription
from_seqquerynointeger (minimum 0)
to_seqquerynointeger (minimum 0)
StatusMeaningBody
200Export bundleEvidenceBundle
401Problem details with a stable code
403Problem details with a stable code
422Problem details with a stable code

GET /.well-known/jwks.json

Public keys (authz-signing and evidence-signing, all versions)

No API key needed. Operation id getJwks.

StatusMeaningBody
200JWKSJwks

keys

GET /v1/keys

Keys of this tenant, active and revoked (never the secret)

Roles: admin. Operation id listApiKeys.

StatusMeaningBody
200Keys, newest firstarray of ApiKey
401Problem details with a stable code
403Problem details with a stable code

POST /v1/keys

Create an API key; the secret is returned once and stored hashed

Roles: admin. Operation id createApiKey.

Request body (JSON, required): ApiKeyCreate

StatusMeaningBody
201CreatedApiKeyCreated
400Problem details with a stable code
401Problem details with a stable code
403Problem details with a stable code
422Problem details with a stable code

POST /v1/keys/{id}/revoke

Revoke a key; takes effect on the next request (well within 5 s). Idempotent

Roles: admin. Operation id revokeApiKey.

The last active admin key cannot be revoked (409 LAST_ADMIN_KEY).

NameInRequiredTypeDescription
no
StatusMeaningBody
204Revoked
401Problem details with a stable code
403Problem details with a stable code
404Problem details with a stable code
409Problem details with a stable code

webhook

GET /v1/webhook

The tenant's webhook URL, if any (role admin)

Roles: admin. Operation id getWebhook.

StatusMeaningBody
200Webhook statusWebhookStatus
401Problem details with a stable code
403Problem details with a stable code

PUT /v1/webhook

Set the webhook URL and create a new signing secret, shown once (role admin)

Roles: admin. Operation id setWebhook.

Events: decision.resolved (an approval ended: ALLOWED with the authorization, or DENIED with a reason), authorization.reported (an execution report or an admin release) and webhook.test. Each delivery is POST with the JSON body {id, type, created_at, tenant_id, data} and the headers Polivor-Event-Id and Polivor-Signature: t=<unix seconds>,v1=<hex>, where v1 is HMAC-SHA256 of <t>.<raw body> with the secret. Reject deliveries whose t is far from your clock. Any 2xx is success; other results are retried 5 times with backoff (1 min, 5 min, 15 min, 1 h, 6 h) and the same event ID. The URL must be HTTPS and public.

Request body (JSON, required): WebhookSet

StatusMeaningBody
200Configured. The secret is not shown again; setting the URL again creates a new one.WebhookConfigured
400Problem details with a stable code
401Problem details with a stable code
403Problem details with a stable code
422Problem details with a stable code

DELETE /v1/webhook

Stop sending events (role admin)

Roles: admin. Operation id removeWebhook.

StatusMeaningBody
204Removed or none was set
401Problem details with a stable code
403Problem details with a stable code

Schemas

WebhookSet

PropertyTypeRequiredDescription
urlstring (maxLength 2048)yesHTTPS

WebhookStatus

PropertyTypeRequiredDescription
configuredbooleanyes
urlstring or nullno

WebhookConfigured

PropertyTypeRequiredDescription
urlstringyes
secretstringyesShown once. Sign check: HMAC-SHA256(secret, ".")

JsonRpcMessage

A JSON-RPC 2.0 request, notification, result or error object (https://www.jsonrpc.org/specification)

PropertyTypeRequiredDescription
jsonrpc"2.0"yes
idstring or integer or nullno
methodstringno
paramsobjectno
resultobjectno
errorobjectno

Uuid

Type: string, uuid

Currency

Type: string (pattern "^[A-Z]{3}$")

Country

Type: string (pattern "^[A-Z]{2}$")

Iban

Type: string (pattern "^[A-Z]{2}[0-9]{2}[A-Z0-9]{11,30}$")

MinorAmount

Integer minor units (cents); never a float

Type: integer, int64 (minimum 1)

Problem

PropertyTypeRequiredDescription
typestringyes
titlestringyes
statusintegeryes
detailstringno
codestringyesStable machine-readable code. Match on it, not on detail. New codes can be added, so treat an unknown code by its HTTP status. Every code with its status and meaning is in the error codes guide (/docs/errors-limits.html); a test keeps that list equal to the codes the API can return.
errorsarray of objectno

Reason

PropertyTypeRequiredDescription
policy_idstringnoThe Cedar policy that decided
codestringnoA pre-check or system reason, e.g. AGENT_SUSPENDED, MANDATE_REVOKED, NO_PERMIT, NO_ACTIVE_POLICY

Check

PropertyTypeRequiredDescription
idstringyes
resultpass, fail, satisfied, not_satisfiedyes
detailobjectno

Beneficiary_Ref

Unknown fields are ignored. Everything decisive about the beneficiary is computed by Polivor from the allowlist and the IBAN.

PropertyTypeRequiredDescription
idstring (minLength 1, maxLength 100)yes
ibanstring (minLength 1, maxLength 42)yes
countrystringnoAccepted for compatibility and never used

Action

Unknown fields are ignored and never influence the decision.

PropertyTypeRequiredDescription
type"PayInvoice"yes
amount_minorMinorAmountyes
currencyCurrencyyes
debtor_accountstring (minLength 15, maxLength 42)yes
payment_typeSEPA_CT, SEPA_INSTyes
beneficiaryBeneficiary_Refyes
referencestring (minLength 1, maxLength 140)yes

Signals

Agent-supplied; may only be used in forbid rules (signals tighten, never loosen). Unknown fields are ignored.

PropertyTypeRequiredDescription
originstring (maxLength 100)no
risk_flagsarray of string (maxItems 50)no

AuthorizeRequest

Unknown fields are ignored. Flags such as iban_changed or beneficiary_allowlisted have no effect, Polivor computes those facts itself.

PropertyTypeRequiredDescription
agent_versionstring (minLength 1, maxLength 64)yes
mandate_idUuidyes
actionActionyes
signalsSignalsno

SimulateRequest

Combines: AuthorizeRequest and object

SimulateResponse

PropertyTypeRequiredDescription
simulatedtrueyes
outcomeALLOW, DENY, REQUIRE_APPROVALyes
reasonsarray of Reasonyes
checksarray of Checkyes
mandateobjectno
policy_versioninteger (minimum 0)yes0 when no policy applied

AuthorizationArtifact

PropertyTypeRequiredDescription
idUuidyes
jwsstringyesCompact JWS, typ polivor-authz+jwt, alg EdDSA
expires_atstring, date-timeyes

AuthorizeResponse

PropertyTypeRequiredDescription
decision_idUuidyes
simulatedbooleanno
outcomeALLOW, DENY, REQUIRE_APPROVALyes
reasonsarray of Reasonyes
checksarray of Checkyes
mandateobjectno
policy_versioninteger (minimum 0)yes
evidenceobjectyesAbsent on simulate
authorizationAuthorizationArtifactno

DecisionStatus

PropertyTypeRequiredDescription
decision_idUuidyes
outcomeALLOW, DENY, REQUIRE_APPROVALyes
statusALLOWED, DENIED, PENDING_APPROVALyes
reasonsarray of Reasonno
authorizationAuthorizationArtifactno

ExecutionReport

PropertyTypeRequiredDescription
statusEXECUTED, REJECTED, FAILEDyes
external_refstring (maxLength 200)no

AuthorizationStatus

PropertyTypeRequiredDescription
idUuidyes
statusISSUED, EXECUTED, REJECTED, FAILED, NOT_EXECUTEDyes
reported_atstring or null, date-timeno
external_refstring or nullno

PrincipalCreate

PropertyTypeRequiredDescription
legal_namestring (minLength 1, maxLength 200)yes
countryCountryyes
leistring (pattern "^[A-Z0-9]{20}$")no

Principal

PropertyTypeRequiredDescription
idUuidyes
legal_namestring (minLength 1, maxLength 200)yes
countryCountryyes
leistring (pattern "^[A-Z0-9]{20}$")no

AgentCreate

PropertyTypeRequiredDescription
namestring (minLength 1, maxLength 200)yes
principal_idUuidyes
owner_emailstring, emailyes
versionstring (minLength 1, maxLength 64)yes

Agent

PropertyTypeRequiredDescription
idUuidyes
namestringyes
principal_idUuidyes
owner_emailstring, emailyes
statusACTIVE, SUSPENDED, RETIREDyes
versionsarray of stringyes
agent_keystringnoShown once, on agent creation only

MandateBody

Native Financial Mandate body. The authoritative definition is docs/schema/financial-mandate.v0.json; validated against it on write. A DRAFT imported from AP2 holds only the mapped fields until a complete version is added.

PropertyTypeRequiredDescription
schema"polivor.financial-mandate/v0"yes

TrustedIssuer

PropertyTypeRequiredDescription
idUuidyes
namestringyes
format"AP2"yes
key_idsarray of stringyesIds of the keys registered by hand
jwks_urlstring or nullno

Ap2ImportResult

PropertyTypeRequiredDescription
mandateMandateyes
reportobjectyes

Mandate

PropertyTypeRequiredDescription
idUuidyes
principal_idUuidyes
agent_idUuidyes
statusDRAFT, ACTIVE, SUSPENDED, REVOKEDyes
current_versioninteger (minimum 1)yesThe version in force (a DRAFT's current_version is the one activation will put in force)
latest_versioninteger (minimum 1)yesHighest version created; takes effect only when activated
versioninteger (minimum 1)yesThe version whose body is returned
sourceNATIVE, AP2yes
bodyMandateBodyyes

BeneficiaryCreate

PropertyTypeRequiredDescription
external_idstring (minLength 1, maxLength 100)yesThe ID the agent sends in an authorize request; letters, digits and . _ : @ / -
namestring (minLength 1, maxLength 200)yes
ibanstring (minLength 15, maxLength 42)yesSpaces and lowercase are accepted and normalised; the checksum is verified
countryCountryyes
statusAPPROVED, BLOCKED (default "APPROVED")no

BeneficiaryUpdate

PropertyTypeRequiredDescription
namestring (minLength 1, maxLength 200)no
ibanstring (minLength 15, maxLength 42)no
countryCountryno
statusAPPROVED, BLOCKEDno

Beneficiary

PropertyTypeRequiredDescription
idUuidyes
external_idstringyes
namestringyes
ibanIbanyes
countryCountryyes
statusAPPROVED, BLOCKEDyes

TemplateParams

Which rules the generated Cedar contains. The mandate's own limits, scope and threshold are facts in the Cedar context; the template only chooses which rules apply. Omitted properties take their default.

PropertyTypeRequiredDescription
scopeboolean (default true)nopermit requires debtor account, currency, beneficiary country and payment type inside the mandate scope
per_transaction_limitboolean (default true)no
daily_limitboolean (default true)no
monthly_limitboolean (default true)no
approval_thresholdboolean (default true)noforbid with approval when the amount exceeds the mandate's threshold
beneficiary_allowlistboolean (default true)noforbid with approval when the beneficiary is not on the allowlist
blocked_beneficiaryboolean (default true)noHard deny for an explicitly blocked beneficiary; never payable by approval
iban_mismatchboolean (default true)noforbid with approval when an allowlisted beneficiary's IBAN differs
risk_signalsarray of string (maxItems 20, default ["prompt_injection_suspected"])noAgent-reported risk flags that escalate to approval. Empty turns the rule off. Signals only ever tighten.

PolicyCreate

One of: any or any

PropertyTypeRequiredDescription
template_paramsTemplateParamsno
cedarstring (maxLength 65536)noRaw Cedar. Validated against the Cedar schema; context.signals is rejected in permit rules.

PolicyVersion

PropertyTypeRequiredDescription
idUuidno
versioninteger (minimum 1)yes
statusDRAFT, ACTIVE, RETIREDyes
cedarstringyes
cedar_sha256stringyesHex
template_paramsTemplateParams or nullno
published_atstring or null, date-timeno

EvidenceRow

PropertyTypeRequiredDescription
seqinteger (minimum 1)yes
event_typestringyes
subject_idUuidyes
payloadobjectyesRFC 8785 canonicalised before hashing
prev_hashstringyesHex
hashstringyesHex
jwsstringyes
key_versionintegeryes
created_atstring, date-timeyes

EvidenceBundle

Everything needed to verify a range of evidence offline (cli/verify or the console verifier): rows with canonical payloads, hashes and signatures, all public keys, and the authorization artifacts issued for the decisions in the range. A range that does not start at row 1 verifies internally; its first row's prev_hash is the anchor to compare with the previous row you hold.

PropertyTypeRequiredDescription
format"polivor.evidence-bundle/v1"yes
tenant_idUuidyes
exported_atstring, date-timeyes
from_seqinteger (minimum 0)yes
to_seqinteger (minimum 0)yes
rowsarray of EvidenceRowyes
jwksJwksyes
authorizationsarray of objectyes

Jwk

PropertyTypeRequiredDescription
kty"OKP"yes
crv"Ed25519"yes
xstringyes
kidstringyes
alg"EdDSA"no
useauthz, evidenceyes
revoked_atstring or null, date-timeno

Jwks

PropertyTypeRequiredDescription
keysarray of Jwkyes

ApiKeyCreate

agent_id is required if and only if role is agent

PropertyTypeRequiredDescription
roleadmin, agent, enforceryes
agent_idUuidno

ApiKey

PropertyTypeRequiredDescription
idUuidyes
roleadmin, agent, enforceryes
agent_idstring or nullno
prefixstringyesThe non-secret part (pv_test_) that identifies the key in logs
created_atstring, date-timeyes
revoked_atstring or null, date-timeno

ApiKeyCreated

PropertyTypeRequiredDescription
idUuidyes
roleadmin, agent, enforceryes
keystringyesPlaintext