Skip to content

Configuration

The facilitator is configured via a YAML file (default: config.yaml in the working directory). Pass a custom path with the --config flag.

bash
go run cmd/main.go --config /etc/x402/config.yaml

A fully-annotated example is available at config.example.yaml.


server

yaml
server:
  host: "0.0.0.0"        # Bind address
  port: ":8080"           # Listen port (include the colon)
  environment: "production"  # development | staging | production | test
FieldRequiredDefaultDescription
hostYes-Network interface to bind. Use 0.0.0.0 to accept all interfaces.
portYes-Port including the colon prefix, e.g. ":8080".
environmentYes-Controls log verbosity and Gin's debug/release mode. One of development, staging, production, test.

database

PostgreSQL connection settings.

yaml
database:
  host: "localhost"
  port: 5432
  name: "x402db"
  user: "x402user"
  password: "secret"
  ssl_mode: "disable"     # disable | require | verify-ca | verify-full
  cert_path: ""           # Path to CA cert (required for verify-ca/verify-full)
FieldRequiredDescription
hostYesPostgreSQL hostname or IP.
portYesPostgreSQL port. Must be 1–65535.
nameYesDatabase name.
userYesDatabase user.
passwordYesDatabase password.
ssl_modeYesOne of disable, require, verify-ca, verify-full.
cert_pathNoPath to the CA certificate when ssl_mode is verify-ca or verify-full.

redis

Redis connection settings (used for caching and rate limiting).

yaml
redis:
  address: "localhost:6379"
  password: ""
  db: 0
FieldRequiredDescription
addressYesRedis host:port.
passwordNoRedis password (leave empty if not set).
dbNoRedis database index (0–15). Default 0.

jwt

JSON Web Token signing secrets and expiry durations.

yaml
jwt:
  access_token_secret: "long-random-string"
  refresh_token_secret: "another-long-random-string"
  access_token_expiry: "15m"
  refresh_token_expiry: "168h"
FieldRequiredDescription
access_token_secretYesHMAC secret for signing access tokens. Must be non-empty.
refresh_token_secretYesHMAC secret for signing refresh tokens. Must be non-empty.
access_token_expiryYesGo duration string (e.g. "15m", "1h"). Minimum 1 minute.
refresh_token_expiryYesGo duration string. Minimum 1 minute. Must be ≥ access_token_expiry.

Best practice: Use at least 32 random bytes (256 bits) for token secrets. Generate with openssl rand -hex 32.


security

yaml
security:
  client_secret: "long-random-string"
FieldRequiredDescription
client_secretYesHMAC key used to sign client API tokens issued via POST /api/v1/clients.

admin

yaml
admin:
  enabled: true
  token: "your-admin-token"
FieldRequiredDescription
enabledNoEnable the /admin route group. Default false.
tokenYes (if enabled)Static bearer token for admin endpoints.

x402

x402 protocol behaviour settings.

yaml
x402:
  default_timeout: "30s"
  retry_count: 3
  log_level: "info"
  enable_metrics: true
  allow_missing_client_auth: false
FieldDefaultDescription
default_timeout"30s"Default request timeout for chain RPC calls.
retry_count3Number of retries for failed settlement broadcasts.
log_level"info"Log verbosity: debug, info, warn, error.
enable_metricstrueRecord per-client x402 metrics to the database.
allow_missing_client_authfalseIf true, /verify and /settle work without client API keys. Useful for testing; disable in production.

rate_limit

yaml
rate_limit:
  enabled: true
  requests_per_minute: 100
FieldDefaultDescription
enabledfalseEnable per-IP rate limiting.
requests_per_minute100Maximum requests per IP per minute.

monitoring

yaml
monitoring:
  metrics_enabled: true
  health_check_interval: "30s"
FieldDescription
metrics_enabledExpose Prometheus-compatible metrics (future).
health_check_intervalHow often to run internal health probes.

logging

yaml
logging:
  level: "info"
  format: "json"
FieldDescription
levelLog level: debug, info, warn, error.
formatLog format: json (structured) or text (human-readable).

networks

Define which blockchain networks the facilitator supports. Each network must have an enabled wallet (private key + fee payer address) so the facilitator can sign and broadcast settlement transactions.

Structure

yaml
networks:
  evm:
    - network_name: "base-sepolia"
      ...
  cosmos:
    - network_name: "osmosis"
      ...
  solana:
    - network_name: "solana-devnet"
      ...

Network fields

FieldRequiredDescription
network_nameYesUnique identifier used in payment requirements (e.g. "base-sepolia").
enabledNoWhether this network is active. Default false.
chain_idNoChain ID (numeric string for EVM, descriptive for Cosmos/Solana).
rpcYesHTTP RPC endpoint for the chain.
grpcNogRPC endpoint (Cosmos only).
websocketNoWebSocket RPC endpoint (optional).
accepted_denomYesToken denom/symbol used for payment matching.
decimalsYesToken decimal places (e.g. 6 for USDC).
private_keyYesHex-encoded private key of the facilitator's settlement wallet.
fee_payerYesPublic address of the settlement wallet (used as fee payer / feegrant granter).

EVM example (Base Sepolia)

yaml
networks:
  evm:
    - network_name: "base-sepolia"
      enabled: true
      chain_id: "base-sepolia"
      rpc: "https://sepolia.base.org"
      accepted_denom: "USDC"
      decimals: 6
      private_key: "0xYourPrivateKey"
      fee_payer: "0xYourAddress"

Cosmos example (Osmosis)

yaml
networks:
  cosmos:
    - network_name: "osmosis"
      enabled: true
      chain_id: "osmosis-1"
      rpc: "https://rpc.osmosis.zone"
      grpc: "grpc.osmosis.zone:443"
      accepted_denom: "ibc/498A0751C798A0D9A389AA3691123DADA57DAA4FE165D5C75894505B876BA84"
      decimals: 6
      private_key: "YourCosmosPrivateKeyHex"
      fee_payer: "osmo1YourAddress"

Solana example

yaml
networks:
  solana:
    - network_name: "solana-devnet"
      enabled: true
      chain_id: "solana-devnet"
      rpc: "https://api.devnet.solana.com"
      accepted_denom: "USDC"
      decimals: 6
      private_key: "YourBase58EncodedPrivateKey"
      fee_payer: "YourSolanaPublicKey"

Full Example

See the full annotated config.example.yaml in the repository.


Environment Variables

The facilitator does not currently support environment-variable overrides - all configuration is file-based. For secrets management in production, consider using Docker secrets or a secrets manager that writes files (e.g. Vault Agent, AWS Secrets Manager with file sink) and mount config.yaml into the container.

Released under the MIT License.