# Debt Collections with the Accounting API

Debt collection software needs a current view of who owes what, how late they are, and a clean way to record settlements back into the customer's books. This guide shows how to power that workflow with Apideck's [Accounting API](/apis/accounting/reference): pull aged receivables, fetch the overdue invoices behind each bucket, and close the loop by recording a payment when a collection succeeds.

## Why a Unified API

Each accounting platform exposes aged receivables and invoice payments differently. Some compute aging server-side, some do not expose a status field at all, and most disagree on what "paid" means. A unified layer absorbs that variance so the collections product can focus on its own logic.

- No connector-specific aging logic to maintain across thirty-plus accounting systems.
- One invoice and payment schema, regardless of whether the downstream system stores allocations as line links, journal lines, or separate payment objects.
- Status reconciliation handled by the downstream system, not by your code.
- A single OAuth and connection model via Apideck Vault.

## Resource mapping

The unified `aged-debtors` and `invoices` resources map to the following downstream concepts where the connector exposes them:

| Connector | Downstream object |
| --- | --- |
| QuickBooks | `AgedReceivableDetail` report and `Invoice` |
| Xero | `AgedReceivablesByContact` report and `Invoice` |
| NetSuite | Customer aging saved search and `Invoice` |
| Sage Intacct | `AR Aging` report and `AR Invoice` |
| Exact Online | Outstanding invoices view and `SalesInvoice` |
| FreshBooks | Aged receivable report and `Invoice` |
| Zoho Books | Receivable summary and `Invoice` |
| Microsoft Dynamics 365 Business Central | Customer ledger entries and `Sales Invoice` |
| MYOB | Customer aging detail and `Sale Invoice` |
| Acumatica | `AR Aging` and `AR Invoice` |
| Sage Business Cloud Accounting | Aged debtors report and `SalesInvoice` |

## Walkthrough

### 1. Fetch aged receivables

Start at the aggregate level. The dedicated aged debtors endpoint returns the downstream system's own bucketing, which avoids re-deriving aging from raw invoices and avoids time-zone or partial-payment edge cases on your side.

