R2 Developers
R2 Connect API

Accounting integration

How to move a business’s income, taxes and collections from R2 into an accounting system, with no manual entry.

The most common use of this API: the business’s accountant stops re-typing what is already in R2. You need two scopes, read:orders and read:payments.

Which resource for what#

You needUseWhy
Accrued income/ordersThe order records the sale, with its tax breakdown, whether collected or not.
Collected income/paymentsThe payment records the money coming in, with method and exact date.
Accounts receivablebalance from /ordersIt is the outstanding balance already computed by R2.
Taxes payabletaxes[] from /ordersIt carries each tax separately, with its rate and amount.

Order and payment are not the same

In R2 an order exists even if it was not paid, is paid later, is paid in cash on arrival or is paid in installments. Do not assume an order implies money received: that is what payments are for. Confusing the two is the costliest mistake in an accounting integration.

Incremental sync#

Store the date of your last run and request only what is new. Leave a one-day overlap so you do not miss records created while the previous run was in flight.

javascript
// Daily reconciliation run
const from = new Date(lastRun - 24 * 60 * 60 * 1000)
  .toISOString().slice(0, 10);          // 1-day overlap

const orders   = await readAll("orders",   { created_from: from });
const payments = await readAll("payments", { created_from: from, status: "succeeded" });

for (const order of orders) {
  await saleEntry({
    reference:  order.order_number,
    date:       order.created_at,
    subtotal:   order.subtotal,
    taxes:      order.taxes,           // each with name, rate and amount
    total:      order.total,
    receivable: order.balance,         // 0 if already settled
  });
}

for (const payment of payments) {
  await collectionEntry({
    reference:  payment.order_number,
    date:       payment.succeeded_at,  // accounting date of the charge
    amount:     payment.amount,
    method:     payment.method,        // card, cash, transfer…
    reconcile:  payment.external_id,   // processor reference
  });
}

Things to watch#