Quiet modern enterprise office interior.

Documentation

Build on the trade-credit rail.

A REST API for invoice escrows, coverage, claims, and settlement. Configure your own underwriting and pricing; integrate through typed SDKs and signed webhooks. Everything here runs today against the Sandbox on Arbitrum Sepolia.

Overview

Introduction

The Prova API is organized around REST. It has predictable, resource-oriented URLs, accepts and returns JSON, and uses standard HTTP response codes, verbs, and authentication. It is the single integration surface for the platform’s engines — invoice escrows, coverage, premium, claims, and non-custodial settlement.

Institutions bring their own underwriting and pricing; the API executes them and returns posted outcomes. Sensitive risk inputs are represented as sealed values and are never decrypted — on-chain or by Prova.

ResourcePurpose
POST /v1/oauth/tokenExchange client credentials for an access token.
POST /v1/business-profilesCreate the institution or counterparty profile (KYB).
POST /v1/escrowsOpen an invoice-backed escrow.
POST /v1/coverage/quotesQuote coverage against an invoice.
POST /v1/coverageBind coverage from a quote.
POST /v1/claimsOpen a protracted-default claim.
GET /v1/transactionsList premium, settlement, and fee movements.
GET /v1/pool/statusRead capacity and utilization for a capital pool.

Get started

Quickstart

Six calls take you from credentials to a bound, settling policy. Each step links to its full reference below. You can run the entire flow against the Sandbox today.

  1. 1

    Authenticate

    Exchange your sandbox client credentials for a short-lived access token.

    curl https://api.sandbox.getprova.trade/v1/oauth/token \
      -u "$PROVA_CLIENT_ID:$PROVA_CLIENT_SECRET" \
      -d grant_type=client_credentials
  2. 2

    Create an invoice

    Open an invoice-backed escrow for the receivable you want to cover.

    curl https://api.sandbox.getprova.trade/v1/escrows \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -d invoice_number="INV-2043" -d amount=48000 -d currency=USDC \
      -d counterparty="bp_7c21a1180f4a"
    # → { "id": "esc_9f4c2be7a1d0", "status": "open" }
  3. 3

    Request a coverage quote

    Submit the invoice and sealed risk inputs; your policy and premium engines return a quote.

    curl https://api.sandbox.getprova.trade/v1/coverage/quotes \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -d invoice_id="esc_9f4c2be7a1d0" -d covered_pct=90 \
      -d 'risk[credit_score]=enc:0x9f4c…'
    # → { "id": "cvq_2be7…", "premium_bps": 200, "status": "quoted" }
  4. 4

    Bind the policy

    Bind the quote to create coverage. Terms carry through unchanged.

    curl https://api.sandbox.getprova.trade/v1/coverage \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -d quote_id="cvq_2be7a1d09f4c"
    # → { "id": "cov_2be7…", "status": "bound" }
  5. 5

    Receive the webhook

    Your endpoint receives a signed coverage.bound event. Verify the signature, then record it.

    POST /webhooks/prova
    Prova-Signature: t=1714563060,v1=5e21a3d0…
    { "type": "coverage.bound", "data": { "object": { "id": "cov_2be7…" } } }
  6. 6

    Monitor settlement

    Track premium, claim, and settlement movements as they post to the ledger.

    curl "https://api.sandbox.getprova.trade/v1/transactions?limit=20" \
      -H "Authorization: Bearer $ACCESS_TOKEN"

Setup

Environments

Every account has two isolated environments with separate credentials, data, and base URLs. Sandbox is fully functional for integration; it settles on Arbitrum Sepolia testnet with no real capital at risk.

EnvironmentBase URLAccess
Sandboxapi.sandbox.getprova.tradeAvailable for integration workshops (Arbitrum Sepolia)
Productionapi.getprova.tradeEnabled after independent audit and institutional onboarding

Prova is a testnet MVP. An independent smart-contract audit is required before any production capital is deployed. We do not enable Production, or represent it as live, before that gate is met.

Security