Send this to [`GET /accounting/aged-debtors`](/apis/accounting/reference#operation/agedDebtorsOne).

```http
GET /accounting/aged-debtors?period_count=4&period_length=30 HTTP/1.1
Host: unify.apideck.com
Authorization: Bearer sk_live_8a2d4e6f1c9b4a73b1f2c8d7e9a3f5b1
x-apideck-app-id: app_01H8X9Y2A3KMVPRSTUWXYZ0001
x-apideck-consumer-id: cus_01H8X9Y2A3KMVPRSTUWXYZ0042
x-apideck-service-id: xero
```

The response contains aging buckets per customer, which the collections workflow uses to prioritize outreach.

```json
{
  "data": {
    "id": "aged-debtors-2025-q1",
    "report_generated_at": "2025-03-31T23:59:59Z",
    "report_basis": "accrual",
    "currency": "USD",
    "outstanding_balances": [
      {
        "customer_id": "cust_01H8X9Y2A3KMVPRSTUWXYZ0101",
        "customer_name": "Northwind Supplies Ltd",
        "outstanding_balances": [
          { "period": "current", "outstanding_balance": 0.00 },
          { "period": "1-30 days", "outstanding_balance": 1240.50 },
          { "period": "31-60 days", "outstanding_balance": 4990.00 },
          { "period": "61-90 days", "outstanding_balance": 2150.75 },
          { "period": "90+ days", "outstanding_balance": 875.00 }
        ],
        "total_outstanding_balance": 9256.25
      }
    ]
  }
}
```

If the connector does not expose aged debtors, fall back to listing invoices and bucketing client-side from `due_date` and `amount_due`. Verify per-connector support on the [Aged Debtors](/apis/accounting/reference#tag/Aged-Debtors) tag.

### 2. List the overdue invoices behind a customer

Once a customer is flagged as delinquent, drop down to invoice level so the collections agent can reference specific document numbers. Filter by customer to limit the response to that account.

Send this to [`GET /accounting/invoices`](/apis/accounting/reference#operation/invoicesAll).

```json
{
  "filter": {
    "customer_id": "cust_01H8X9Y2A3KMVPRSTUWXYZ0101",
    "updated_since": "2024-12-01T00:00:00Z"
  },
  "sort": { "by": "due_date", "direction": "asc" }
}
```

Within the response, treat any invoice where `due_date` is in the past and `amount_due` is greater than zero as overdue. `amount_due` is authoritative because the downstream system has already netted partial payments.

### 3. Record the payment after a successful collection

When the debtor pays, post the receipt back to the books using a payment with an allocation pointing at the original invoice. The accounting system recomputes invoice status from the allocation, so the integration does not need to send a status update.

Send this to [`POST /accounting/payments`](/apis/accounting/reference#operation/paymentsAdd).

```json
{
  "transaction_date": "2025-04-02T10:15:00Z",
  "currency": "USD",
  "total_amount": 4990.00,
  "reference": "COLLECT-2025-00187",
  "payment_method": "ACH",
  "payment_method_reference": "ach_3f8c1a07",
  "accounts_receivable_account_id": "acct_01H8X9Y2A3KMVPRSTUWXYZ0500",
  "customer": {
    "id": "cust_01H8X9Y2A3KMVPRSTUWXYZ0101",
    "display_name": "Northwind Supplies Ltd"
  },
  "allocations": [
    {
      "id": "inv_01H8X9Y2A3KMVPRSTUWXYZ0777",
      "type": "invoice",
      "amount": 4990.00
    }
  ],
  "type": "accounts_receivable",
  "note": "Settled via collections agency on 2025-04-02"
}
```

For partial settlements, set `total_amount` and the matching `allocations[].amount` to the partial figure. The invoice will move to a partially-paid state and remain visible in the next aged debtors pull.

### 4. Re-pull aged debtors to confirm the change

After posting payments, re-fetch the aged debtors report for the affected customer. Most downstream systems propagate the new balance immediately, though a few cache the report briefly. If the balance has not updated within a few minutes, fall back to summing `amount_due` on the customer's invoices.

## Connector-specific behavior

Coverage varies for `aged-debtors`, `invoices`, and `payments` across the connectors below. Verify each operation against the live coverage on the [Accounting API reference](/apis/accounting/reference) before relying on it for a given connector. Where aged debtors is not exposed, derive aging from invoice `due_date` and `amount_due`.

| Connector | Notes |
| --- | --- |
| `access-financials` | Confirm aged-debtors and payments coverage in the reference. Derive aging from invoice fields if the report is not exposed. |
| `acumatica` | Allocations close invoices through the AR application. Confirm aged-debtors coverage in the reference. |
| `banqup` | Standard mapping. Verify aged-debtors coverage in the reference; derive from invoice fields otherwise. |
| `campfire` | Standard mapping. No known quirks beyond the unified model. |
| `clearbooks-uk` | Standard mapping. Verify aged-debtors coverage in the reference. |
| `digits` | Standard mapping. No known quirks beyond the unified model. |
| `dualentry` | Standard mapping. No known quirks beyond the unified model. |
| `exact-online` | Aged debtors backed by the outstanding invoices view. Payments must reference an AR ledger account. |
| `exact-online-nl` | Same surface as `exact-online`, localized for the Netherlands. Verify operation coverage in the reference. |
| `exact-online-uk` | Same surface as `exact-online`, localized for the UK. Verify operation coverage in the reference. |
| `freeagent` | Standard mapping. Verify aged-debtors coverage; derive from invoice fields if not exposed. |
| `freshbooks` | Aged receivables and payment allocations supported. Allocations close the invoice automatically. |
| `intuit-enterprise-suite` | QuickBooks-family connector. Aged debtors and payment allocations follow the QuickBooks behavior; verify in the reference. |
| `kashflow` | Standard mapping. No known quirks beyond the unified model. |
| `microsoft-dynamics-365-business-central` | Aging derives from customer ledger entries; the unified `aged-debtors` response normalizes this. Payment allocations translate to apply-to-document entries. |
| `moneybird` | Standard mapping. Verify aged-debtors coverage in the reference. |
| `mrisoftware` | Standard mapping. No known quirks beyond the unified model. |
| `myob` | Allocations require the AR account to be set on the payment. Verify aged-debtors coverage in the reference. |
| `myob-acumatica` | Acumatica-family connector. Verify operation coverage separately from `acumatica` and `myob`. |
| `netsuite` | Aged debtors and payment allocations supported. Payments require a deposit-to account, otherwise the receipt sits in undeposited funds. |
| `odoo` | Standard mapping. Verify aged-debtors coverage in the reference. |
| `pennylane` | Standard mapping. No known quirks beyond the unified model. |
| `procountor-fi` | Standard mapping. No known quirks beyond the unified model. |
| `quickbooks` | Aged debtors and payment allocations supported. `accounts_receivable_account_id` must point to an Accounts Receivable account. |
| `rillet` | Standard mapping. No known quirks beyond the unified model. |
| `sage-business-cloud-accounting` | Aged debtors report and payment allocations supported. |
| `sage-intacct` | Aged debtors backed by the AR Aging report. Payment posting requires a configured payment method. |
| `sage-intacct-rest` | REST surface for Sage Intacct. Behavior tracks `sage-intacct`; verify each operation in the reference. |
| `stripe` | Stripe is not a double-entry ledger. Aged debtors is not exposed; list invoices and bucket client-side from `due_date` and `amount_due`. |
| `visma-netvisor` | Standard mapping. No known quirks beyond the unified model. |
| `wave` | Standard mapping. Verify aged-debtors coverage in the reference. |
| `workday` | Customer invoices and payments are surfaced through Financial Management. Verify aged-debtors coverage in the reference; bucket from invoice fields when not available. |
| `xero` | Aged debtors and payment allocations supported. Filter on authorised invoices when querying for collectibles. |
| `yuki` | Standard mapping. No known quirks beyond the unified model. |
| `zoho-books` | Aged debtors and payment allocations supported. Allocation `amount` cannot exceed the invoice's outstanding balance. |

### exact-online, exact-online-nl, exact-online-uk

The outstanding invoices view is the canonical source for AR aging. When a payment is posted, the AR ledger account on the payment must match the one used on the original invoice, or the allocation will not close it.

### microsoft-dynamics-365-business-central

Aging is computed from customer ledger entries rather than a dedicated report object. The unified `aged-debtors` response normalizes this. Payment allocations translate to apply-to-document entries on the customer ledger.

### netsuite

Set the deposit-to bank account on the payment. Without it, NetSuite leaves the payment as undeposited funds and the invoice does not move to paid.

### quickbooks, intuit-enterprise-suite

The `accounts_receivable_account_id` on the payment must point at an account of type `Accounts Receivable`. Pulling the chart of accounts via [`GET /accounting/ledger-accounts`](/apis/accounting/reference#operation/ledgerAccountsAll) and filtering on type is the safest way to resolve this at runtime.

### stripe

Stripe exposes invoices and payments but is not a double-entry ledger, and there is no aged debtors report. For Stripe-only customers, list invoices via [`GET /accounting/invoices`](/apis/accounting/reference#operation/invoicesAll), filter on `due_date` and `amount_due`, and bucket client-side.

## Next steps

- [Mark invoices and bills as paid](/guides/mark-invoices-as-paid) for the full payment-allocation pattern, including bill payments.
- [Accounting API reference](/apis/accounting/reference) for full schemas on invoices, payments, and aged debtors.
- [`GET /accounting/aged-creditors`](/apis/accounting/reference#operation/agedCreditorsOne) when the same workflow runs in the other direction against suppliers.
