> ## Documentation Index
> Fetch the complete documentation index at: https://docs.spirii.com/llms.txt
> Use this file to discover all available pages before exploring further.

# ERP integration

> Invoice your customers, and post charging costs and home charging reimbursements, from Spirii's charge detail records.

By the end of this playbook you'll turn Spirii's charge detail records (CDRs) into invoice lines and ledger entries in your ERP, matched to the right customer, site, and cost centre. If you run home charging reimbursement through payroll, you'll bring approved expense reports in as well.

## Before you start

This playbook is for operators and e-mobility providers who invoice their customers from their own systems. That's the case on the **Invoice Data Service** and **No service** billing service levels. On **Full Service**, Spirii invoices your customers for you, so your ERP receives Spirii's invoices rather than building its own. See [Billing service levels](/capabilities/billing-payouts/charge-key-billing#billing-service-levels).

Spirii doesn't expose finished billing documents through the API. You build invoice lines from raw CDRs, which carry the energy, price, VAT rate, and references each line needs.

You'll need an [API key](/developers/authentication) and a working understanding of [sessions and CDRs](/components/charging/sessions-and-cdrs). Who carries the VAT on a session depends on who is the merchant; see [Who is the merchant](/capabilities/billing-payouts/billing-and-payout-flows#who-is-the-merchant).

## How the pieces fit

Each CDR becomes one line. Three references on it place that line in your ERP:

* **The customer**, to know whom to invoice. The CDR carries Spirii's customer ID, which you map to your ERP's customer number through the customer's `externalId`.
* **The charge key's billing reference**, such as a driver's cost centre. It travels on the CDR as `auth.idTag.billingReference`.
* **The location's billing reference**, such as a site or project code. It isn't on the CDR: fetch it from the location, using the CDR's `location.id`.

```mermaid theme={null}
flowchart LR
    CDR("CDR") -->|"location.crmCustomerId or auth.idTag.crmCustomerId"| CU("Customer: externalId")
    CDR -->|"auth.idTag.billingReference"| CK("Charge key reference")
    CDR -->|"location.id"| LO("Location: billingReference")
    CU --> LINE("Invoice line in your ERP")
    CK --> LINE
    LO --> LINE
```

### Choose the mode for what you invoice

| You're invoicing                                       | `mode` | Match each CDR to a customer on |
| ------------------------------------------------------ | ------ | ------------------------------- |
| Charging on locations you operate                      | `cpo`  | `location.crmCustomerId`        |
| Charging on the charge keys you issued, on any network | `emp`  | `auth.idTag.crmCustomerId`      |

If you do both, run the two as separate pulls and keep the lines apart in your ERP.

## Set up invoicing

A fleet operator with 600 issued charge keys is a typical case: each key's billing reference holds the driver's cost centre, and every month's charging, at the depot and on the road, is posted to the ERP per cost centre.

<Steps>
  <Step title="Map customers to your ERP">
    Set each customer's `externalId` to its customer number in your ERP, so a CDR's customer resolves to an ERP account without a lookup table. If a CRM owns your customer records, the [CRM integration](/developers/crm-integration) playbook covers keeping `externalId` in step.
  </Step>

  <Step title="Set billing references">
    Write the references your invoices need onto charge keys and locations. Both are free-text fields.

    ```bash theme={null}
    curl -X PATCH https://api.spirii.com/v2/tokens/48213 \
      -H "Authorization: Bearer <SPIRII_API_KEY>" \
      -H "Content-Type: application/json" \
      -d '{ "billingReference": "CC-4410" }'

    curl -X PATCH https://api.spirii.com/v2/locations/12345 \
      -H "Authorization: Bearer <SPIRII_API_KEY>" \
      -H "Content-Type: application/json" \
      -d '{ "billingReference": "SITE-0231" }'
    ```
  </Step>

  <Step title="Pull the period's CDRs">
    Fetch CDRs by `updatedAt`, in the mode that matches what you invoice. To invoice one customer, add a filter on its customer ID.

    ```bash theme={null}
    curl -G "https://api.spirii.com/v2/charge-records" \
      -H "Authorization: Bearer <SPIRII_API_KEY>" \
      --data-urlencode 'mode=emp' \
      --data-urlencode 'filter={"auth.idTag.crmCustomerId":{"$eq":123}}' \
      --data-urlencode 'updatedAtFrom=2026-09-01T00:00:00.000Z' \
      --data-urlencode 'updatedAtTo=2026-10-01T00:00:00.000Z' \
      --data-urlencode 'limit=5000'
    ```

    Store what you pull, and decide which timestamp assigns a session to an invoice period, such as `endedAt`. Apply that choice everywhere so a session never lands in two periods.
  </Step>

  <Step title="Keep the sessions you invoice">
    Keep CDRs whose `paymentMethod` is `Invoice`. Sessions paid another way, in an app, at a payment terminal, or through a roaming partner, have already been paid for, and invoicing them again would charge twice.

    The `filter` parameter doesn't accept `paymentMethod`, so apply this rule after you've pulled the records. Sessions with `paymentMethod` `Free` are yours to decide on, depending on how you charge for them.
  </Step>

  <Step title="Build the invoice lines">
    Group the kept CDRs by customer and `price.currency`, and within that by `price.vatRate`. For each line, take:

    | Line field        | From the CDR                                                  |
    | ----------------- | ------------------------------------------------------------- |
    | Quantity          | `consumed` (kWh)                                              |
    | Net amount        | `price.amountExVat`                                           |
    | VAT rate          | `price.vatRate`, as a fraction: `0.25` is 25%                 |
    | Gross amount      | `price.amount`                                                |
    | Cost centre       | `auth.idTag.billingReference`                                 |
    | Site reference    | The location's `billingReference`, looked up by `location.id` |
    | Driver or vehicle | `auth.idTag.label`                                            |
    | Traceability      | `transactionId`                                               |

    Use the amounts on the CDR rather than recalculating them from the tariff. `price.breakdown` shows how a price was arrived at, if a customer asks.
  </Step>
</Steps>

## Verify

<Check>
  Build lines for one customer and one closed month, then export that customer's CDRs for the same month from **Charge detail records** in Spirii Connect. The session count, total kWh, and net amount match your ERP's lines once you apply the same `paymentMethod` rule to the export.
</Check>

## Handle corrected CDRs

A CDR can change after you first pull it. When a faulty session's price is corrected, the record is recalculated and its `updatedAt` moves. Keep pulling by `updatedAt` after a period closes, compare against what you've already invoiced, and raise the difference as a credit or adjustment in your ERP rather than editing an issued invoice.

## Home charging reimbursement

If employees are reimbursed for home charging through payroll, the ERP that runs payroll picks up each month's approved expense report. See [Home charging reimbursement](/capabilities/billing-payouts/home-charging-reimbursement) for how reports are produced and approved.

The Reimbursement API authenticates with the same API key, from its own base URL: `https://api.spirii.com/reimbursement`.

<Steps>
  <Step title="List approved reports">
    Filter by status, and by fleet customer if you handle more than one.

    ```bash theme={null}
    curl "https://api.spirii.com/reimbursement/v1/expense-reports?status=Approved&customerCrmId=4567&limit=100" \
      -H "Authorization: Bearer <SPIRII_API_KEY>"
    ```

    | Status          | Means                                        |
    | --------------- | -------------------------------------------- |
    | `Active`        | The current month, still collecting sessions |
    | `Pending`       | Ready for approval                           |
    | `Approved`      | Approved and ready for payroll               |
    | `FundsReceived` | Approved and paid                            |
  </Step>

  <Step title="Post each employee's amount">
    Fetch the report to get its expenses, one per employee. `recipientExternalId` is the `externalId` on the employee's customer record, which makes it the key to your payroll system. `amountInCents` is the amount to pay and `currency` its currency.

    For the report as a file, download it with `format=csv` or `format=pdf` from [Download expense report](https://docs.spirii.com/api-reference/reimbursement-expenses/download-expense-report).
  </Step>
</Steps>

A report can be approved either in Spirii Connect or with [Approve expense report](https://docs.spirii.com/api-reference/reimbursement-expenses/approve-expense-report). Approving through the API stores the report and notifies its email recipients, so approve only once the fleet manager has checked it.

## Best practices

* **Mind the units.** The Reimbursement API returns amounts in cents and energy in watt-hours. CDRs use decimal amounts and kilowatt-hours. Convert before combining the two.
* **Keep `transactionId` on every line.** It traces a line back to the session behind it when a customer queries an invoice.
* **Store CDRs locally.** A CDR request returns at most 5,000 records and the API allows 120 requests per minute. Pull incrementally and build invoices from your own copy. See [Rate limits](/developers/rate-limits).
* **Page through completely.** CDRs page by cursor; follow it to the end. See [Pagination](/developers/pagination).
* **Split by currency.** A customer charging in several countries can produce sessions in more than one currency. Invoice each currency separately rather than converting.

## Next steps

<CardGroup cols={2}>
  <Card title="CRM integration" icon="users" href="/developers/crm-integration">
    Keep the customer records these invoices depend on in step with your CRM.
  </Card>

  <Card title="Reporting and dashboards" icon="chart-column" href="/developers/reporting-and-dashboards">
    The retrieval patterns for storing and aggregating CDRs.
  </Card>
</CardGroup>
