Indexer + REST/WebSocket API for StackPay — turns Soroban payment events into queryable requests, balances, and webhooks.
The off-chain brain of StackPay. The contract (stackpay-contracts) is the source of truth; this service keeps a materialized view so the dApp and integrators can query requests, statuses, and history without replaying ledgers.
- What it does
- Architecture
- Tech stack
- Getting started
- Configuration
- API reference
- WebSocket events
- Indexer internals
- Docker
- Testing
- Deployment
- Contributing
- License
- Indexes
request_created,request_paid,request_cancelledevents from Soroban RPC. - Materializes request state into PostgreSQL.
- Serves a REST API for the dApp and partners.
- Streams live updates over WebSocket.
- Notifies via webhooks on payment.
Stellar RPC / Horizon
| poll ledger
v
+------------+ events +--------------+
| Indexer | -------> | PostgreSQL |
| (worker) | +------+-------+
+------------+ |
+-----v------+
| REST API |<-- dApp / partners
| (Express) |
+-----+------+
| publish
+-----v------+
| WebSocket |
| (Socket.IO)|
+------------+
- Node.js 20 + TypeScript, Express, Socket.IO
- PostgreSQL 16 (Prisma), Redis 7 (BullMQ)
@stellar/stellar-sdkfor RPC/ledger access
git clone https://github.com/Stack-Rocks/stackpay-backend.git
cd stackpay-backend
cp .env.example .env
npm install
npx prisma migrate dev
npm run devAPI at http://localhost:4000.
See .env.example:
| Variable | Description |
|---|---|
PORT |
HTTP port (default 4000). |
DATABASE_URL |
PostgreSQL connection string. |
REDIS_URL |
Redis connection string. |
STELLAR_RPC_URL |
Soroban RPC endpoint. |
STELLAR_NETWORK |
testnet | mainnet. |
CONTRACT_PAYMENT |
Deployed PaymentRequest contract address. |
START_LEDGER |
Ledger to begin indexing from. |
Base: http://localhost:4000/api/v1
| Method | Path | Description |
|---|---|---|
GET |
/requests |
List requests (filter payee, payer, status, asset). |
GET |
/requests/:id |
Get a request + on-chain status. |
GET |
/requests/:id/history |
Event history. |
GET |
/accounts/:address/requests |
Requests involving an address. |
GET |
/accounts/:address/received |
Total received by an address. |
| Method | Path | Description |
|---|---|---|
POST |
/webhooks |
Register a URL to notify on request_paid. |
Example:
curl http://localhost:4000/api/v1/requests/7{ "id": 7, "payee": "GABC...", "asset": "C...", "amount": "5000000",
"memo": "Invoice #12", "status": "Paid" }Connect to ws://localhost:4000. Subscribe to a request room:
socket.emit("subscribe", { requestId: 7 });
socket.on("request:paid", (p) => console.log(p));Events: request:created, request:paid, request:cancelled.
- Polls
getEventsin contiguous ledger windows; resumable via a storedlast_ledgercursor. - Maps events to DB upserts keyed by
contract + request_id. - Idempotent — safe to run a single worker replica.
docker compose up --buildnpm run test # vitest (PG via testcontainers)
npm run test:e2e # against local soroban sandboxStateless API behind any Node host; one long-running indexer worker; managed Postgres + Redis.
Part of the Stellar Wave Program on Drips. Look for Stellar Wave / Good first issue. Run npm run lint && npm run test before a PR.
MIT.