Spindle is an API-first Fiber payment gateway for agent backends on CKB.
Spindle puts a narrow gateway layer in front of agent payment execution:
- authenticates callers with API keys
- enforces route-level scopes
- checks spend policy before execution
- creates Fiber invoices
- executes allowed payments on owned Fiber testnet nodes
- handles retries and duplicate execution honestly
- records audit history
- exposes tenant-scoped query APIs for invoices, payments, audit rows, and API keys
Agent backends should not move directly from app logic to payment execution. Without a gateway layer, ownership boundaries get blurred, spend rules are easy to bypass, and denial or failure states are easy to hide.
Spindle sits between agent logic and Fiber so each request has explicit auth, policy, execution, and audit outcomes. The point is not to look like a broad infrastructure platform. The point is to make automated payment requests controlled and auditable.
The current repo supports:
- API-key authentication with active, inactive, malformed, and invalid key handling
- API-key lifecycle with create and revoke flows
- route-level scopes for invoice, payment, audit, and key routes
- policy checks for approved addresses, max-per-action, and rolling 24-hour spend
- invoice creation through Fiber testnet
- payment execution against owned Fiber testnet nodes
- payment status lookup by owned payment hash
- tenant-scoped invoice, payment, audit, and key reads
- audit logging for success, denial, failure, blocked, idempotent, and status-check paths
- idempotent retry handling for already-settled invoices
- duplicate in-flight execution blocking
- stale processing recovery during payment-status checks
See also:
This repository does not claim:
- mainnet settlement
- proof verification or on-chain anchoring
- live telemetry or an operations console
- a published SDK
- production SLA or uptime guarantees
- full RBAC or session-based auth
- webhook delivery or external reconciliation tooling
- a broader infrastructure platform beyond the gateway described here
Fiber is the actual payment rail used by the repo. That makes Spindle relevant to CKB in a direct way: it is not a generic policy engine with an ecosystem label attached after the fact.
The honest value is the gateway shape around Fiber:
- policy before execution
- tenant ownership before reads and writes
- truthful handling of denial, failure, blocked, processing, and settled states
- audit and query surfaces after execution
GET /api/health
Returns application, database, and Fiber configuration status for the current environment.
POST /api/v1/invoices
Creates an invoice through Fiber and persists an owned invoice record.
Request body:
{
"amount": "1",
"assetSymbol": "USDT",
"description": "Agent payout",
"externalReference": "optional"
}GET /api/v1/invoices
Lists invoices for the authenticated agent. Supports status and limit.
GET /api/v1/invoices/[invoiceId]
Returns one owned invoice by stable ID.
POST /api/v1/payments
Executes payment for an owned invoice string.
Request body:
{
"invoice": "fibt1..."
}Behavior includes:
- policy evaluation before execution
- idempotent success for already-paid invoices
409blocking for duplicate in-flight execution- status updates written back to the owned invoice
GET /api/v1/payments/[paymentHash]
Returns normalized invoice status and Fiber status for an owned payment hash.
GET /api/v1/audit
Lists tenant-scoped audit rows. Supports invoiceId, paymentHash, actionType, and limit.
GET /api/v1/keys
Lists API keys owned by the authenticated agent.
POST /api/v1/keys
Creates a new scoped API key.
{
"name": "Read-only payment key",
"scopes": ["payments:read"]
}DELETE /api/v1/keys/[keyId]
Revokes an owned API key.
Prerequisites:
- Postgres reachable through
DATABASE_URL - Fiber testnet node reachable through
FIBER_NODE_URL - optional
FIBER_API_KEYif the node requires it
Recommended local flow:
npm install
npm run db:setup
npm run devIf port 3000 is busy:
npm run dev -- --port 3041- The seeded local fixture creates the test API key
spnd_test_abcdef123. - That key is a local test fixture, not a production secret.
- Reviewer-facing seeded scenarios live in the app under
/scenariosand are labeled as seeded support material rather than live runtime evidence.
The repo is ready for a hosted Postgres database through Prisma. For the current MVP, Neon is the simplest fit because Spindle only needs Postgres plus a connection string, not Supabase auth, storage, realtime, or dashboard features.
Set these variables in .env locally and in the demo host:
# Runtime app connection. Use a pooled hosted Postgres URL when available.
DATABASE_URL="postgresql://USER:PASSWORD@HOST/DATABASE?sslmode=require"
# Prisma CLI migration connection. Use the direct/non-pooled URL.
# If omitted, Prisma falls back to DATABASE_URL.
DIRECT_URL="postgresql://USER:PASSWORD@DIRECT_HOST/DATABASE?sslmode=require"
FIBER_NODE_URL="http://localhost:8227"
FIBER_API_KEY=""
SPINDLE_ENABLE_LEGACY_API_KEY_FALLBACK="false"Run the hosted database setup from this repo:
npm install
npm run db:migrate
npm run db:generate
npm run db:seed
npm run buildThe demo seed creates:
- agent
test-agent-id - managed API key secret
spnd_test_abcdef123 - active policy with daily spend limit
300, max per action500, and two approved addresses - one paid
USDTinvoice for policy history
The simplest public deployment is the full Next.js app on Vercel when FIBER_NODE_URL points to a Fiber RPC endpoint that Vercel can reach. The app does not need a separate frontend/backend split for Postgres or Prisma.
If FIBER_NODE_URL is local, such as http://127.0.0.1:8229, the public UI can still run on Vercel, but live invoice creation and payment execution must run on a backend host that can reach that Fiber node.
Minimum production env vars:
DATABASE_URL="postgresql://..."
DIRECT_URL="postgresql://..."
FIBER_NODE_URL="https://public-or-private-fiber-rpc.example"
FIBER_API_KEY=""
SPINDLE_ENABLE_LEGACY_API_KEY_FALLBACK="false"Vercel deployment commands:
npm run build
vercel --prod