Skip to main content
Rail402 reads its configuration from environment variables once, at startup. Every value is validated: a missing credential, a malformed value or an unsafe mainnet setting stops the process with exit code 78 and a message naming the variable. Secrets are never echoed. An empty value is treated as unset, and booleans are the literal strings true or false.

Service

API keys are sent as Authorization: Bearer <key> or X-API-Key: <key>. Compute a key’s digest with echo -n "$KEY" | sha256sum | cut -d' ' -f1. The rate limit applies to every endpoint except /health, /ready and /metrics. A limited request gets HTTP 429 with a Retry-After header. Without TRUSTED_PROXY_HOPS, the client address is the TCP peer; behind a proxy, set it to the number of proxies so each real client gets its own limit. Metering. Every /verify and /settle that reaches the facilitator is counted per caller (key:<hash prefix> for API-key holders, public otherwise), per day, network, operation, outcome and asset, with the settled volume. Not metered: transport rejections (HTTP 400, 413, 415 and 429), invalid_network and unsupported_scheme refusals, requests refused with HTTP 401 because a required API key is missing or unknown, and requests the service answers with HTTP 500. Key holders read their own usage and accrued service fee at GET /usage. With Postgres, rate limits and metering are shared by every replica.

Per network

Variables are prefixed TESTNET_ or PUBNET_, for example TESTNET_RPC_URL. Only the networks listed in NETWORKS are read. The default asset is Circle USDC on each network: CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA on testnet and CCW67TSZV3SSS2HXMBQ5JFGCKJNXKZM7UQUWUZPUTHXSTZLEO7SJMI75 on pubnet, both with 7 decimals. INCLUSION_FEE_PERCENTILE is one of p50, p70, p80, p90, p95 or p99. Validation rules beyond the formats:
  • NETWORKS may not list a network twice, and each network needs its own sponsor account.
  • PUBNET_RPC_URL must use https, and PUBNET_REQUIRE_API_KEY must be set to true or false whenever pubnet is enabled: mainnet access control is always an explicit decision.
  • REQUIRE_API_KEY=true needs at least one digest in API_KEY_SHA256.
  • TIMEOUT_MIN_SECONDS may not exceed TIMEOUT_MAX_SECONDS, INCLUSION_FEE_STROOPS may not exceed MAX_TX_FEE_STROOPS, and INCLUSION_FEE_CAP_STROOPS must lie between the two.
  • ASSETS entries need a C… contract address, a symbol of 1 to 12 letters or digits, decimals of 0 to 38, and a minimum no larger than the maximum; no contract may be listed twice.
With embeddings on, the service refuses to start if the model files are missing or their SHA-256 hashes do not match the pinned manifest. pnpm models:fetch downloads and verifies them into .models/; the container image already contains them.

Accounts

The sponsor pays every settlement fee through a fee-bump transaction and the base reserve of every channel account. It never holds or sends payment funds. Fund it with XLM only. Channel accounts are the source accounts of settlement transactions, one per in-flight settlement, so concurrent settlements never compete for a sequence number. They are derived from the sponsor secret (HKDF-SHA256), hold a zero balance, and need no separate secret or backup.

Examples

A testnet instance with the bundled Postgres needs only:
A pubnet-only instance that requires API keys:
On pubnet, channel accounts are not created at startup: run channels provision first (see operations.md). The validation rules above are checked for pubnet at startup, but pubnet itself has not been exercised end to end. The hosted Rail402 service serves testnet only.