Quickstart
You need a sandbox tenant. Request sandbox access and we create one for you. You receive three API keys (admin, agent and enforcer), a seeded demo setup, and the console address. Keys look like pv_test_<prefix>_<secret>. Send them as Authorization: Bearer <key>.
The seeded tenant has an agent called Treasury Agent at version 3.7, an active mandate, an allowlist with a few suppliers, and a default policy. Find the mandate id in the console, under Mandates.
Set two variables in your shell. Use the agent key from your welcome message.
export POLIVOR=https://api.staging.polivor.com
export AGENT_KEY=pv_test_...
1. Ask for authority
Every authorize call needs an Idempotency-Key. Money is always an integer in minor units (cents) plus an ISO 4217 currency, never a decimal.
{
"agent_version": "3.7",
"mandate_id": "2d1b3b44-5e0c-4a3c-9a7e-6f1f7a9c0a11",
"action": {
"type": "PayInvoice",
"amount_minor": 420000,
"currency": "EUR",
"debtor_account": "ES9121000418450200051332",
"payment_type": "SEPA_CT",
"beneficiary": {
"id": "lopez-sl",
"iban": "ES7620770024003102575766"
},
"reference": "INV-104"
}
}
curl -sS "$POLIVOR/v1/authorize" \
-H "Authorization: Bearer $AGENT_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d @request.json
An allowed payment returns 200:
{
"decision_id": "6a0b7f0e-3d5e-4d6c-8a54-0d6a6a8b8c21",
"outcome": "ALLOW",
"reasons": [{ "policy_id": "agent.may_pay_invoices" }],
"checks": [
{ "id": "agent.active", "result": "pass" },
{ "id": "agent.version_authorized", "result": "pass" },
{ "id": "mandate.active", "result": "pass" },
{ "id": "beneficiary.allowlisted", "result": "pass" },
{ "id": "beneficiary.iban_match", "result": "pass" }
],
"mandate": { "id": "2d1b3b44-5e0c-4a3c-9a7e-6f1f7a9c0a11", "version": 1 },
"policy_version": 1,
"evidence": { "id": "b53c9b3e-9a1e-4a43-9c5b-2a6f5c6e7d10", "seq": 17 },
"authorization": {
"id": "0f6c8f6e-2f0d-4b8e-bb0a-3a1d4c5e6f70",
"jws": "eyJhbGciOiJFZERTQSIsInR5cCI6InBvbGl2b3ItYXV0aHorand0In0.eyJpc3MiOi4uLn0.c2lnbmF0dXJl",
"expires_at": "2026-10-14T10:05:00Z"
}
}
A payment that needs a person returns 202 with REQUIRE_APPROVAL and no authorization yet; see Approvals and webhooks. A refused payment returns 200 with DENY and the reasons.
2. Hand the authorization to the enforcement point
The authorization.jws is the proof. It is valid for 5 minutes and only for this exact payment. Your payment system verifies it before releasing money; Enforcement points lists the checks. You need only the public keys, at GET /.well-known/jwks.json.
3. Report what happened
After the payment system acts, it reports with the enforcer key. One terminal report is accepted per authorization.
{ "status": "EXECUTED", "external_ref": "bank-ref-77812" }
curl -sS -X POST "$POLIVOR/v1/authorizations/$AUTHORIZATION_ID/execution" \
-H "Authorization: Bearer $ENFORCER_KEY" \
-H "Content-Type: application/json" \
-d '{"status":"EXECUTED","external_ref":"bank-ref-77812"}'
REJECTED and FAILED give the reserved budget back. EXECUTED keeps it used.
4. See the evidence
Open the console, Evidence, and export a range. The export is a bundle that anyone can verify offline: the hash chain, every signature and every authorization. See Evidence.
Try without risk
POST /v1/simulate (admin key) runs the same decision without writing anything, issuing an authorization or reserving budget. The console simulator does the same with ready-made scenarios.