PayeeProof
Integration quickstart
Minimal docs · modern risk control

Add a pre-send control call in 5–10 minutes.

One endpoint. One API key. One clear control answer before funds move. This page is intentionally small: one quickstart request, two working code examples, and three sample responses. The primary operator outcomes are SAFE, BLOCK, REVERIFY, and TEST FIRST; UNAVAILABLE is a retry or manual-review state, not a green light.

Base URL
https://payeeproof-api.onrender.com
Auth
X-API-Key: YOUR_API_KEY
Main endpoint
POST /api/preflight-check
What you get back
verdict, reason_code, next_action, confidence_score, risk_level, AI risk context, proof
POST /api/preflight-check

Request:
- expected.network
- expected.asset
- expected.address
- provided.network
- provided.asset
- provided.address

Response:
- SAFE
- BLOCK
- TEST FIRST
- REVERIFY
- UNAVAILABLE
Direct API access requires an API key. The public website demo is separate from direct integration. Public verdict language stays simple: SAFE, BLOCK, REVERIFY, and TEST FIRST. UNAVAILABLE is the system fallback.
What to send

Use the approved route as expected and the submitted route as provided.

Required fields

expected.network / provided.networkLower friction if you normalize chain names before the request.
expected.asset / provided.assetUse a stable symbol such as USDC or USDT.
expected.address / provided.addressThese are the most important fields for a first risk-control integration.
memoOptional. Include it for memo or tag based destinations.
contextOptional but useful for your own reference_id and policy_profile.

Fast mental model

SAFEThe route matches and looks operationally normal.
BLOCKStop. Something is clearly wrong or too risky for release.
TEST FIRSTThe route may be valid, but it behaves like infrastructure or an app.
REVERIFYPause and confirm memo, venue, or destination details.
UNAVAILABLERetry or route to manual review because live lookup did not complete cleanly.
1. First successful call

Start with cURL.

curl -X POST "https://payeeproof-api.onrender.com/api/preflight-check" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -d '{
    "expected": {
      "network": "ethereum",
      "asset": "USDC",
      "address": "0x59d779BED4dB1E734D3fDa3172d45bc3063eCD69",
      "memo": null
    },
    "provided": {
      "network": "ethereum",
      "asset": "USDC",
      "address": "0x59d779BED4dB1E734D3fDa3172d45bc3063eCD69",
      "memo": null
    },
    "context": {
      "reference_id": "payout_102948",
      "flow_type": "payout_approval",
      "policy_profile": "payout_strict"
    }
  }'
If you only need a first proof-of-life integration, this request is enough. Dynamic fields such as trace_id, record_id, and checked_at change on every call.
2. Working examples

Use a ready file, not guesswork.

Node.js

No dependency version for Node 18+

Uses built-in fetch, reads PAYEEPROOF_API_KEY from env, prints verdict + reason + next step.

Python

Simple requests example

Reads PAYEEPROOF_API_KEY from env, sends one request, prints a compact risk-control summary, and exits with error details if the call fails.

3. Sample responses

These three shapes are enough for a practical first risk-control integration.

SAFE

Matching network, asset, and address. Destination looks like a normal wallet flow.

BLOCK

Mismatch or invalid route. Do not send until the instruction is corrected.

TEST FIRST

Route may be valid, but it behaves like infrastructure or an app rather than a plain wallet, so the safest action is to test small or reverify.

