ReferenceFacilitator API

Facilitator API Reference

The T402 Facilitator API provides payment verification and on-chain settlement services. The public facilitator is available at https://facilitator.t402.io.

Base URL

EnvironmentURLAPI Key
Productionhttps://facilitator.t402.ioRequired (X-API-Key)
Sandboxhttps://sandbox.t402.ioNot needed

The Sandbox supports 7 testnets with magic test addresses for deterministic testing. Try the playground to explore the API interactively.

Authentication

The production facilitator requires an API key for /verify and /settle endpoints. Get a free key at facilitator.t402.io/register.

Pass the key via header:

Authorization: Bearer t402_sk_...

Or via X-API-Key header. Free tier includes 1,000 transactions/month at 0% fee.

TierQuotaRPMFee
Free1,000 tx/month100%
Builder100K tx/month1000.1%
Scale1M tx/month1,0000.08%
EnterpriseUnlimited10,000Custom

Endpoints

GET /health

Health check endpoint for liveness probes.

Response

{
  "status": "ok"
}

GET /ready

Readiness check endpoint. Returns 200 when the service is ready to accept requests.

Response

{
  "status": "ready",
  "checks": {
    "redis": "ok",
    "rpc": "ok"
  }
}

GET /metrics

Prometheus metrics endpoint for monitoring.

Response: Prometheus text format


GET /supported

Returns the supported networks, schemes, and signers.

Response

{
  "kinds": [
    {
      "t402Version": 2,
      "scheme": "exact",
      "network": "eip155:8453"
    },
    {
      "t402Version": 2,
      "scheme": "exact",
      "network": "ton:mainnet"
    }
  ],
  "extensions": [],
  "signers": {
    "eip155:*": ["0xC88f67e776f16DcFBf42e6bDda1B82604448899B"],
    "ton:*": ["EQDjv9CUEJ__D_3-3J4trQtqVklMBiNoGVSf3Fu6AaDGkEUe"]
  }
}

Response Fields

FieldTypeDescription
kindsarrayList of supported scheme/network combinations
kinds[].t402VersionnumberProtocol version supported (2 for v2)
kinds[].schemestringPayment scheme (e.g., exact, upto)
kinds[].networkstringCAIP-2 network identifier
extensionsarrayExtension identifiers the facilitator has implemented
signersobjectMap of CAIP-2 patterns (e.g., eip155:*) to signer addresses

POST /verify

Verify a signed payment authorization without executing settlement.

Request Body

{
  "paymentPayload": {
    "t402Version": 2,
    "resource": {
      "url": "https://api.example.com/premium",
      "description": "Premium API access",
      "mimeType": "application/json"
    },
    "accepted": {
      "scheme": "exact",
      "network": "eip155:8453",
      "amount": "1000000",
      "asset": "0x6C96dE32CEa08842dcc4058c14d3aaAD7Fa41dee",
      "payTo": "0xRecipientAddress",
      "maxTimeoutSeconds": 600,
      "extra": {
        "name": "USDT0",
        "version": "2"
      }
    },
    "payload": {
      "signature": "0x...",
      "authorization": {
        "from": "0xPayerAddress",
        "to": "0xRecipientAddress",
        "value": "1000000",
        "validAfter": "0",
        "validBefore": "1706745600",
        "nonce": "0x..."
      }
    }
  },
  "paymentRequirements": {
    "scheme": "exact",
    "network": "eip155:8453",
    "amount": "1000000",
    "asset": "0x6C96dE32CEa08842dcc4058c14d3aaAD7Fa41dee",
    "payTo": "0xRecipientAddress",
    "maxTimeoutSeconds": 600,
    "extra": {
      "name": "USDT0",
      "version": "2"
    }
  }
}

Response (Success)

{
  "isValid": true,
  "payer": "0xPayerAddress"
}

Response (Invalid)

{
  "isValid": false,
  "invalidReason": "Signature verification failed",
  "payer": "0xPayerAddress"
}

Response Fields

FieldTypeDescription
isValidbooleanWhether the payment authorization is valid
invalidReasonstringReason for invalidity (omitted if valid)
payerstringAddress of the payer’s wallet

POST /settle

Execute on-chain settlement for a verified payment.

Headers

HeaderRequiredDescription
Idempotency-KeyRecommendedUnique key (max 64 chars, alphanumeric/hyphens) to prevent duplicate settlements

Request Body

