Architecture
Data flow
This page walks the bytes through a single end-to-end payment, from the merchant''s API call to the signed webhook.
Read this page if you are integrating as a merchant or debugging settlement. It is the single best page to understand the lifecycle of a payment in BabyFX Pay.
End-to-end sequence
sequenceDiagram
autonumber
actor C as Customer
participant M as Merchant
participant P as pay/api :4000
participant DB as Postgres
participant S as pay/settlement
participant N as chain :8545
participant W as pay/webhooks
participant H as Merchant endpoint
C->>M: scan QR (EIP-681)
M->>P: POST /v1/invoices
P->>P: auth (HMAC)
P->>P: rate limit + idempotency
P->>DB: nextval(invoice_deriv_seq)
P->>P: derive deposit address
m/44'/60'/0'/0/index
P->>DB: INSERT invoice
P-->>M: 201 deposit_address + QR
C->>N: eth_sendRawTransaction
N-->>S: new block (polled 1.5s)
S->>DB: match by deposit_address
S->>N: getTransactionReceipt
S->>DB: status = PAID
S->>W: queue payment.detected
loop until 2xx
W->>H: POST webhook
x-babyfx-signature
H-->>W: response
end
Note over S: confirmations advance
S->>DB: status = CONFIRMED at threshold
S->>S: sweep ? merchant.settlement_address
S->>N: eth_sendRawTransaction
S->>DB: sweep_status = SWEPT
Where each piece lives
| Step | Component | File |
|---|---|---|
| Auth + idempotency | pay/api |
pay/index.js |
| HD derivation | pay/api (in-process) |
pay/lib.js |
| Block polling | pay/settlement |
pay/settlement.js loop() |
| Payment matching | pay/settlement |
pay/settlement.js scanBlock() |
| Confirmation tracking | pay/settlement |
pay/settlement.js updateConfirmations() |
| Webhook signing | pay/settlement (queue) + pay/webhooks (deliver) |
pay/settlement.js queueWebhook(), pay/webhooks.js deliverOne() |
| Sweep | pay/sweep |
pay/sweep.js sweepInvoice() |
Failure modes and recovery
Crash between invoice INSERT and webhook queue: the invoice is PENDING with a deposit address. The next settlement run will detect the on-chain payment and queue the webhook. No manual recovery.
Crash between webhook queue and HTTP delivery: the row in
webhook_deliveries is delivered=FALSE. The dispatcher retries it.Customer pays wrong amount: the settlement listener only matches
tx.value >= invoice.baby_amount_wei. Underpayment is ignored. There is no automatic overpayment refund; the merchant must handle it out of band.Reorg that drops the paying block: the confirmation count drops. The invoice returns to PAID (or PENDING if the reorg is deeper). No automatic re-notification.
Sweep failure (insufficient gas): the invoice is marked
sweep_status=FAILED with a sweep_tx_hash if a tx was sent. Manual retry is required.