Skip to content

Quickstart

Getting started

Quickstart

Record a settled x402 payment, fetch fiscal402.receipt, and verify it. HTTP first — packages are not on npm.

Record a settled x402 payment

You already settled. Fiscal402 observes the evidence and returns a signed receipt. It does not generate HTTP 402, authorize the transfer, or hold funds. A transaction hash alone is not enough.

  1. SETTLED x402 exact
  2. ↓
  3. POST /settlements
  4. ↓
  5. EU VAT + UBL + fiscal402.receipt
  6. ↓
  7. verify locally

1. Configure the key

Server only. Header X-Fiscal402-Key. Environment variable FISCAL402_MERCHANT_KEY. Merchant keys use the f402m_ prefix. Never ship the key to a browser. Seller establishment (Acme BV, NL) lives on the merchant account, not in this body.

.env

FISCAL402_MERCHANT_KEY=f402m_your_key_here
FISCAL402_ORIGIN=https://api.fiscal402.com

2. POST the settlement

Example: Acme BV sells digital inference to Buyer GmbH in DE. Amounts are decimal strings — never 0.1 as a float. consumerCountry is attested buyer location.

record.ts

const origin = process.env.FISCAL402_ORIGIN ?? "https://api.fiscal402.com";

const response = await fetch(`${origin}/settlements`, {
  method: "POST",
  headers: {
    "content-type": "application/json",
    "X-Fiscal402-Key": process.env.FISCAL402_MERCHANT_KEY!,
    "Idempotency-Key": "acme-nl-de-1",
  },
  body: JSON.stringify({
    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",
    consumerName: "Buyer GmbH",
  }),
});

if (!response.ok) {
  const body = await response.json();
  throw body.error ?? new Error(`Fiscal402 ${response.status}`);
}

const event = await response.json();
// event.id → GET /v1/receipts/:id

shell

export FISCAL402_ORIGIN="https://api.fiscal402.com"
export FISCAL402_MERCHANT_KEY="f402m_your_key_here"

curl -sS -X POST "$FISCAL402_ORIGIN/settlements" \
  -H "Content-Type: application/json" \
  -H "X-Fiscal402-Key: $FISCAL402_MERCHANT_KEY" \
  -H "Idempotency-Key: acme-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",
    "consumerName": "Buyer GmbH"
  }'

3. Read the result

201 means the event was recorded. custody is always none. PENDING_MANUAL_REVIEW is a result — Fiscal402 did not invent a VAT rate.

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"
  }
}

4. Fetch and verify the receipt

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.json

verify.ts

import { verifyReceipt } from "./verify"; // source only — not on npm

const report = await verifyReceipt({
  receipt,
  jwks,
  ubl,
});

if (report.result !== "VERIFIED") {
  throw new Error(report.code);
}
// VERIFIED = cryptographic integrity. Not tax-authority approval.

VERIFIED means cryptographic integrity under Fiscal402 rules. It does not mean tax-authority approval, a VAT return, or legal advice.

What just happened

x402 moved USDC. Fiscal402 stored settlement evidence, classified an EU OSS B2C pattern for a DE consumer, bound UBL 2.1 bytes, and signed fiscal402.receipt/1.0.0 with Ed25519. You can verify that object later with JWKS and the exact invoice bytes — without this API being up.

OSS is the EU One-Stop-Shop: destination VAT for intra-EU B2C digital services. Reverse charge is intra-EU B2B when a VAT ID is accepted. VIES is the EU VAT-number check. Place of supply is the tax jurisdiction, not the chain.

Idempotency

Send Idempotency-Key per settlement. The same key plus the same body returns the same fiscal event. The same key plus a different body is IDEMPOTENCY_CONFLICT (409). Do not retry 4xx validation blindly.

B2B with a VAT number

b2b.json

{
  "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",
  "consumerVatNumber": "DE123456789",
  "consumerName": "Buyer GmbH"
}
// Reverse charge only when the VAT ID is accepted. Unconfirmed IDs → PENDING_MANUAL_REVIEW.

review.ts

if (event.reviewStatus === "PENDING_MANUAL_REVIEW") {
  // No rate was invented. Complete attested buyer country / VAT ID and retry.
}
if (!response.ok && body.error?.code === "UNSUPPORTED_JURISDICTION") {
  // Corridor is not a production engine. Do not treat as 0% VAT.
}

Source client (not on npm)

Do not npm install @fiscal402/node. When you copy the source client, the typed surface is recordSettlement over POST /settlements.

source.ts

import { Fiscal402 } from "@fiscal402/node"; // source only — not on npm

const fiscal = new Fiscal402({
  apiKey: process.env.FISCAL402_MERCHANT_KEY!,
  origin: process.env.FISCAL402_ORIGIN ?? "https://api.fiscal402.com",
});

const result = await fiscal.recordSettlement({
  amountUsdc: "1.00",
  txHash: "0xYOUR_SETTLED_TX",
  timestamp: "2026-09-10T12:00:00.000Z",
  payerWallet: "0xPAYER",
  receiverWallet: "0xPAY_TO",
  network: "eip155:1",
  buyer: { country: "DE", legalName: "Buyer GmbH" },
  supply: { kind: "digital", description: "Inference units" },
  idempotencyKey: "acme-nl-de-1",
});

console.log(result.id, result.reviewStatus);

Optional sandbox classify

POST /v1/compliance/evaluate classifies without writing a production settlement. Seller country may be anywhere; the buyer must be an attested EU customer for this EU VAT preview. 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"
}