Authentication

The API authenticates with OAuth 2.0 client credentials. Each environment issues a client_id and client_secret scoped to specific resources. Exchange them for a short-lived access token, then send it as a bearer token on every request. Treat the secret like a production credential — it grants access to your book.

POST /v1/oauth/token
curl https://api.sandbox.getprova.trade/v1/oauth/token \
  -u "$PROVA_CLIENT_ID:$PROVA_CLIENT_SECRET" \
  -d grant_type=client_credentials \
  -d scope="coverage:write escrows:write"
200 OK
{
  "access_token": "prova_sandbox_at_9f4c2be7a1d0",
  "token_type": "Bearer",
  "expires_in": 900,
  "scope": "coverage:write escrows:write"
}

Access tokens expire in 15 minutes; request a new one as needed. Keys are managed per environment and can be rotated without downtime by issuing a new secret before retiring the old one.

Stability

Versioning

The major version is pinned in the URL path (/v1). Backward-compatible changes — new endpoints, new response fields, new event types — ship without a version bump. Breaking changes ship under a new major version, and existing versions remain supported.

Pin a dated release with the Prova-Version header (for example 2026-05-01) so behavior is deterministic across deploys. Requests without the header use your account default.

Core resource

Quote and bind coverage

Coverage is the most common first integration. You submit an invoice reference, the percentage to cover, and the sealed risk inputs; the Policy and Premium engines run your configured rules and return a quote with a premium in basis points. Binding the quote produces a coverage record.

POST /v1/coverage/quotes
curl https://api.sandbox.getprova.trade/v1/coverage/quotes \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Prova-Version: 2026-05-01" \
  -H "Idempotency-Key: 8f14e45f-ea0a-4b2c-9f1a-3d0c7b6a5e21" \
  -H "Content-Type: application/json" \
  -d '{
    "invoice_id": "inv_9f4c2be7a1d0",
    "covered_pct": 90,
    "risk": {
      "credit_score": "enc:0x9f4c…",
      "credit_limit": "enc:0x2be7…",
      "exposure":     "enc:0x1a08…"
    }
  }'
200 OK
{
  "id": "cvq_2be7a1d09f4c",
  "object": "coverage_quote",
  "invoice_id": "inv_9f4c2be7a1d0",
  "covered_pct": 90,
  "premium_bps": 200,
  "currency": "USDC",
  "status": "quoted",
  "expires_at": "2026-05-01T12:30:00Z",
  "created_at": "2026-05-01T12:00:00Z"
}

Bind the quote to create coverage. The premium and covered percentage are carried through unchanged.

POST /v1/coverage
curl https://api.sandbox.getprova.trade/v1/coverage \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Idempotency-Key: 5e21a3d0-c7b6-4a5e-8f14-e45fea0a4b2c" \
  -d quote_id="cvq_2be7a1d09f4c"
# → { "id": "cov_2be7a1d09f4c", "status": "bound", "premium_bps": 200 }

Reliability

Idempotency

All POST requests accept an Idempotency-Key header. Prova stores the first response for a key for 24 hours and replays it on any retry with the same key — so a network timeout never creates duplicate coverage or a duplicate claim. Reusing a key with a different request body returns 409 idempotency_conflict. Use a unique UUID per logical operation.

Reference

Errors

Prova uses conventional HTTP status codes and returns a structured error object with a stable code, a human-readable message, the offending parameter, and a request_id for support. Never branch on the message string; branch on the code.

422 Unprocessable Entity
{
  "error": {
    "type": "invalid_request_error",
    "code": "covered_pct_out_of_range",
    "message": "covered_pct must be between 1 and 100.",
    "param": "covered_pct",
    "request_id": "req_5e21a3d0c7b6"
  }
}
StatusTypeMeaning
400invalid_request_errorThe request was malformed or a parameter was out of range.
401authentication_errorThe access token is missing, expired, or invalid.
403permission_errorThe token is valid but lacks the scope for this resource.
404not_foundThe requested resource does not exist.
409idempotency_conflictAn Idempotency-Key was reused with a different payload.
422unprocessable_entityThe request was valid but could not be fulfilled.
429rate_limit_errorToo many requests. Retry after the Retry-After interval.
5xxapi_errorAn error on Prova’s side. Safe to retry idempotent requests.

