> For the complete documentation index, see [llms.txt](https://docs.shortcutco.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.shortcutco.com/developers/guides/export-invoices-and-payments-to-accounting.md).

# Export invoices and payments to accounting

Copy Shortcut invoices, their lines, and payments into an accounting system, and keep balances current.

After this guide, a scheduled job copies every Shortcut invoice and payment into your accounting system, with the lines the customer saw, and keeps statuses, refunds, and overdue balances current. It reads only, so it can never change what your customers owe.

## 1. Create a read-only token

In **Settings → API & integrations**, create a token named `Accounting export` with **Custom** scopes: **Read invoices**, **Read payments**, and **Read customers** (to match invoices to your accounting system's customers).

## 2. Copy invoices

List invoices changed since your last run, oldest change first, and fetch each one for its lines:

```bash
curl "https://api.shortcutco.com/v1/invoices?updatedSince=2026-10-16T08:55:00Z&limit=200" \
  -H "Authorization: Bearer $SHORTCUT_TOKEN"
```

```json
{
  "data": [
    {
      "id": "d3c2b1a0-9f8e-4d7c-8b6a-5f4e3d2c1b0a",
      "object": "invoice",
      "number": 1042,
      "kind": "standard",
      "status": "paid",
      "paymentActivity": null,
      "customerId": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
      "propertyId": "1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
      "propertyAddress": "412 Elm St, Bozeman, MT 59715",
      "propertyLabel": "Home",
      "subtotal": 120,
      "salesTax": 9.5,
      "processingFee": 0,
      "processingFeeScope": "all_payments",
      "cardProcessingFee": 0,
      "lateFees": 0,
      "total": 129.5,
      "dueDate": "2026-10-31",
      "dueAt": "2026-10-31T00:00:00.000Z",
      "coverageStartDate": null,
      "coverageEndDate": null,
      "sentAt": "2026-10-16T17:05:02.000Z",
      "paidAt": "2026-10-16T21:40:13.000Z",
      "createdAt": "2026-10-16T17:02:20.114Z",
      "updatedAt": "2026-10-16T21:40:13.502Z"
    }
  ],
  "meta": { "nextCursor": null, "hasMore": false }
}
```

Then `GET /v1/invoices/{id}` returns the same invoice with `lines`: each line's `type` (`service`, `product`, `add_on`, `discount`, `manual`, `project`), `name`, `date`, `amount`, `taxable`, and the `visitId` and `serviceId` it bills. Map them to your accounting system's items by `serviceId`, or by `name` for manual lines.

Amounts are decimal US dollars. `total` is `subtotal + salesTax + processingFee + lateFees`. Sales tax is computed by Shortcut on the underlying lines and reported once per invoice in `salesTax`.

Use the watermark loop from [Sync](/developers/concepts/sync.md): keep the largest `updatedAt` you have copied, subtract five minutes on the next run, and upsert by `id`. Use `number`, the invoice number the customer sees, as the document number in accounting.

## 3. Copy payments

Payments are never edited, so they sync on `createdSince`:

```bash
curl "https://api.shortcutco.com/v1/payments?createdSince=2026-10-16T08:55:00Z&limit=200" \
  -H "Authorization: Bearer $SHORTCUT_TOKEN"
```

```json
{
  "data": [
    {
      "id": "e7f6a5b4-c3d2-4e1f-9a8b-7c6d5e4f3a2b",
      "object": "payment",
      "invoiceId": "d3c2b1a0-9f8e-4d7c-8b6a-5f4e3d2c1b0a",
      "customerId": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
      "amount": 129.5,
      "method": "online",
      "reference": null,
      "refundedAmount": 0,
      "paidAt": "2026-10-16T21:40:11.000Z",
      "createdAt": "2026-10-16T21:40:13.004Z"
    }
  ],
  "meta": { "nextCursor": null, "hasMore": false }
}
```

Apply each payment to its invoice by `invoiceId`. `method` says how it was paid: `online` through Shortcut, or `cash`, `check`, `ach`, or `other` recorded by the office, with any check number in `reference`.

## 4. Keep balances current

Two changes do not move a watermark, so the job checks them directly:

* **Overdue.** An invoice turns `overdue` on its own when `dueAt` passes, without changing `updatedAt`. Each run, re-list open invoices with `GET /v1/invoices?status=unpaid` and `GET /v1/invoices?status=overdue` and update their status in accounting.
* **Refunds.** A refund that succeeds later raises the payment's `refundedAmount` without changing the payment or its invoice. Re-read recent payments, for example the last 90 days with `GET /v1/payments?createdSince=…`, and post any new refunded amount.

When the office undoes a manual payment, the payment is removed and its invoice's `updatedAt` changes. When an invoice comes back in the sync, re-read its payments with `GET /v1/payments?invoiceId=…` and remove any you have that are gone.

A voided invoice comes back with `status: "void"`; void it in accounting rather than deleting it.

## 5. React within a minute

To post payments as they happen instead of on the next run, subscribe to the invoice and payment webhook events and run the copy for the invoice in the event. Creating the webhook needs **Manage webhooks** on the token, with **Read invoices** and **Read payments** for those events, so add **Manage webhooks** to this token, or have a company admin create the webhook in **Settings → API & integrations**. See [Webhook events](/developers/webhooks/events.md).

## Reference

* [The invoice object](/developers/api-reference/reference/objects/invoice.md) and [the payment object](/developers/api-reference/reference/objects/payment.md): every field. Each list's filters are on its endpoint in the [API reference](/developers/api-reference/reference.md).
* [Sync](/developers/concepts/sync.md): the watermark loop and what it does not pick up.
