Happy path
- REQUEST
- ↓
- x402 payment (HTTP 402 + settle)
- ↓
- SETTLED
- ↓
- POST /settlements
- ↓
- EU VAT determination
- ↓
- UBL + ledger
- ↓
- fiscal402.receipt
x402 payment happens first. Fiscal402 observes evidence afterward. It does not generate the 402, authorize the transfer, or control funds.
1. Ingest a settled transfer
Replace the placeholders. https://api.fiscal402.com is the operator origin. $FISCAL402_API_KEY is issued to the merchant. txHash must already exist on-chain.
http
POST https://api.fiscal402.com/settlements
Content-Type: application/json
X-Fiscal402-Key: $FISCAL402_API_KEY
{
"amountUsdc": "1.00",
"txHash": "0xYOUR_SETTLED_TX",
"timestamp": "2026-09-10T12:00:00.000Z",
"payerWallet": "0xPAYER",
"receiverWallet": "0xPAY_TO",
"network": "eip155:1",
"asset": "USDC",
"scheme": "exact",
"consumerCountry": "DE"
}shell
export FISCAL402_ORIGIN="https://api.fiscal402.com"
export FISCAL402_API_KEY="$FISCAL402_API_KEY"
curl -sS -X POST "$FISCAL402_ORIGIN/settlements" \
-H "Content-Type: application/json" \
-H "X-Fiscal402-Key: $FISCAL402_API_KEY" \
-H "Idempotency-Key: demo-nl-de-1" \
-d '{
"amountUsdc": "1.00",
"txHash": "0xYOUR_SETTLED_TX",
"timestamp": "2026-09-10T12:00:00.000Z",
"payerWallet": "0xPAYER",
"receiverWallet": "0xPAY_TO",
"network": "eip155:1",
"asset": "USDC",
"scheme": "exact",
"consumerCountry": "DE"
}'2. Result
A successful ingest returns 201 with a public fiscal record. custody is always none. Production ids keep the x402- prefix.
201.json
{
"id": "x402-4f9c1670",
"custody": "none",
"reviewStatus": "PROCESSED",
"classification": {
"regime": "OSS_B2C",
"taxCategoryCode": "S",
"ratePercent": 19,
"taxingCountry": "DE"
},
"fx": {
"pair": "USDC/EUR",
"netEur": "0.86",
"vatEur": "0.16"
}
}3. Receipt, UBL, JWKS
http
GET https://api.fiscal402.com/v1/receipts/rcpt_x402-4f9c1670
GET https://api.fiscal402.com/settlements/x402-4f9c1670/ubl
GET https://api.fiscal402.com/.well-known/jwks.json4. Verify locally
- Confirm
specisfiscal402.receiptandspec_versionis1.0.0. - Drop
hashesandsignature. Canonicalize the rest withfiscal402.sorted-json/1. SHA-256 the UTF-8 JSON. Compare tohashes.canonical_payload_sha256. - Select the JWKS key whose
kidmatchessignature.key_id. - Verify Ed25519 over the hex digest string, not the raw 32-byte hash.
- SHA-256 the exact UBL UTF-8 bytes. Compare to
artifacts.ubl_sha256.
verify-report.json
{
"verified": true,
"result": "VERIFIED",
"receipt_schema": "SUPPORTED",
"canonicalization": "fiscal402.sorted-json/1",
"canonical_payload": "MATCH",
"signing_key": "JWKS_MATCH",
"signature": "VALID",
"ubl_sha256": "MATCH",
"settlement_reference": "PRESENT",
"notes": [
"verified means Fiscal402 receipt integrity, not tax-authority acceptance."
]
}Optional sandbox classify
POST /v1/compliance/evaluate classifies without writing a production settlement. seller_country must be EU-27. Currency is USDC.
evaluate.http
POST https://api.fiscal402.com/v1/compliance/evaluate
Content-Type: application/json
{
"seller_country": "NL",
"buyer_country": "DE",
"buyer_type": "B2C",
"service_type": "DIGITAL_SERVICE",
"amount": "1.00",
"currency": "USDC",
"chain": "eip155:1",
"settled_at": "2026-09-10T12:00:00.000Z"
}