MirrorProof API
Generate and verify zero-knowledge proofs about financial data. Connect bank accounts and crypto exchanges via Plaid, attest balances, and create shareable proof links — all without exposing actual numbers.
Authentication
Protected endpoints require a Clerk JWT in the Authorization header.
Authorization: Bearer <clerk_jwt_token>
Public endpoints (proof lookup, verification, health) require no authentication.
Errors
All errors return a JSON object with an error field.
{
"error": "Description of what went wrong"
}
| Status | Meaning |
|---|---|
400 | Bad request — missing fields or invalid proof |
401 | Not authenticated — missing or invalid JWT |
404 | Resource not found |
500 | Server error |
Creates a Plaid Link token for connecting a bank or exchange account.
Request Body
{
"account_type": "bank" | "crypto" // optional, defaults to "bank"
}
Response
{
"link_token": "link-sandbox-xxxxxxxx"
}
Exchanges a Plaid public token for an access token after the user completes Plaid Link. Creates or updates the user record with institution info and masked email.
Request Body
{
"public_token": "public-sandbox-xxxxxxxx",
"metadata": {
"institution": {
"name": "Chase",
"institution_id": "ins_3"
}
}
}
Response
{
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"institution_name": "Chase",
"account_type": "bank",
"accounts": [
{
"id": "abc123",
"name": "Checking",
"type": "depository",
"subtype": "checking",
"mask": "1234"
}
]
}
Fetches current account balances from Plaid and returns attested data for client-side proof generation. Balances are not stored on the server.
Request Body
Empty.
Response
{
"accounts": [
{
"account_id": "abc123",
"name": "Checking",
"type": "depository",
"subtype": "checking",
"mask": "1234",
"currency": "USD",
"current_balance": 15250.50,
"available_balance": 15100.00
}
],
"timestamp": 1711497600,
"attestation_hash": "a1b2c3d4...",
"source": "plaid"
}
Fetches investment and crypto holdings from Plaid with per-security breakdowns and per-account totals.
Request Body
Empty.
Response
{
"accounts": [
{
"account_id": "xyz789",
"name": "Coinbase",
"type": "investment",
"current_balance": 42500.00,
...
}
],
"holdings": [
{
"ticker": "BTC",
"name": "Bitcoin",
"quantity": 0.5,
"price": 67000.00,
"value": 33500.00,
"is_crypto": true,
...
}
],
"timestamp": 1711497600,
"attestation_hash": "e5f6g7h8...",
"source": "plaid_investments"
}
Submits a zero-knowledge proof for verification. The proof is verified server-side using snarkjs, stored, and a shareable link is generated.
Request Body
{
"proof": { // Groth16 proof object (pi_a, pi_b, pi_c, protocol, curve) },
"publicSignals": ["10000000000", "...", ...],
"circuit": "balance-threshold",
"attestation_hash": "a1b2c3d4..." // optional
}
Response
{
"proof_id": "550e8400-...",
"circuit": "balance-threshold",
"verified": true,
"share_token": "aBcDeFgH",
"share_url": "https://app.mirrorzkp.com/verify/aBcDeFgH",
"created_at": "2026-03-26T12:00:00.000Z"
}
Lists all proofs belonging to the authenticated user, newest first. Includes computed freshness for each proof.
Response
{
"proofs": [
{
"id": "550e8400-...",
"circuit": "balance-threshold",
"public_inputs": { ... },
"verified": true,
"institution_name": "Chase",
"share_token": "aBcDeFgH",
"expires_at": "2026-03-27T12:00:00.000Z",
"created_at": "2026-03-26T12:00:00.000Z",
"freshness": { ... } // see Freshness Object
}
]
}
Returns details for a single proof by its UUID.
Response
{
"id": "550e8400-...",
"circuit": "balance-threshold",
"public_inputs": { ... },
"verified": true,
"institution_name": "Chase",
"source_type": "bank",
"freshness": { ... },
"created_at": "2026-03-26T12:00:00.000Z"
}
Re-verifies a proof's cryptographic validity and checks freshness. Optionally override the freshness window.
Request Body
{
"max_age_hours": 48 // optional, overrides default window
}
Response
{
"valid": true,
"circuit": "balance-threshold",
"public_inputs": { ... },
"freshness": { ... }
}
Looks up all proofs associated with a wallet address. Case-insensitive. Designed for DeFi protocol integrations — any protocol can check if a wallet has valid proofs without the user being present.
Response
{
"proofs": [
{
"id": "550e8400-...",
"circuit": "balance-threshold",
"public_inputs": { ... },
"verified": true,
"share_token": "aBcDeFgH",
"created_at": "2026-03-26T12:00:00.000Z"
}
]
}
Ensures a database user record exists for the authenticated Clerk user. Called automatically by the frontend after sign-in. Safe to call multiple times.
Response
{
"ok": true
}
Health check. Returns API status and available circuits.
Response
{
"status": "ok",
"version": "1.0.0",
"circuits": ["balance-threshold"]
}
Freshness Object
Included in proof responses to indicate how current the underlying attestation is.
{
"attestation_time": "2026-03-26T12:00:00.000Z",
"proof_age_seconds": 3600,
"proof_age_human": "1 hours ago",
"is_fresh": true,
"freshness_window_hours": 24,
"warning": "This proof is 3 days ago..." // only if stale
}
Default freshness windows
| Circuit | Window |
|---|---|
balance-threshold | 24 hours |
average-balance | 7 days |
account-age | Permanent |
Public Inputs
The public_inputs field is parsed from the circuit's public signals. The shape depends on the circuit type.
balance-threshold
{
"threshold": "10000000000", // scaled by 1,000,000 ($10,000)
"attestation_commitment": "12345...", // Poseidon hash
"source_id": "1", // 1 = Plaid
"timestamp": "1711497600", // Unix seconds
"account_hash": "67890..." // Poseidon(account_uuid)
}
To convert a threshold to dollars: divide by 1,000,000.