2026-03-23 10:51:12 -07:00
# psf-bch-api-base
2025-11-09 16:16:37 -08:00
2026-02-08 13:07:23 -07:00
[](https://github.com/Permissionless-Software-Foundation/psf-bch-api/blob/master/LICENSE.md)
[](https://github.com/feross/standard)
2026-03-23 10:51:12 -07:00
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.
2026-02-08 13:07:23 -07:00
2026-03-23 10:51:12 -07:00
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.
2025-11-09 16:16:37 -08:00
2026-03-23 10:51:12 -07:00
## What Changed In This Fork
2026-02-08 12:57:06 -07:00
2026-03-23 10:51:12 -07:00
- Switched from `x402-bch` middleware to `x402-express` .
- Added Base/EVM payment support (`@x402/evm` ) and `x402-axios` client example.
- Pricing is configured in `X402_PRICE_USDC` (USDC amount), not BCH satoshis.
- x402 network is configured using CAIP-2 format (for example `eip155:8453` for Base mainnet and `eip155:84532` for Base Sepolia).
- Facilitator auth headers are generated using Coinbase CDP JWT auth (`FACILITATOR_KEY_ID` and `FACILITATOR_SECRET_KEY` ) when using CDP endpoints.
2025-11-09 16:16:37 -08:00
2026-03-23 10:51:12 -07:00
## Architecture
2026-02-08 13:07:23 -07:00
2026-03-23 10:51:12 -07:00
The server is a Node.js + Express REST API following a Clean Architecture style, and it still depends on:
2026-02-08 13:07:23 -07:00
2026-03-23 10:51:12 -07:00
- BCH full node JSON-RPC
- Fulcrum API
- SLP indexer API
2026-02-08 13:07:23 -07:00
2026-03-23 10:51:12 -07:00
The access-control layer now supports:
2026-02-08 13:07:23 -07:00
2026-03-23 10:51:12 -07:00
- open access (no auth, no payment)
- bearer-token auth
- x402 paid access on Base + USDC
- optional bearer bypass for trusted clients when x402 is enabled
2026-02-08 13:07:23 -07:00
2026-03-23 10:51:12 -07:00
## Quick Start
2026-02-08 13:07:23 -07:00
2026-03-23 10:51:12 -07:00
1. Install dependencies:
2026-02-08 13:07:23 -07:00
2026-03-23 10:51:12 -07:00
```bash
npm install
```
2026-02-08 13:07:23 -07:00
2026-03-23 10:51:12 -07:00
2. Create a local env file:
2026-02-08 13:07:23 -07:00
2026-03-23 10:51:12 -07:00
```bash
cp .env-example .env
```
2026-02-08 13:07:23 -07:00
2026-03-23 10:51:12 -07:00
3. Edit `.env` for your infrastructure and access-control mode.
2026-02-08 13:07:23 -07:00
2026-03-23 10:51:12 -07:00
4. Start the server:
2026-02-08 13:07:23 -07:00
2026-03-23 10:51:12 -07:00
```bash
npm start
```
2026-02-08 13:07:23 -07:00
2026-03-23 10:51:12 -07:00
By default, the API runs on `http://localhost:5942` and controllers are mounted under `/v6` .
2026-02-08 13:07:23 -07:00
2026-03-23 10:51:12 -07:00
## Environment Variables
2026-02-08 13:07:23 -07:00
2026-03-23 10:51:12 -07:00
All configuration is loaded from environment variables (typically from `.env` ).
2026-02-08 13:07:23 -07:00
2026-03-23 10:51:12 -07:00
### Core Server and BCH Infrastructure
2026-02-08 13:07:23 -07:00
2026-03-23 10:51:12 -07:00
- `PORT` (default: `5942` )
- `NODE_ENV` (default: `development` )
- `API_PREFIX` (default: `/v6` )
- `LOG_LEVEL` (default: `info` )
- `RPC_BASEURL` (default: `http://127.0.0.1:8332` )
- `RPC_USERNAME`
- `RPC_PASSWORD`
- `RPC_TIMEOUT_MS` (default: `15000` )
- `RPC_REQUEST_ID_PREFIX` (default: `psf-bch-api` )
- `FULCRUM_API`
- `FULCRUM_TIMEOUT_MS` (default: `15000` )
- `SLP_INDEXER_API`
- `SLP_INDEXER_TIMEOUT_MS` (default: `15000` )
- `REST_URL` or `LOCAL_RESTURL` (default fallback: `http://127.0.0.1:5942/v6/` )
- `IPFS_GATEWAY` (default: `p2wdb-gateway-678.fullstack.cash` )
- `SERVER_KEEPALIVE_TIMEOUT_MS` (default: `3000` )
- `SERVER_HEADERS_TIMEOUT_MS` (default: `65000` )
- `SERVER_REQUEST_TIMEOUT_MS` (default: `120000` )
### x402 + Base + USDC Settings
- `X402_ENABLED` (default: `true` )
- `SERVER_BASE_ADDRESS` (EVM address receiving x402 settlements)
- `X402_PRICE_USDC` (USDC charged per request)
- `x402_NETWORK` (CAIP-2 chain ID; e.g. `eip155:8453` or `eip155:84532` )
- `x402_FACILITATOR_URL` (default: `https://api.cdp.coinbase.com/platform/v2/x402` )
- `FACILITATOR_KEY_ID` (required for CDP facilitator auth)
- `FACILITATOR_SECRET_KEY` (required for CDP facilitator auth)
### Optional Bearer Auth
- `USE_BASIC_AUTH` (default: `false` )
- `BASIC_AUTH_TOKEN`
## Access Control Modes
Behavior is controlled by `X402_ENABLED` and `USE_BASIC_AUTH` .
### 1) Open Access
```bash
2026-02-08 13:07:23 -07:00
X402_ENABLED = false
USE_BASIC_AUTH = false
```
2026-03-23 10:51:12 -07:00
No payment and no auth checks.
2026-02-08 13:07:23 -07:00
2026-03-23 10:51:12 -07:00
### 2) Bearer Auth Only
2026-02-08 13:07:23 -07:00
2026-03-23 10:51:12 -07:00
```bash
2026-02-08 13:07:23 -07:00
X402_ENABLED = false
USE_BASIC_AUTH = true
BASIC_AUTH_TOKEN = my-secret-token
```
2026-03-23 10:51:12 -07:00
Requests (except `/` and `/health` ) must send:
2026-02-08 13:07:23 -07:00
2026-03-23 10:51:12 -07:00
```text
2026-02-08 13:07:23 -07:00
Authorization: Bearer my-secret-token
```
2026-03-23 10:51:12 -07:00
### 3) x402 Payments on Base (USDC)
2026-02-08 13:07:23 -07:00
2026-03-23 10:51:12 -07:00
```bash
2026-02-08 13:07:23 -07:00
X402_ENABLED = true
2026-03-23 10:51:12 -07:00
USE_BASIC_AUTH = false
SERVER_BASE_ADDRESS = 0xYourBaseAddress
X402_PRICE_USDC = 0.1
x402_NETWORK = eip155:8453
x402_FACILITATOR_URL = https://api.cdp.coinbase.com/platform/v2/x402
FACILITATOR_KEY_ID = your_key_id
FACILITATOR_SECRET_KEY = your_secret
2026-02-08 13:07:23 -07:00
```
2026-03-23 10:51:12 -07:00
Protected endpoints return `402 Payment Required` when no valid payment is attached. x402-capable clients can pay and retry automatically.
2026-02-08 13:07:23 -07:00
2026-03-23 10:51:12 -07:00
### 4) x402 + Bearer Bypass
2026-02-08 13:07:23 -07:00
2026-04-01 08:36:47 -07:00
When `X402_ENABLED=true` , the server also exposes machine-discovery endpoints:
- `/.well-known/x402` - x402-bch v2 payment discovery manifest
- `/openapi.json` - OpenAPI 3 projection generated from apiDoc annotations
- `/swagger.json` - Swagger 2.0 compatibility projection
- `/llms.txt` - LLM-oriented markdown index of service metadata
- `/.well-known/agent.json` - draft agent manifest describing API actions
When `X402_ENABLED=false` , these discovery endpoints return `404` .
2026-02-08 13:07:23 -07:00
#### Combined: x402 + Bearer Token
You can enable both at the same time:
```
X402_ENABLED=true
USE_BASIC_AUTH=true
BASIC_AUTH_TOKEN=my-secret-token
```
2026-03-23 10:51:12 -07:00
Bearer-authenticated requests bypass payment; all others must pay via x402.
2026-02-08 13:07:23 -07:00
2026-03-23 10:51:12 -07:00
## Client Example: Axios + x402
2026-02-08 13:07:23 -07:00
2026-03-23 10:51:12 -07:00
Use `examples/01-x402-axios-client.js` to test the payment flow end-to-end.
2025-11-09 16:16:37 -08:00
2026-03-23 10:51:12 -07:00
What it does:
2025-11-09 21:42:00 -08:00
2026-03-23 10:51:12 -07:00
1. Calls a protected endpoint without payment and expects `402` .
2. Repeats the call using `x402-axios` + an EVM wallet and expects success.
2025-11-09 21:42:00 -08:00
2026-03-23 10:51:12 -07:00
Run it with an EVM private key:
2025-11-09 21:42:00 -08:00
2026-03-23 10:51:12 -07:00
```bash
PRIVATE_KEY = 0x... node examples/01-x402-axios-client.js
2026-02-08 13:07:23 -07:00
```
2025-11-09 21:42:00 -08:00
2026-03-23 10:51:12 -07:00
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.
2026-02-08 13:07:23 -07:00
2026-03-23 10:51:12 -07:00
## Coinbase CDP Credentials
2026-02-08 13:07:23 -07:00
2026-03-23 10:51:12 -07:00
When using Coinbase's hosted facilitator (`https://api.cdp.coinbase.com/platform/v2/x402` ), you must provide:
2026-02-08 13:07:23 -07:00
2026-03-23 10:51:12 -07:00
- `FACILITATOR_KEY_ID`
- `FACILITATOR_SECRET_KEY`
2026-02-08 13:13:19 -07:00
2026-03-23 10:51:12 -07:00
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` .
2026-02-08 13:07:23 -07:00
2026-03-23 10:51:12 -07:00
## Development
2026-02-08 13:07:23 -07:00
2026-03-23 10:51:12 -07:00
Common commands:
2026-02-08 13:07:23 -07:00
2026-03-23 10:51:12 -07:00
```bash
npm start
npm test
npm run test:integration
npm run docs
2026-02-08 13:07:23 -07:00
```
X402_ENABLED=false
USE_BASIC_AUTH=false
```
2025-11-09 21:42:00 -08:00
2026-02-08 13:07:23 -07:00
5. Start the server:
2025-11-09 21:42:00 -08:00
2026-02-08 13:07:23 -07:00
`npm start`
2025-11-09 21:42:00 -08:00
2026-02-08 13:07:23 -07:00
The server will start on port `5942` by default (or whatever you set in `PORT`). API documentation is available at `http://localhost:5942/`.
2025-11-09 21:42:00 -08:00
2026-02-08 13:07:23 -07:00
### Generating API Docs
The API reference documentation is generated by [apiDoc](https://apidocjs.com/) from inline annotations in the source code. To regenerate:
`npm run docs`
The output is written to the `docs/` directory and served by the running server at its root URL.
2026-04-01 08:36:47 -07:00
To regenerate API docs plus discovery artifacts (`openapi.json`, `swagger.json`, `llms.txt`, and `agent.json` payload source):
`npm run docs:all`
This runs apiDoc first, then generates `docs/discovery-artifacts.json` from the same annotation source.
2026-02-08 13:13:19 -07:00
A live version can be found at [bch.fullstack.cash](https://bch.fullstack.cash/).
2026-02-08 13:07:23 -07:00
## Production (Docker)
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:
```
RPC_BASEURL=http://172.17.0.1:8332
FULCRUM_API=http://172.17.0.1:3001/v1
SLP_INDEXER_API=http://172.17.0.1:5010
```
2026-04-01 08:57:10 -07:00
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.
2026-02-08 13:07:23 -07:00
4. Build the Docker image:
` docker-compose build --no-cache`
5. Start the container:
` docker-compose up -d`
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`
- ` LOG_LEVEL` - Winston logging level. Default: ` info`
- ` RPC_BASEURL` - Full node JSON-RPC URL. Default: ` http://127.0.0.1:8332`
- ` RPC_USERNAME` - Full node RPC username.
- ` RPC_PASSWORD` - Full node RPC password.
- ` RPC_TIMEOUT_MS` - Full node RPC request timeout in ms. Default: ` 15000`
- ` FULCRUM_API` - Fulcrum indexer REST API URL.
- ` FULCRUM_TIMEOUT_MS` - Fulcrum API request timeout in ms. Default: ` 15000`
- ` SLP_INDEXER_API` - SLP Token Indexer REST API URL.
- ` SLP_INDEXER_TIMEOUT_MS` - SLP Indexer API request timeout in ms. Default: ` 15000`
- ` LOCAL_RESTURL` - Internal REST URL for wallet operations. Default: ` http://127.0.0.1:5942/v6/`
- ` IPFS_GATEWAY` - IPFS gateway hostname. Default: ` p2wdb-gateway-678.fullstack.cash`
- ` X402_ENABLED` - Enable x402-bch payment middleware. Default: ` true`
- ` SERVER_BCH_ADDRESS` - BCH address for x402 payments. Default: ` bitcoincash:qqsrke9lh257tqen99dkyy2emh4uty0vky9y0z0lsr`
- ` FACILITATOR_URL` - x402-bch facilitator service URL. Default: ` http://localhost:4345/facilitator`
- ` X402_PRICE_SAT` - Satoshis charged per API call via x402. Default: ` 200`
- ` USE_BASIC_AUTH` - Enable Bearer token authentication. Default: ` false`
- ` BASIC_AUTH_TOKEN` - Expected Bearer token value.
## License
[MIT ](./LICENSE.md )