# Accounts Payable Automation

This guide walks through automating the full accounts payable cycle against the Apideck [Accounting API](/apis/accounting/reference): creating vendors, ingesting bills with line items posted to the right ledger accounts, and recording bill payments to close the loop. The same flow targets QuickBooks, Xero, NetSuite, Sage Intacct, Microsoft Dynamics 365 Business Central, and other accounting platforms through a single contract.

## Why a Unified API

AP automation products spend most of their integration budget on the same plumbing: vendor sync, GL coding, posting bills, and reconciling payments. Apideck's unified Accounting API collapses that work into one schema so the AP product team doesn't rebuild it per connector.

- No connector-specific bill schemas, payment endpoints, or vendor identifiers
- One auth flow (Apideck Vault) instead of one OAuth or API-key flow per system
- Consistent linking between bill payments and the bills they apply to
- A single place to read and write ledger accounts, suppliers, tax rates, and tracking categories

## Resource mapping

The unified `Bill` resource maps to the closest AP document in each system. `BillPayment` maps to the payment object the system uses for vendor disbursements.

| Connector | Bill maps to | Bill payment maps to |
| --- | --- | --- |
| QuickBooks | `Bill` | `BillPayment` |
| Xero | `Invoice` of type `ACCPAY` | `Payment` against an AP invoice |
| NetSuite | `Vendor Bill` | `Vendor Payment` |
| Sage Intacct | `AP Bill` | `AP Payment` |
| Microsoft Dynamics 365 Business Central | `Purchase Invoice` | `Vendor Payment Journal` line |
| Exact Online | `Purchase Invoice` | `Payment` |
| Odoo | `account.move` (type `in_invoice`) | `account.payment` |
| Sage Business Cloud Accounting | `Purchase Invoice` | `Purchase Payment` |
| FreshBooks | `Bill` | `Bill Payment` |
| Zoho Books | `Bill` | `Vendor Payment` |

## Walkthrough

The example below ingests a vendor invoice, codes its lines to expense accounts, and records a payment that clears the bill. All requests target `https://unify.apideck.com`.

### 1. Resolve or create the supplier

