Guide

Reconcile payments

Match confirmed on-chain payments back to the invoices and orders they settle, so your books always agree with the blockchain.

The model

A payment is a confirmed on-chain receipt. Most payments reference the invoice_id they settled, which in turn maps to the order you stored when you created the invoice. The reconciliation chain is:

  1. Payment (amount_sats, tx_hash) →
  2. Invoice (invoice_id, your stored order) →
  3. Your order record.

Poll for new payments

Run a periodic job that lists recent payments and processes any you haven't seen before:

const res = await fetch("https://markgroup.app/api/v1/payments?limit=50", {
  headers: { Authorization: `Bearer ${process.env.MG_API_KEY}` },
})
const { data: payments } = await res.json()

for (const payment of payments) {
  if (await alreadyProcessed(payment.id)) continue
  if (payment.invoice_id) {
    await markOrderPaid(payment.invoice_id, payment)
  }
  await recordProcessed(payment.id)
}

Reconcile a single invoice

To settle one specific order, filter payments by its invoice id — useful when confirming a checkout you're actively watching:

curl "https://markgroup.app/api/v1/payments?invoice_id=inv_3n8Kd0Qz" \
  -H "Authorization: Bearer $MG_API_KEY"

Tie out your balance

Your balance reflects all settled payments. Use confirmed_sats as the authoritative, withdrawable figure; total_sats includes incoming amounts not yet fully confirmed.

Make processing idempotent

Key your bookkeeping on payment.idand skip payments you've already handled. That keeps a re-run of your job from crediting the same order twice.