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

# Validate a sales data backfill

> Compare source-system sales totals with Layer after a sync or backfill.

After backfilling invoices and payments, compare your source system with Layer to confirm two things:

<CardGroup cols={2}>
  <Card title="Data completeness" icon="list-check">
    Every record in the intended date range was sent, without missing or duplicate invoices, refunds, or payments.
  </Card>

  <Card title="Data consistency" icon="scale-balanced">
    The financial totals calculated from those records agree across your system and Layer's accounting representations.
  </Card>
</CardGroup>

Layer's [data sync validation endpoint](/api-reference/v1/fetch-data-sync-validation-totals) returns a compact set of totals for this comparison.

<Note>
  Amounts returned by Layer are integer cents. Calculate your source-system totals in the same unit and use the exact same date boundaries for both sides of every comparison.
</Note>

## Validation workflow

<Steps>
  <Step title="Complete the backfill">
    Import the full set of invoices, refunds, payments, and related sales data for the period you want to validate. Record the exact `start_date` and `end_date` boundaries used for the backfill.

    See [Sales / AR data](/guides/importing-sales-ar-data) for the available invoice, payment, refund, and payout workflows. For large imports, use [Bulk create invoices](/api-reference/v1/bulk-create-invoices) and [Bulk create invoice payments](/api-reference/v1/bulk-create-invoice-payments) where appropriate.
  </Step>

  <Step title="Calculate invoice totals in your system">
    Pull every invoice or sales receipt in the synced period, regardless of payment status. Calculate the following totals:

    * **`TOTAL_SALES`** — Sum all invoice totals.
    * **`CUSTOMER_REFUNDS`** — Sum refunds issued against invoices. Do not include refunded payments that left the invoice open.
    * **`TIPS`** — Sum tips included on invoices.
    * **`DISCOUNTS`** — Sum invoice-level and line-item discounts.
    * **`SALES_TAXES`** — Sum sales taxes reported on invoices.
    * **`NET_REVENUE`** — Calculate `TOTAL_SALES - CUSTOMER_REFUNDS - DISCOUNTS - TIPS - SALES_TAXES`.

    These fields use **accrual accounting** in Layer. They reflect invoiced activity during the period and do not depend on whether an invoice has been paid.
  </Step>

  <Step title="Calculate payment processing fees">
    Pull the payments collected in the synced period and sum the processing fees reported on those payments.

    Compare this result with **`PAYMENT_PROCESSOR_FEES`**. This field uses the **cash basis** because it reflects fees on collected payments. It does not include hypothetical fees on invoices for which no payment was collected.
  </Step>

  <Step title="Fetch and compare Layer's totals">
    Call the validation endpoint with the same boundaries used for your source-system calculations:

    ```bash Request theme={null}
    curl --request GET \
      --url 'https://sandbox.layerfi.com/v1/businesses/{businessId}/reports/data-sync-validation?start_date=2026-01-01T00:00:00Z&end_date=2026-07-01T00:00:00Z' \
      --header 'Authorization: Bearer <access_token>'
    ```

    The response identifies the report and accounting basis used for each total:

    ```json Response theme={null}
    {
      "data": {
        "type": "Data_Sync_Validation_Report",
        "business_id": "83d8fb80-31ee-4d57-b684-44b4aaa5e01f",
        "start_date": "2026-01-01T00:00:00Z",
        "end_date": "2026-07-01T00:00:00Z",
        "totals": [
          {
            "field": "TOTAL_SALES",
            "description": "Total sales should match the sum of all invoice totals sent over the period. This statistic does not consider payments, only the invoiced amounts.",
            "value": 1250000,
            "generated_by": {
              "report": "PROFIT_AND_LOSS",
              "reporting_basis": "ACCRUAL"
            }
          },
          {
            "field": "CUSTOMER_REFUNDS",
            "description": "Customer refunds should reflect the total of refunds issued against invoices. Refunded payments that left invoices open are not included.",
            "value": 25000,
            "generated_by": {
              "report": "PROFIT_AND_LOSS",
              "reporting_basis": "ACCRUAL"
            }
          },
          {
            "field": "TIPS",
            "description": "Tips should match the sum of all tips included on all invoices over the period. Ignore invoice payment status.",
            "value": 10000,
            "generated_by": {
              "report": "BALANCE_SHEET",
              "reporting_basis": "ACCRUAL"
            }
          },
          {
            "field": "DISCOUNTS",
            "description": "Discounts should reflect the total of invoice and individual line item discounts on all invoices sent over the period. Invoice payment status is not considered.",
            "value": 15000,
            "generated_by": {
              "report": "PROFIT_AND_LOSS",
              "reporting_basis": "ACCRUAL"
            }
          },
          {
            "field": "SALES_TAXES",
            "description": "Total sales taxes reported on invoices across the period. Invoice payment status is not considered.",
            "value": 100000,
            "generated_by": {
              "report": "BALANCE_SHEET",
              "reporting_basis": "ACCRUAL"
            }
          },
          {
            "field": "PAYMENT_PROCESSOR_FEES",
            "description": "Payment processor fees should match the total reported fees on payments. Fees on invoices with no payment collected are not included.",
            "value": 30000,
            "generated_by": {
              "report": "PROFIT_AND_LOSS",
              "reporting_basis": "CASH"
            }
          },
          {
            "field": "NET_REVENUE",
            "description": "Topline sales less customer refunds, discounts, tips, and sales taxes.",
            "value": 1100000,
            "generated_by": {
              "report": "PROFIT_AND_LOSS",
              "reporting_basis": "ACCRUAL"
            }
          }
        ]
      }
    }
    ```

    Compare each field independently. Matching only `NET_REVENUE` can hide offsetting differences between sales, refunds, discounts, tips, or taxes.
  </Step>
</Steps>

## Investigate a difference by bisecting the period

If a total differs, narrow the problem by repeatedly splitting the date range:

1. Divide the mismatched period into two non-overlapping date ranges.
2. Recalculate the source-system total and call the validation endpoint for each half.
3. Keep the half containing the difference and split it again.
4. Repeat until the range is small enough to inspect individual records.

This is well suited to an automated agent: give it the original boundaries, the mismatched field, and access to both totals, then have it bisect until it finds a small set of example records.

<Warning>
  Use identical boundaries on both systems at every iteration. Check records exactly on each boundary, timezone conversion, duplicate or missing external IDs, refunds that leave invoices open, and payment `fee` values before treating a difference as an accounting issue.
</Warning>

## Related documentation

<CardGroup cols={2}>
  <Card title="Data sync validation API" icon="code" href="/api-reference/v1/fetch-data-sync-validation-totals">
    Review request parameters and the complete response schema.
  </Card>

  <Card title="Import sales and AR data" icon="file-invoice-dollar" href="/guides/importing-sales-ar-data">
    Review how invoices, payments, refunds, and payouts flow into Layer.
  </Card>
</CardGroup>
