Send receipts and documents from your cloud app to any thermal or desktop printer through one API and a tiny bridge agent. A PrintNode alternative with flat plans, a real job state machine, and server-side receipt rendering.
your app ── POST /v1/jobs ──> printforge cloud <── long-poll ── bridge agent ──> printer
(queued) GET /bridge/v1/jobs?wait=25 (LAN/USB)
POST /bridge/v1/jobs/:id/ack
receipt_json that we render to fixed-width text server-side).printed or failed. Failures requeue automatically until maxAttempts (3), then park as failed for inspection or manual retry.dedupeKey and replays return the original job instead of printing twice.# 1. Create an account (starts a 14-day trial)
curl -X POST http://localhost:5102/api/auth/signup \
-H "content-type: application/json" \
-d '{"email":"you@company.com","password":"s3cret-pass","companyName":"Acme"}'
# 2. Mint an API key with the returned JWT (shown once!)
curl -X POST http://localhost:5102/api/keys \
-H "authorization: Bearer $JWT" -H "content-type: application/json" \
-d '{"name":"production"}'
# 3. Register a printer and queue your first job with the sk_pf_ key
curl -X POST http://localhost:5102/v1/printers \
-H "authorization: Bearer $API_KEY" -H "content-type: application/json" \
-d '{"name":"Kitchen","kind":"thermal","widthChars":42}'
curl -X POST http://localhost:5102/v1/jobs \
-H "authorization: Bearer $API_KEY" -H "content-type: application/json" \
-d '{"printerId":"PRINTER_ID","contentType":"receipt_json","dedupeKey":"order-1042",
"content":{"header":"ACME CAFE","lines":[{"name":"Cheeseburger","qty":2,"price":25.98}],
"totals":[{"label":"TOTAL","amount":25.98}],"footer":"Thank you!"}}'
Then create a bridge (POST /v1/bridges), run node bridge-agent/agent.js with the returned pfb_ token, and the job lands on paper.
| Endpoint | Description |
|---|---|
POST /api/auth/signup | Create account, start trial, returns JWT |
POST /api/auth/login | Login, returns JWT |
GET /api/auth/me | Current account |
POST /api/keys | Create API key (full key shown once) |
GET /api/keys · DELETE /api/keys/:id | List / revoke keys |
GET /api/usage | Current-month counters vs plan limits |
POST /api/billing/checkout · /portal · /webhook | Stripe (or simulated) subscription management |
GET /api/health | Service + DB status |
sk_pf_...)| Endpoint | Description |
|---|---|
POST/GET /v1/printers, GET/PATCH/DELETE /v1/printers/:id | Printer CRUD; status derived from heartbeats (90s window) |
POST/GET /v1/bridges, DELETE /v1/bridges/:id | Bridge devices; device token pfb_... shown once |
POST /v1/bridges/:id/assign | Assign printers to a bridge |
POST /v1/jobs | Queue a job (escpos_base64 | text | receipt_json, optional dedupeKey) |
GET /v1/jobs · /v1/jobs/:id | List (filter by state, printerId, paginated) / inspect |
POST /v1/jobs/:id/cancel | Cancel — only while queued |
POST /v1/jobs/:id/retry | Requeue a failed job (attempts reset) |
pfb_...)| Endpoint | Description |
|---|---|
POST /bridge/v1/heartbeat | Mark device + assigned printers online (optional per-printer statuses) |
GET /bridge/v1/jobs?wait=25 | Long-poll and atomically claim up to 10 queued jobs |
POST /bridge/v1/jobs/:id/ack | Report printed or failed (auto-requeue below max attempts) |
Every account starts with a 14-day free trial (Starter limits), no card required. All errors use one envelope: {"error":{"code":"...","message":"..."}}.