Polivor

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.