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.