PayeeProof
Integration quickstart
Minimal docs · pre-send first

Integrate PayeeProof in 5–10 minutes.

One endpoint. One API key. One clear 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, 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 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.
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 summary, and exits with error details if the call fails.

3. Sample responses

These three shapes are enough for a practical first 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.

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",
  "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.",
  "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",
  "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.",
  "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",
  "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.",
  "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.