This project is a fork of `psf-bch-api` with one major change: paid access now uses the `x402` protocol on the Base ecosystem, with pricing in USDC, instead of `x402-bch` on BCH.
The API surface remains focused on BCH infrastructure (BCH full node, Fulcrum, and SLP indexer), but monetization and payment verification are handled through x402-compatible middleware and facilitator endpoints.
- Optional facilitators: **Dexter** (`PRIMARY_FACILITATOR=dexter`) and **PayAI** (`PRIMARY_FACILITATOR=payai`, default URL `https://facilitator.payai.network`, no API keys).
- **Bazaar** discovery metadata on payment requirements via `@x402/extensions/bazaar`, and optional **multi-facilitator** mode (`ACTIVE_FACILITATORS=cdp,dexter,payai`) with round-robin settle + failover across CDP, Dexter, and PayAI.
-`PRIMARY_FACILITATOR` (default: `cdp`) — one of `cdp`, `dexter`, or `payai`. Used for **single-facilitator** mode when `ACTIVE_FACILITATORS` is unset; selects the default facilitator base URL unless `x402_FACILITATOR_URL` is set.
-`ACTIVE_FACILITATORS` — optional comma-separated list (e.g. `dexter,payai`). When set with multi-facilitator mode, the server registers multiple facilitator backends. `PRIMARY_FACILITATOR` is always first in the active list; remaining names follow in listed order, deduped. Verify uses this order with fallback. Settle uses round-robin per `(x402Version, network, scheme)` with failover to remaining facilitators. Each facilitator uses its default base URL (`x402_FACILITATOR_URL` applies only in **single-facilitator** mode).
-`X402_BAZAAR_ENABLED` (default: `true`) — attach Bazaar **discovery** extension to protected route payment requirements (for facilitator catalogs). Set `false` to disable.
-`x402_FACILITATOR_URL` — optional override for the facilitator HTTP base URL (must expose `/verify`, `/settle`, and `/supported` like the x402 reference facilitator). When unset, the URL is derived from `PRIMARY_FACILITATOR`. **Ignored per-facilitator when `ACTIVE_FACILITATORS` lists more than one entry** (each entry uses its provider URL).
-`PAYAI_FACILITATOR_URL` — optional; when `PRIMARY_FACILITATOR=payai` and `x402_FACILITATOR_URL` is unset, defaults to `https://facilitator.payai.network`.
Use this mode when you want settlement load distributed across multiple facilitators while preserving compatibility for verify calls.
```bash
X402_ENABLED=true
USE_BASIC_AUTH=false
SERVER_BASE_ADDRESS=0xYourBaseAddress
X402_PRICE_USDC=0.1
x402_NETWORK=eip155:8453
PRIMARY_FACILITATOR=cdp
ACTIVE_FACILITATORS=cdp,dexter,payai
FACILITATOR_KEY_ID=your_key_id
FACILITATOR_SECRET_KEY=your_secret
```
How it works:
- Verify path: tries facilitators in configured order (`PRIMARY_FACILITATOR` first), falling back on errors.
- Settle path: uses round-robin rotation per payment kind (`x402Version + network + scheme`), starting from the next facilitator each successful settlement.
- Settle failover: if the selected facilitator fails, the server tries the remaining facilitators in circular order for that request.
- URL behavior: with more than one active facilitator, per-provider default URLs are used; `x402_FACILITATOR_URL` is only for single-facilitator mode.
How to confirm it is active:
1. Start the server and check startup logs for `settle strategy: round-robin-failover`.
2. Send multiple paid requests to the same protected endpoint.
3. Confirm settlement calls alternate over `cdp -> dexter -> payai` (with failover if one is unavailable).
The script is configured for Base mainnet by default (`viem/chains``base`). You can switch it to Base Sepolia by using the commented testnet import in the file.
These are CDP Secret API Key credentials from the Coinbase Developer Platform API Keys dashboard and are used to generate JWT auth headers for `/verify` and `/settle`.
A Docker setup is provided in the `production/docker/` directory for production deployments. The target OS is Ubuntu Linux.
1. Install [Docker and Docker Compose](https://docs.docker.com/engine/install/ubuntu/).
2. Navigate to the Docker directory:
`cd production/docker`
3. Create and configure the `.env` file. An example is provided:
`cp .env-example .env`
Edit `.env` to match your production infrastructure. Note that inside a Docker container, `localhost` refers to the container itself. Use `172.17.0.1` (the default Docker bridge gateway) to reach services running on the host machine:
Set `APIDOC_URL` to the public base URL for your deployment (for example `https://api.example.com` or your subdomain). The container entrypoint applies this value to `apidoc.json` and the `apidoc` section of `package.json`, then runs `npm run docs` before starting the server so generated HTML matches each instance. The compose file mounts `./.env` to `/home/safeuser/psf-bch-api/.env` so it matches `dotenv.config()` in the app.
The container maps host port `5942` to container port `5942`. The `.env` file is mounted into the container as a volume, so you can update configuration without rebuilding.
To view logs:
`docker logs -f psf-bch-api`
To stop the container:
`docker-compose down`
A helper script `cleanup-images.sh` is provided to remove dangling Docker images after rebuilds.
## Testing
The project includes both unit tests and integration tests. Tests use [Mocha](https://mochajs.org/) as the test runner, [Chai](https://www.chaijs.com/) for assertions, and [Sinon](https://sinonjs.org/) for mocking. Code coverage is provided by [c8](https://github.com/bcoe/c8).
### Unit Tests
Unit tests are located in `test/unit/` and cover adapters, controllers, and use cases. They do not require any running infrastructure. To run:
`npm test`
This will first lint the code with [Standard](https://standardjs.com/), then execute all unit tests with code coverage.
To generate an HTML coverage report:
`npm run coverage`
The report is written to the `coverage/` directory.
### Integration Tests
Integration tests are located in `test/integration/` and require the back end infrastructure (full node, Fulcrum, SLP indexer) to be running. To run:
`npm run test:integration`
Integration tests have a 25-second timeout per test to accommodate network calls.
## Configuration Reference
All configuration values are read from environment variables (via the `.env` file). The complete list:
- `PORT` - Server listen port. Default: `5942`
- `NODE_ENV` - Environment (`development` or `production`). Default: `development`
- `API_PREFIX` - URL prefix for all REST endpoints. Default: `/v6`