{
  "paymentPayload": {
    "t402Version": 2,
    "resource": {
      "url": "https://api.example.com/premium",
      "description": "Premium API access",
      "mimeType": "application/json"
    },
    "accepted": {
      "scheme": "exact",
      "network": "eip155:8453",
      "amount": "1000000",
      "asset": "0x6C96dE32CEa08842dcc4058c14d3aaAD7Fa41dee",
      "payTo": "0xRecipientAddress",
      "maxTimeoutSeconds": 600,
      "extra": {
        "name": "USDT0",
        "version": "2"
      }
    },
    "payload": {
      "signature": "0x...",
      "authorization": {
        "from": "0xPayerAddress",
        "to": "0xRecipientAddress",
        "value": "1000000",
        "validAfter": "0",
        "validBefore": "1706745600",
        "nonce": "0x..."
      }
    }
  },
  "paymentRequirements": {
    "scheme": "exact",
    "network": "eip155:8453",
    "amount": "1000000",
    "asset": "0x6C96dE32CEa08842dcc4058c14d3aaAD7Fa41dee",
    "payTo": "0xRecipientAddress",
    "maxTimeoutSeconds": 600,
    "extra": {
      "name": "USDT0",
      "version": "2"
    }
  }
}

Response (Success)

{
  "success": true,
  "transaction": "0x...",
  "network": "eip155:8453",
  "payer": "0xPayerAddress"
}

Response (Failure)

{
  "success": false,
  "errorReason": "Insufficient balance",
  "transaction": "",
  "network": "eip155:8453",
  "payer": "0xPayerAddress"
}

Response Fields

FieldTypeDescription
successbooleanWhether settlement was successful
transactionstringBlockchain transaction hash (empty string if failed)
networkstringNetwork where settlement occurred
payerstringAddress of the payer’s wallet
errorReasonstringReason for failure (omitted if successful)
⚠️

Idempotency: Always use the Idempotency-Key header for settlement requests to prevent double payments in case of network errors or retries.


GET /info

Returns API version, feature flags, and all available endpoints.

Response: JSON with name, version, description, endpoints[], features{}.


GET /tiers

List all available pricing tiers and their configurations.

Response

{
  "tiers": {
    "free": { "name": "Free", "monthlyQuota": 1000, "rpmLimit": 10, "feeRate": 0, "priceCents": 0 },
    "builder": { "name": "Builder", "monthlyQuota": 100000, "rpmLimit": 100, "feeRate": 0.001, "priceCents": 0 },
    "scale": { "name": "Scale", "monthlyQuota": 1000000, "rpmLimit": 1000, "feeRate": 0.0008, "priceCents": 9900 },
    "enterprise": { "name": "Enterprise", "monthlyQuota": -1, "rpmLimit": 10000, "feeRate": 0.0005, "priceCents": 0 }
  }
}

Registration & Key Management

POST /register

Create a new API key. Idempotent per email + project name.

Request Body

{ "email": "you@company.com", "projectName": "My App" }

Response (201 Created)

{
  "apiKey": "t402_sk_...",
  "projectName": "My App",
  "quota": { "limit": 1000, "period": "monthly", "used": 0, "tier": "free", "feeRate": 0, "resetsAt": "2026-05-01T00:00:00Z" },
  "isNew": true
}

Rate limited: 5 registrations per IP per hour.


POST /lookup

Recover an existing API key by email. Rate limited separately from registration.

Request Body

{ "email": "you@company.com" }

Dashboard API

All dashboard endpoints require Authorization: Bearer t402_sk_... header.

GET /dashboard/info

Get key info, tier, quota, and settings. Does not increment quota.

Response

{
  "tier": "free",
  "config": { "name": "Free", "monthlyQuota": 1000, "rpmLimit": 10, "feeRate": 0 },
  "quota": { "limit": 1000, "used": 42, "tier": "free", "feeRate": 0, "resetsAt": "2026-05-01T00:00:00Z" },
  "email": "you@company.com",
  "project": "My App",
  "status": "active",
  "createdAt": "2026-04-07T06:28:26Z",
  "webhookUrl": "",
  "allowedIPs": null,
  "allowedRef": null
}

GET /dashboard/keys

List all API keys for the authenticated user’s email.

Response

{
  "keys": [
    { "apiKey": "t402_sk_...", "project": "My App", "tier": "free", "status": "active", "createdAt": "...", "current": true }
  ],
  "email": "you@company.com"
}

GET /dashboard/usage

Daily usage data for the last 7 days (for charts).

Response

{
  "days": 7,
  "usage": [
    { "date": "2026-04-01", "count": 0 },
    { "date": "2026-04-02", "count": 15 }
  ]
}

POST /dashboard/rotate

Regenerate API key. The old key is immediately invalidated. All settings (webhook, restrictions, tier) are preserved.

Response

{ "apiKey": "t402_sk_NEW...", "project": "My App", "message": "Key rotated successfully. Old key is now invalid." }

POST /dashboard/webhook

Set a webhook URL for settlement notifications. Must use HTTPS. Send empty string to clear.

Request Body

{ "webhookUrl": "https://your-server.com/t402-webhook" }

POST /dashboard/webhook/test

Send a test payload to the configured webhook URL.

Response

{ "success": true, "statusCode": 200, "message": "Webhook responded with 200 OK" }

POST /dashboard/restrictions

Set IP and referrer domain restrictions. Empty arrays allow all.

Request Body

{ "allowedIPs": ["203.0.113.1"], "allowedRef": ["myapp.com"] }

Credit Scoring API

GET /v1/credit/score?wallet=0x…

