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.
| Resource | Purpose |
|---|---|
| POST /v1/oauth/token | Exchange client credentials for an access token. |
| POST /v1/business-profiles | Create the institution or counterparty profile (KYB). |
| POST /v1/escrows | Open an invoice-backed escrow. |
| POST /v1/coverage/quotes | Quote coverage against an invoice. |
| POST /v1/coverage | Bind coverage from a quote. |
| POST /v1/claims | Open a protracted-default claim. |
| GET /v1/transactions | List premium, settlement, and fee movements. |
| GET /v1/pool/status | Read 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
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
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
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
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
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
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.
| Environment | Base URL | Access |
|---|---|---|
| Sandbox | api.sandbox.getprova.trade | Available for integration workshops (Arbitrum Sepolia) |
| Production | api.getprova.trade | Enabled 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.
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"{
"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.
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…"
}
}'{
"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.
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.
{
"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"
}
}| Status | Type | Meaning |
|---|---|---|
| 400 | invalid_request_error | The request was malformed or a parameter was out of range. |
| 401 | authentication_error | The access token is missing, expired, or invalid. |
| 403 | permission_error | The token is valid but lacks the scope for this resource. |
| 404 | not_found | The requested resource does not exist. |
| 409 | idempotency_conflict | An Idempotency-Key was reused with a different payload. |
| 422 | unprocessable_entity | The request was valid but could not be fulfilled. |
| 429 | rate_limit_error | Too many requests. Retry after the Retry-After interval. |
| 5xx | api_error | An 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.
curl "https://api.sandbox.getprova.trade/v1/transactions?limit=20" \
-H "Authorization: Bearer $ACCESS_TOKEN"{
"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.
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"
}
}
}| Event | Fires when |
|---|---|
| escrow.created | An invoice-backed escrow was opened. |
| coverage.quoted | A coverage quote was produced. |
| coverage.bound | Coverage was bound against an invoice. |
| claim.opened | A protracted-default claim entered review. |
| claim.resolved | A claim was accepted or declined. |
| settlement.completed | A 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.
npm install @prova/nodeimport { 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 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.
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.