SAFE response
{
  "ok": true,
  "service": "preflight-check",
  "version": "2.x",
  "trace_id": "req_example_safe_01",
  "checked_at": "2026-03-31T10:12:08Z",
  "chain": "ethereum",
  "policy_profile": "payout_strict",
  "status": "verified",
  "verdict": "SAFE",
  "reason_code": "OK",
  "next_action": "SAFE_TO_PROCEED",
  "next_action_label": "Proceed with the payment",
  "confidence": "High",
  "confidence_score": 92,
  "risk_level": "low",
  "summary": "Core details match and the destination looks like a personal wallet.",
  "why_this_verdict": "Network, asset, address, and memo or tag checks matched cleanly, and the destination looks like a normal wallet rather than infrastructure.",
  "ai_risk_context": {
    "pills": ["Human verification preserved", "Low route ambiguity"],
    "summary": "The submitted payout route is suitable for normal approval in an AI-assisted operations workflow."
  },
  "risk_flags": [],
  "checks": {
    "network_match": true,
    "asset_match": true,
    "address_match": true,
    "memo_match": true,
    "expected_address_valid": true,
    "provided_address_valid": true,
    "expected_network_supported": true,
    "provided_network_supported": true,
    "expected_asset_supported": true,
    "provided_asset_supported": true
  },
  "proof": {
    "checked_at": "2026-03-31T10:12:08Z",
    "chain": "ethereum",
    "trace_id": "req_example_safe_01",
    "verdict": "SAFE",
    "confidence": "High",
    "reason_code": "OK",
    "next_action": "SAFE_TO_PROCEED",
    "next_action_label": "Proceed with the payment",
    "policy_profile": "payout_strict"
  },
  "record_id": "ppf_demo_safe_01",
  "history_url": "/api/verification-records/ppf_demo_safe_01"
}
BLOCK response
{
  "ok": true,
  "service": "preflight-check",
  "version": "2.x",
  "trace_id": "req_example_block_01",
  "checked_at": "2026-03-31T10:14:08Z",
  "chain": "polygon",
  "policy_profile": "payout_strict",
  "status": "blocked",
  "verdict": "BLOCK",
  "reason_code": "NETWORK_MISMATCH",
  "next_action": "BLOCK_AND_REVERIFY",
  "next_action_label": "Block and re-verify the destination",
  "confidence": "High",
  "confidence_score": 96,
  "risk_level": "high",
  "summary": "The submitted payout details do not match the approved instructions.",
  "why_this_verdict": "The submitted destination is on a different chain than the approved request. This is the classic wrong-network mistake.",
  "ai_risk_context": {
    "pills": ["Fast execution risk", "Human re-check required"],
    "summary": "Do not let an automated or AI-assisted payout workflow release funds until the route is corrected."
  },
  "risk_flags": ["NETWORK_MISMATCH"],
  "checks": {
    "network_match": false,
    "asset_match": true,
    "address_match": true,
    "memo_match": true,
    "expected_address_valid": true,
    "provided_address_valid": true,
    "expected_network_supported": true,
    "provided_network_supported": true,
    "expected_asset_supported": true,
    "provided_asset_supported": true
  },
  "proof": {
    "checked_at": "2026-03-31T10:14:08Z",
    "chain": "polygon",
    "trace_id": "req_example_block_01",
    "verdict": "BLOCK",
    "confidence": "High",
    "reason_code": "NETWORK_MISMATCH",
    "next_action": "BLOCK_AND_REVERIFY",
    "next_action_label": "Block and re-verify the destination",
    "policy_profile": "payout_strict"
  },
  "record_id": "ppf_demo_block_01",
  "history_url": "/api/verification-records/ppf_demo_block_01"
}
TEST FIRST response
{
  "ok": true,
  "service": "preflight-check",
  "version": "2.x",
  "trace_id": "req_example_test_01",
  "checked_at": "2026-03-31T10:16:08Z",
  "chain": "ethereum",
  "policy_profile": "payout_strict",
  "status": "review_required",
  "verdict": "TEST FIRST",
  "reason_code": "DESTINATION_IS_CONTRACT_OR_APP",
  "next_action": "TEST_FIRST",
  "next_action_label": "Send a small test first",
  "confidence": "Medium",
  "confidence_score": 68,
  "risk_level": "medium",
  "summary": "The details match, but the destination looks like a contract or app.",
  "why_this_verdict": "Contract destinations can accept funds differently from a personal wallet. A small test first reduces irreversible mistakes.",
  "ai_risk_context": {
    "pills": ["Destination ambiguity", "Small test recommended"],
    "summary": "The route should not be treated as a normal wallet approval inside a modern finance workflow."
  },
  "risk_flags": ["DESTINATION_IS_CONTRACT_OR_APP"],
  "checks": {
    "network_match": true,
    "asset_match": true,
    "address_match": true,
    "memo_match": true,
    "expected_address_valid": true,
    "provided_address_valid": true,
    "expected_network_supported": true,
    "provided_network_supported": true,
    "expected_asset_supported": true,
    "provided_asset_supported": true
  },
  "proof": {
    "checked_at": "2026-03-31T10:16:08Z",
    "chain": "ethereum",
    "trace_id": "req_example_test_01",
    "verdict": "TEST FIRST",
    "confidence": "Medium",
    "reason_code": "DESTINATION_IS_CONTRACT_OR_APP",
    "next_action": "TEST_FIRST",
    "next_action_label": "Send a small test first",
    "policy_profile": "payout_strict"
  },
  "record_id": "ppf_demo_test_01",
  "history_url": "/api/verification-records/ppf_demo_test_01"
}
Common errors

Handle the three that matter first.

401 — missing or invalid API key
{
  "ok": false,
  "error": "API key required for direct API access."
}
400 — missing required fields
{
  "ok": false,
  "error": "Both expected.network and provided.network are required."
}
429 — rate limited
{
  "ok": false,
  "error": "RATE_LIMITED",
  "message": "Too many requests. Retry later."
}
Minimal rule: treat non-200 as a hard failure, log the response body, and do not auto-approve a payout on an error path.
Contract and next step

Keep the docs light. Get to the first real call fast.

This page is intentionally enough, not endless. Review the public OpenAPI contract if you need the schema, then move straight to a real call or a pilot conversation.