First, look up the vendor by name to avoid duplicates. Send this to [`GET /accounting/suppliers`](/apis/accounting/reference#operation/suppliersAll) with a filter:

```
GET /accounting/suppliers?filter[company_name]=Northwind%20Cloud%20Hosting
Authorization: Bearer ${APIDECK_API_KEY}
x-apideck-app-id: ${APIDECK_APP_ID}
x-apideck-consumer-id: ${APIDECK_CONSUMER_ID}
x-apideck-service-id: quickbooks
```

If the supplier doesn't exist, create one via [`POST /accounting/suppliers`](/apis/accounting/reference#operation/suppliersAdd):

```json
{
  "company_name": "Northwind Cloud Hosting",
  "display_name": "Northwind Cloud Hosting",
  "tax_number": "GB123456789",
  "currency": "USD",
  "addresses": [
    {
      "type": "primary",
      "line1": "455 Market Street",
      "line2": "Suite 1400",
      "city": "San Francisco",
      "state": "CA",
      "postal_code": "94105",
      "country": "US"
    }
  ],
  "emails": [{ "email": "ap@northwindcloud.example", "type": "primary" }],
  "phone_numbers": [{ "number": "+1 415 555 0188", "type": "primary" }],
  "payment_method": "ACH",
  "status": "active"
}
```

Persist the returned `id` (e.g. `acct_supp_01H8X9Y2A3B4C5D6E7F8G9H0J1`) on your vendor record so subsequent bills can link to it.

### 2. Fetch the chart of accounts for line coding

Pull the expense and liability accounts you'll post against using [`GET /accounting/ledger-accounts`](/apis/accounting/reference#operation/ledgerAccountsAll). Filter by classification to keep the response focused:

```
GET /accounting/ledger-accounts?filter[classification]=expense
```

Cache the resulting account IDs (and the AP control account) in your category mapping. The bill creation in step 3 references those IDs directly on each line.

### 3. Ingest the bill

With the supplier and account IDs in hand, post the bill to [`POST /accounting/bills`](/apis/accounting/reference#operation/billsAdd):

```json
{
  "bill_number": "NW-2025-04412",
  "supplier_id": "acct_supp_01H8X9Y2A3B4C5D6E7F8G9H0J1",
  "currency": "USD",
  "bill_date": "2025-03-04",
  "due_date": "2025-04-03",
  "reference": "PO-9921",
  "po_number": "PO-9921",
  "line_items": [
    {
      "description": "Production Kubernetes cluster, March 2025",
      "quantity": 1,
      "unit_price": 4200.00,
      "total_amount": 4200.00,
      "ledger_account": {
        "id": "acct_ledger_01HQR4F2T8YZA3KQVN9XJ7M5RP",
        "nominal_code": "6310",
        "name": "Cloud Hosting"
      },
      "tracking_categories": [
        { "id": "trk_dept_eng", "name": "Engineering" }
      ]
    },
    {
      "description": "Egress and CDN overage",
      "quantity": 1,
      "unit_price": 318.47,
      "total_amount": 318.47,
      "ledger_account": {
        "id": "acct_ledger_01HQR4F31KZB6F2N7P9Q8T0V2W",
        "nominal_code": "6315",
        "name": "Bandwidth"
      }
    }
  ],
  "sub_total": 4518.47,
  "total_tax": 0.00,
  "total": 4518.47,
  "status": "draft"
}
```

The response returns the bill `id`. Store it alongside your internal AP record so payment events can be applied back to it.

### 4. Attach the source document

For audit trail, upload the original PDF invoice with [`POST /accounting/attachments/{reference_type}/{reference_id}`](/apis/accounting/reference#operation/attachmentsUpload), using `bill` as the `reference_type` and the bill ID as the `reference_id`. Attachment support is connector-dependent (see the matrix below); fall back to storing the file in your own object storage for connectors that don't accept uploads.

### 5. Record the bill payment

When the bill is paid, post a payment that allocates against it via [`POST /accounting/bill-payments`](/apis/accounting/reference#operation/billPaymentsAdd):

```json
{
  "transaction_date": "2025-04-02T16:00:00Z",
  "supplier_id": "acct_supp_01H8X9Y2A3B4C5D6E7F8G9H0J1",
  "currency": "USD",
  "total_amount": 4518.47,
  "reference": "ACH-2025-04-02-00471",
  "payment_method": "ACH",
  "account": {
    "id": "acct_ledger_01HQR4F4P9R2VX5N6T8Q1W3Y4Z",
    "nominal_code": "1100",
    "name": "Operating Bank Account"
  },
  "type": "accounts_payable",
  "status": "authorised",
  "reconciled": false,
  "allocations": [
    {
      "id": "acct_bill_01HQR8M5Y2K3X7N6P9Q1V4T8R5",
      "type": "bill",
      "amount": 4518.47
    }
  ]
}
```

The downstream system computes the bill's paid status from the allocations. There's no separate "mark as paid" call; for the rationale, see the [Mark Invoices and Bills as Paid](/guides/mark-invoices-as-paid) guide.

## Connector-specific behavior

Coverage varies across the catalog. The table below summarizes what each connector supports for the supplier, bill, and bill-payment resources used in this flow. "Read-only" means the connector exposes the resource but Apideck cannot create or update records there yet. "Limited" and "not in coverage" assignments come from the live coverage matrix; verify in Vault before relying on edge behavior.

| Connector | Notes |
| --- | --- |
| `access-financials` | Suppliers and unified payments are writable, but bills and bill payments are not in coverage. AP automation requires a connector with bill write support; use this one for vendor sync only. |
| `acumatica` | Suppliers and bills writable. Bill payments not in coverage. Record the disbursement against the bill using [`POST /accounting/payments`](/apis/accounting/reference#operation/paymentsAdd) with `type: accounts_payable`. |
| `banqup` | Not in coverage for suppliers, bills, or bill payments. Skip for AP automation. |
| `campfire` | Suppliers and bills writable. Bill payments are limited. Verify payment write behavior in Vault before building automated reconciliation. |
| `clearbooks-uk` | Suppliers and bills are read-only; bill payments not in coverage. Use for AP visibility only, not for ingest. |
| `digits` | Suppliers read-only. Bills and bill payments not in coverage. AP ingest is not supported. |
| `dualentry` | Full read+write across suppliers, bills, and bill payments. Standard mapping. |
| `exact-online` | Bills and bill payments are writable. Suppliers are read-only, so vendors must already exist in Exact Online. Resolve existing suppliers via `GET /accounting/suppliers` and have the customer create new vendors in Exact directly. |
| `exact-online-nl` | Same constraints as `exact-online`. Suppliers read-only, bills and bill payments writable. |
| `exact-online-uk` | Suppliers and bills are read-only. Bill payments are writable, but you can only record payments against bills already present in Exact UK. Treat as read-mostly for ingest. |
| `freeagent` | Suppliers and bills are read-only. Bill payments not in coverage. Use for AP read-back only. |
| `freshbooks` | Full read+write across suppliers, bills, and bill payments. Standard mapping. |
| `intuit-enterprise-suite` | Full read+write across suppliers, bills, and bill payments. Also supports attachments, departments, and locations. |
| `kashflow` | Suppliers read-only. Bills and bill payments not in coverage. Skip for AP ingest. |
| `microsoft-dynamics-365-business-central` | Full read+write across suppliers, bills, and bill payments. Bill payments map to vendor payment journal lines; allocations are required to apply against the originating purchase invoice. |
| `moneybird` | Suppliers and bills writable. Bill payments are limited. Confirm whether allocations are accepted before relying on automated bill clearing. |
| `mrisoftware` | Suppliers and bills writable. Bill payments not in coverage and unified payments not in coverage either. Use [`POST /accounting/journal-entries`](/apis/accounting/reference#operation/journalEntriesAdd) when a payment record is required. |
| `myob` | Suppliers and bills not in coverage. Skip for AP automation. |
| `myob-acumatica` | Suppliers and bills writable. Bill payments not in coverage. Use [`POST /accounting/payments`](/apis/accounting/reference#operation/paymentsAdd) with allocations to record disbursements. |
| `netsuite` | Full read+write across suppliers, bills, and bill payments. Subsidiary is required on every bill in OneWorld accounts. Departments, classes, and locations are read-only and must be selected from existing values. |
| `odoo` | Full read+write across suppliers, bills, and bill payments. Bills are stored as `account.move` records of type `in_invoice` and must be confirmed before payment allocation. |
| `pennylane` | Suppliers and bills writable. Bill payments not in coverage and unified payments are not in coverage either. Track payment status outside Pennylane or use journal entries. |
| `procountor-fi` | Suppliers and bills writable. Bill payments not in coverage. Unified payments are read-only, so you can read disbursement status but not write it. |
| `quickbooks` | Full read+write across suppliers, bills, and bill payments. Attachments, departments, and locations are all writable. |
| `rillet` | Suppliers and bills writable. Bill payments are limited. Verify allocation behavior before building automated reconciliation. |
| `sage-business-cloud-accounting` | Full read+write across suppliers, bills, and bill payments. Standard mapping. |
| `sage-intacct` | Full read+write across suppliers, bills, and bill payments. Dimensions (departments, locations) are read-only and must already exist in Intacct. |
| `sage-intacct-rest` | Not in coverage for any of the resources used in this flow. Skip. |
| `stripe` | Suppliers and bills not in coverage. Stripe is not an AP system; skip for vendor bill workflows. |
| `visma-netvisor` | Suppliers and bills writable. Bill payments not in coverage. Use [`POST /accounting/payments`](/apis/accounting/reference#operation/paymentsAdd) with `type: accounts_payable` to record disbursements. |
| `wave` | Suppliers read-only and bills not in coverage. Skip for AP ingest. |
| `workday` | Suppliers and bills writable. Bill payments are read-only, so payment data flows from Workday into your product, not the other way. |
| `xero` | Full read+write across suppliers, bills, and bill payments. Bills are AP invoices (`ACCPAY`); the bill-payment endpoint allocates against them. |
| `yuki` | Suppliers writable, bills are read-only, bill payments not in coverage. Use for vendor sync only. |
| `zoho-books` | Full read+write across suppliers, bills, and bill payments. Standard mapping. |

### NetSuite

NetSuite OneWorld accounts require subsidiary context on the bill. Read available subsidiaries from [`GET /accounting/subsidiaries`](/apis/accounting/reference#operation/subsidiariesAll). Lines also reference `department_id`, `class_id`, and `location_id`, but these dimensions are read-only on NetSuite; surface them as dropdowns sourced from the connector rather than free-text fields.

### Exact Online

Suppliers in Exact Online are read-only across `exact-online`, `exact-online-nl`, and `exact-online-uk`. Vendor onboarding must happen in Exact's UI; your product can only resolve and reference existing suppliers. Bills and bill payments are writable on `exact-online` and `exact-online-nl`; on `exact-online-uk`, bills are read-only too, so only payments against pre-existing bills can be recorded.

### Acumatica, MYOB Acumatica, Visma Netvisor, Pennylane, Procountor

These connectors support bill creation but not the dedicated `bill-payments` endpoint. For the three where the unified `payments` endpoint is writable (`acumatica`, `myob-acumatica`, `visma-netvisor`), record the disbursement via [`POST /accounting/payments`](/apis/accounting/reference#operation/paymentsAdd) with `type: accounts_payable` and an `allocations` entry referencing the bill ID. For `pennylane` (payments not in coverage) and `procountor-fi` (payments read-only), neither bill payments nor writable payments are available, so payment status has to be tracked outside the connector.

### Microsoft Dynamics 365 Business Central

Bill payments map to lines on a vendor payment journal. Always include `allocations` referencing the bill ID; without an allocation, the journal line posts but does not clear the bill.

## Next steps

- [Mark Invoices and Bills as Paid](/guides/mark-invoices-as-paid) for the payment-allocation pattern in more depth
- [Handling Bills and Expenses](/guides/expenses-bills) for the broader Bills vs Expenses decision
- [Accounting API reference](/apis/accounting/reference) for the full unified schema
- [`GET /accounting/aged-creditors`](/apis/accounting/reference#operation/agedCreditorsOne) for AP aging reports without recomputing buckets from raw bills
