1) Overview
This documentation mirrors the exact behavior implemented in the server files you provided (api.js and logic.js).
Key architecture: the HTTP API enqueues write operations into a bounded in-memory queue (with optional DB persistence for pending jobs) and then either waits for the queue worker result (preferred) or returns a legacy-shaped response for backward compatibility. The queue attaches a txId to payloads for idempotency; whether that txId appears in the HTTP response depends on per-route mapping rules implemented in doEnqueueAndMap. See Queue & idempotency below for exact mapping rules. (source: api.js, logic.js).
2) Authentication
Endpoints that require authentication use an Authorization header with a session token:
Authorization: Bearer <sessionId>
Content-Type: application/json
The middleware resolves the session using db.getSession and sets req.userId. If session lookup fails the route returns 403 with legacy error shapes. (see /api/login to create sessions). fileciteturn1file12 fileciteturn1file6
3) Queue & idempotency
Important implementation details (exact):
- The server uses
queue.enqueueAndWait(payload). Before enqueueing, doEnqueueAndMap ensures payload.args.ip is set and attaches payload.txId = a random UUID if not provided. (see api.js) fileciteturn1file12
- If the queue refuses with
ENQUEUE_REJECTED the wrapper will attempt an in-memory cache and a DB pending-job. If that also fails, the API returns 429 / { error: "QUEUE_FULL" }. The cache worker will later flush pending items into the queue. fileciteturn1file10
- Per-route legacy mapping: when
doEnqueueAndMap is called with { legacyReturn: 'transfer' } the API responds with { success: true } on success (hides txId). When called with { legacyReturn: 'transfer_card' } the API will return { success: true, txId?, date? } if the worker result contains a txId, otherwise it returns { success: true }. Other endpoints return the worker result as-is by default. fileciteturn1file10
4) Endpoints (complete & exact)
POST /api/login
Body: { username, password } (server hashes password before checking). Returns sessionCreated + sessionId + userId + saldo + cooldownRemainingMs per logic.login.
Request body:
{
"username": "alice",
"password": "secret"
}
Response (success):
{
"sessionCreated": true,
"passwordCorrect": true,
"userId": "123456789012345678",
"sessionId": "",
"saldo": 12.345678,
"cooldownRemainingMs": 0
}
Notes: the server enforces IP registration/login protections (see logic.login) including IP try counts and blocking windows. fileciteturn1file1
POST /api/register
Creates a user. Body: { username, password }. Server may enforce "one-registration-per-IP" within 24h. On success returns { success:true, userId, sessionId } (session created server-side). fileciteturn1file1
Request:
{ "username": "bob", "password": "s3cret" }
Response:
{ "success": true, "userId": "987654321", "sessionId": "" }
POST /api/transfer — authenticated transfer (legacy response)
Headers: Authorization: Bearer <sessionId>. Body: { toId, amount }. This route enqueues op: 'transfer' with args: { from: req.userId, to, amount }. The legacy behavior is to return { success: true } on success and not include the txId in the HTTP response (even though the queue payload has a txId internally). Use one of the alternatives below if you need the txId. fileciteturn1file12
Request (auth):
Authorization: Bearer
{
"toId": "987654321",
"amount": 0.01234567
}
Response:
{ "success": true }
Alternatives to obtain txId:
- Provide
txId in the request body yourself — the server will keep it for idempotency (it sets payload.txId only if not provided).
- If you can persist the pending job record (DB), correlate it to the eventual transaction when the worker finalizes and write the txId into your tracking table (server may persist pending jobs into DB if configured).
- Use card-based endpoints (which may return
txId) or GET /api/tx/:txid once you have the id. fileciteturn1file10
POST /api/transfer/card — transfer using a card code
Body: { cardCode, toId, amount }. This route hashes the cardCode to find the ownerId, ensures recipient user exists, enqueues op: 'transfer_card', and uses legacyReturn 'transfer_card'. That means:
- If the worker result contains
txId (common when DB helper supports atomic transfer & returns txId) the HTTP response will be { success:true, txId, date }.
- If the worker result does not include
txId, the response will fall back to legacy { success:true }.
Request:
{ "cardCode": "abcd-efgh-1234", "toId": "11111", "amount": 0.01 }
Response (if txId available):
{ "success": true, "txId": "uuid-12345-abcdef", "date": "2025-12-07T12:00:00.000Z" }
Response (legacy fallback):
{ "success": true }
Notes: server truncates amounts to 8 decimals (sats) before enqueueing. Card lookup helpers may be named db.getCardOwnerByHash or similar. fileciteturn1file9
POST /api/card/pay or /api/transfer_between_cards — card-to-card payment
Body: { fromCard, toCard, amount }. Server enqueues op: 'transfer_between_cards' and uses the same legacy mapping as transfer_card, returning txId when the worker returns it, otherwise { success:true }. Amounts truncated to 8 decimals. fileciteturn1file18
Request:
{ "fromCard": "abcd-ef", "toCard": "wxyz-12", "amount": 0.002 }
Possible response:
{ "success": true, "txId": "uuid-xxxxx", "date": "2025-12-07T12:01:00.000Z" }
POST /api/claim — faucet / reward claim
Headers: Authorization: Bearer <sessionId>. Enqueues op: 'claim' (args: { userId }). The API calls the queue directly via queue.enqueueAndWait for claim, and then returns the worker result as-is. The worker (logic.claimCoins) will try to use an atomic DB helper (claimReward) if available; as a fallback it will add coins, set cooldown, and insert a transaction record internally. However, claimCoins returns only the domain result (e.g. { success:true, claimed: X }) and intentionally does not expose the internal txId. If you need the txId for claims you must correlate via server-side pending-job records or change the logic to return txId. fileciteturn1file4
Request (auth):
Authorization: Bearer
Body: {}
Response (success):
{ "success": true, "claimed": 0.05 }
Response (cooldown):
{ "error": "Cooldown active" }
GET /api/tx/:txid — lookup transaction
Use to retrieve transaction info when you have a txId. This route delegates to logic.checkTransaction which uses DB helpers getTransaction|getTransactionById. Response shape:
Response (found):
{
"success": true,
"tx": {
"id": "uuid-12345",
"date": "2025-12-07T12:00:00.000Z",
"from": "11111",
"to": "22222",
"amountSats": 12345,
"amountCoins": "0.00012345"
}
}
Response (not found):
{ "success": false, "errorCode": "INVALID_TRANSACTION", "message": "Transaction not found" }
Notes: amountSats is the integer internal representation (satoshis). The public string amount amountCoins mirrors the DB column. fileciteturn1file4
GET /api/transactions?userId=<id>&page=<n> — list transactions (paginated)
Returns { transactions: [ { id, date, from_id, to_id, amount } ], page } where amount is in coins (string/float formatted via fromSats). The API enqueues or delegates to logic.getTransactions. fileciteturn1file16
Response:
{
"transactions": [
{ "id": "tx-1", "date": "2025-12-07T12:00:00.000Z", "from_id": "11111", "to_id": "22222", "amount": "0.001" }
],
"page": 1
}
GET /api/card/info (or similar helpers) & POST /api/card/reset
The server exposes card helpers via queue ops: get_card (returns { cardCode }) and reset_card (returns { newCode }). Implementation delegates to logic.getCardCode and logic.resetUserCard which call DB helpers. These endpoints usually are protected by auth. fileciteturn1file10
Backup endpoints
Operations: create/list/restore backups. They use logic.createBackup, logic.listBackups, logic.restoreBackup. Examples:
POST /api/backup/create (auth)
-> returns: { success: true } (or an array of codes when createBackup returns codes)
GET /api/backup/list (auth)
-> returns: { backups: ["code1","code2"] }
POST /api/backup/restore (body: { backupId: "..." }, auth)
-> returns: { success: true } on success
Notes: Restore consumes the backup code and will transfer the full balance from the original owner to the requester (see logic.restoreBackup). There are checks to avoid restoring your own backup and to ensure the source wallet has funds. fileciteturn1file7
Billing endpoints (create / pay / list)
Ops supported: bill_create, bill_pay, bill_list, and card variants bill_create_card, bill_pay_card. Examples:
POST /api/bill/create (body: { toId, amount, time? })
-> { success: true, billId: "..." }
POST /api/bill/pay (auth, body: { billId })
-> { success: true }
POST /api/bill/create/card (body: { fromCard?, toCard?, amount, time? })
-> returns logic result (e.g. { success:true, billId })
POST /api/bill/pay/card (body: { cardCode, billId })
-> { success:true } or { success:false, error: '...' }
Card bill flows resolve owner ids from card codes and reuse the bill logic. fileciteturn1file6
Queue inspection (optional)
If EXPOSE_INTERNALS is enabled then:
GET /api/queue/info -> { queued, usedBytes, maxBytes, maxOpsPerSecond }
GET /api/queue/status/:id -> { state, ts, result? }
Useful to debug pending items or to correlate a client-side stored txId with the queue status. fileciteturn1file18
5) txId: generation & when responses include it
- Every enqueued payload receives a
payload.txId (UUID) for idempotency; the server will only set it if the client didn't provide one. This is implemented in doEnqueueAndMap. fileciteturn1file10
- Whether the HTTP response includes the
txId depends on the route mapping rules:
legacyReturn: 'transfer' → response is always { success:true } (txId hidden).
legacyReturn: 'transfer_card' → response is { success:true, txId?, date? } if worker result contains a txId; otherwise { success:true }.
- Default behavior (no legacyReturn) → returns the worker result as-is (which may include txId if the logic function returned it). Examples: some logic functions like
transferCoins return { txId, date } when DB helpers provide it. fileciteturn1file4
- If you must always receive the txId for a transfer, either provide it yourself in the request body or modify the server mapping (in
doEnqueueAndMap) to include payload.txId in the response for transfers. fileciteturn1file17
6) Concrete examples (requests & responses)
cURL — authenticated transfer (legacy)
curl -X POST "https://your.host/api/transfer" \
-H "Authorization: Bearer "
-H "Content-Type: application/json"
-d '{"toId":"987654321","amount":0.001}'
Response:
{ "success": true }
cURL — transfer using card (may return txId)
curl -X POST "https://your.host/api/transfer/card" \
-H "Content-Type: application/json"
-d '{"cardCode":"abcd-efgh-1234","toId":"11111","amount":0.01}'
Possible response:
{ "success": true, "txId": "uuid-12345-abcdef", "date": "2025-12-07T12:00:00.000Z" }
Or (legacy fallback):
{ "success": true }
Node (fetch) — claim
await fetch('https://your.host/api/claim', {
method: 'POST',
headers: { 'Content-Type':'application/json', 'Authorization': 'Bearer ' }
}).then(r => r.json()) // -> { success: true, claimed: 0.05 }
GET tx lookup
curl -X GET "https://your.host/api/tx/uuid-12345-abcdef"
Response:
{
"success": true,
"tx": {
"id": "uuid-12345-abcdef",
"date": "2025-12-07T12:00:00.000Z",
"from": "11111",
"to": "22222",
"amountSats": 12345,
"amountCoins": "0.00012345"
}
}
7) Errors & mappings
- 429 — rate-limit exceeded or queue full:
{ error: "RATE_LIMIT_EXCEEDED" } or { error: "QUEUE_FULL" }. The wrapper tries caching/persistence before returning 429. fileciteturn1file10
- 400 — invalid parameters:
{ error: 'Invalid parameters' }.
- 403 — auth failure: legacy responses often return
{ error: 'operation failed' } with HTTP 403.
- 404 — resource not found (eg. card owner not found) or invalid tx lookup.
- 504 — queue wait timeout:
{ error: 'QUEUE_TIMEOUT' } (or legacy code mapping).
- 500 — internal server error: generic
{ error: 'Internal error' } or { success: false, error: 'Internal error' } depending on route.
8) Appendix — op names & developer notes
Queue operations (payload.op values used by the API):
login, register, logout, account_change, account_unregister, account_update,
transfer, transfer_card, claim, claim_status, get_card, reset_card,
backup_create, backup_list, backup_restore,
get_balance, rank, total_users, tx_lookup, transactions,
bill_list, bill_list_from, bill_list_to, bill_create, bill_pay,
card_info, card_claim, transfer_between_cards,
bill_create_card, bill_pay_card
Developer note: to change whether a route returns txId, edit doEnqueueAndMap mapping in api.js. The server already provides a recommended path: supply your own txId in the request to keep control of idempotency and later correlate with /api/tx/:txid. fileciteturn1file10