Reference

Pagination

List endpoints are cursor-paginated. Pass limit (default 20, max 100). When has_more is true, request the next page with starting_after=<next_cursor>. Cursors are stable and safe to page through concurrent writes.

GET /v1/transactions
curl "https://api.sandbox.getprova.trade/v1/transactions?limit=20" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
200 OK
{
  "object": "list",
  "url": "/v1/transactions",
  "has_more": true,
  "next_cursor": "txn_1a08c7b6a5e2",
  "data": [
    {
      "id": "txn_1a08c7b6a5e2",
      "type": "premium",
      "amount": 960,
      "currency": "USDC",
      "coverage_id": "cov_2be7a1d09f4c",
      "created_at": "2026-05-01T12:31:00Z"
    }
  ]
}

Events

Webhooks

Prova delivers signed events to your HTTPS endpoint as the lifecycle advances. Each delivery carries a Prova-Signature header — an HMAC-SHA256 of the timestamp and raw body, keyed with your endpoint signing secret. Verify it before trusting the payload, and respond 2xx within 10 seconds; failed deliveries retry with exponential backoff.

Delivery
POST /webhooks/prova HTTP/1.1
Host: your-app.example.com
Prova-Signature: t=1714563060,v1=5e21a3d0c7b6a5e28f14e45fea0a4b2c…

{
  "id": "evt_7c21a1180f4a",
  "object": "event",
  "type": "coverage.bound",
  "created_at": "2026-05-01T12:31:00Z",
  "data": {
    "object": {
      "id": "cov_2be7a1d09f4c",
      "invoice_id": "inv_9f4c2be7a1d0",
      "covered_pct": 90,
      "premium_bps": 200,
      "status": "bound"
    }
  }
}
EventFires when
escrow.createdAn invoice-backed escrow was opened.
coverage.quotedA coverage quote was produced.
coverage.boundCoverage was bound against an invoice.
claim.openedA protracted-default claim entered review.
claim.resolvedA claim was accepted or declined.
settlement.completedA non-custodial settlement event was recorded.

Libraries

SDKs

A typed Node/TypeScript SDK wraps authentication, request signing, idempotency, pagination, and webhook verification. The API is described by an OpenAPI 3.1 contract, so you can generate a client in any language.

Install
npm install @prova/node
Quote coverage
import { Prova, seal } from '@prova/node'

const prova = new Prova(process.env.PROVA_SECRET_KEY)

// Sensitive inputs are sealed client-side before they touch the API.
const quote = await prova.coverage.quotes.create({
  invoice_id: 'inv_9f4c2be7a1d0',
  covered_pct: 90,
  risk: {
    credit_score: seal(riskScore),
    credit_limit: seal(creditLimit),
  },
})

console.log(quote.premium_bps) // 200
Verify a webhook
// Verify the signature before trusting an event.
const event = prova.webhooks.constructEvent(rawBody, signatureHeader, endpointSecret)

if (event.type === 'coverage.bound') {
  await ledger.recordCoverage(event.data.object)
}

Model

Confidential fields

Fields prefixed with enc: are sealed handles produced by the SDK on your side before they reach the API. The Policy and Premium engines compute directly on the sealed values (FHE via Fhenix CoFHE) and never decrypt them — on-chain or by Prova. Derived outcomes like premium_bps and covered_pct are returned in plaintext; the inputs that produced them are not. This is what lets competing institutions operate on the same rail without exposing their book.

Ready to integrate? Sandbox credentials and an OpenAPI contract are issued during an integration workshop.

Request demo

Evaluate Prova for an institutional trade-credit pilot.

We will walk through the rail, deployment status, the integration model, and what must be true before a production-capital launch.