Get credit score (0-1000) for a wallet based on payment history.

Response

{
  "wallet": "0x...",
  "score": 750,
  "breakdown": { "volumeScore": 200, "frequencyScore": 180, "reliabilityScore": 250, "ageScore": 120 },
  "stats": { "paymentCount": 150, "successRate": 0.98, "totalVolume": "5000000000", "accountAgeDays": 90 }
}

POST /v1/credit/refresh

Force a fresh score computation. Accepts query param ?wallet=0x... or JSON body {"wallet":"0x..."}.


GET /v1/credit/top?limit=20

Leaderboard of top wallets by credit score.


Stats API

GET /stats/keys

Public count of registered API keys.

{ "totalKeys": 27 }

GET /stats/requests

Aggregate request statistics (requires database).

{ "totalRequests": 235000, "successfulRequests": 234300, "failedRequests": 700, "avgDurationMs": 5.1 }

GET /stats/settlements

Settlement status counts.

{ "confirmed": 0, "failed": 32, "pending": 0 }

Error Responses

All endpoints return structured error responses:

{
  "code": "INVALID_REQUEST",
  "message": "Invalid request body"
}

Error Codes

CodeHTTP StatusDescription
INVALID_REQUEST400Malformed request body
INVALID_IDEMPOTENCY_KEY400Invalid idempotency key format
VERIFICATION_FAILED500Payment verification failed
SETTLEMENT_FAILED500On-chain settlement failed
REQUEST_IN_PROGRESS409Duplicate request still processing
PAYLOAD_MISMATCH409Payload doesn’t match previous request with same idempotency key
PREVIOUS_REQUEST_FAILED409Previous request with this key failed
IDEMPOTENCY_UNAVAILABLE503Idempotency service unavailable

Rate Limiting

Global limit: 1,000 requests/minute per IP (anonymous) or per API key (authenticated).

Endpoint-specific limits:

EndpointLimitReason
POST /settle100/minOn-chain transactions
POST /register30/minRegistration (also 5/hour per IP)
POST /lookup30/minKey recovery (also 5/hour per IP)
POST /dashboard/rotate5/minKey rotation (destructive)
POST /dashboard/webhook/test5/minWebhook test
GET /dashboard/info120/minDashboard reads
POST /v1/intent/execute100/minIntent execution

Response headers (on authenticated requests):

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 978
X-RateLimit-Reset: 1712592000
X-RateLimit-Tier: free

Supported Networks

EVM Networks

NetworkChain IDCAIP-2Facilitator Address
Ethereum1eip155:10xC88f67e776f16DcFBf42e6bDda1B82604448899B
Base8453eip155:84530xC88f67e776f16DcFBf42e6bDda1B82604448899B
Arbitrum42161eip155:421610xC88f67e776f16DcFBf42e6bDda1B82604448899B
Optimism10eip155:100xC88f67e776f16DcFBf42e6bDda1B82604448899B
Ink57073eip155:570730xC88f67e776f16DcFBf42e6bDda1B82604448899B
Berachain80094eip155:800940xC88f67e776f16DcFBf42e6bDda1B82604448899B

Non-EVM Networks

NetworkCAIP-2Facilitator Address
Solanasolana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp8GGtWHRQ1wz5gDKE2KXZLktqzcfV1CBqSbeUZjA7hoWL
TONton:mainnetEQDjv9CUEJ__D_3-3J4trQtqVklMBiNoGVSf3Fu6AaDGkEUe
TRONtron:mainnetTT1MqNNj2k5qdGA6nrrCodW6oyHbbAreQ5
NEARnear:mainnetfacilitator.t402.near
Stacksstacks:1SP36B1B191JTQAZTRKKWRN7J0YHHM41W9P9P7EPR5
Cosmos (Noble)cosmos:noble-1noble1ejc2c2gvk46h7kyulx9fus85vdpq0zdjwkfav0
Aptosaptos:1Verification only (exact-direct)
Tezostezos:NetXdQprcVkpaWUVerification only (exact-direct)
Polkadotpolkadot:68d56f15f85d3136970ec16946040bc1Verification only (exact-direct)

Code Examples

# Check supported networks
curl https://facilitator.t402.io/supported
 
# Verify payment
curl -X POST https://facilitator.t402.io/verify \
  -H "Content-Type: application/json" \
  -d '{
    "paymentPayload": {...},
    "paymentRequirements": {...}
  }'
 
# Settle payment
curl -X POST https://facilitator.t402.io/settle \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: unique-key-123" \
  -d '{
    "paymentPayload": {...},
    "paymentRequirements": {...}
  }'

Self-Hosting

You can run your own facilitator for greater control and privacy. See the Deployment Guide for instructions.

# Docker
docker run -p 8080:8080 ghcr.io/t402-io/facilitator:latest
 
# Environment variables
export EVM_PRIVATE_KEY=0x...
export TON_MNEMONIC="word1 word2 ..."
export REDIS_URL=redis://localhost:6379