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

# Reconciliation

> Match Grid transactions with your internal systems

This guide explains how to reconcile transactions between your internal systems and the Grid API using two complementary mechanisms: real-time webhooks and periodic queries.

<Tip>
  Use webhooks for real-time updates and daily queries as a backstop to detect missed events or data drift.
</Tip>

## Handling webhooks

Listen for transaction webhooks to track transaction status change until a terminal state is reached.

<Info>
  Expected terminal statuses for outgoing transactions: `COMPLETED`, `FAILED`, `EXPIRED`. However, transitions between these can occur (e.g., a bank return moves `COMPLETED` → `FAILED`). Also listen for `OUTGOING_PAYMENT.REFUND_COMPLETED` and `OUTGOING_PAYMENT.REFUND_FAILED` to track refunds on failed transactions.
</Info>

* **Outbound transactions**: The originating account is debited at transaction creation. If the transaction ultimately fails, a refund is posted back to the originating account.
* **Inbound transactions**: The receiving account is credited only on success. Failures do not change balances.

<Tip>
  Grid retries failed webhooks up to 160 times over 7 days with exponential backoff. Use the dashboard to review and remediate webhook delivery issues.
</Tip>

<Steps>
  <Step title="Subscribe and verify signatures">
    Configure your webhook endpoint and verify signatures. See <a href="/global-p2p/platform-tools/webhooks">Webhooks</a>.

    Sample webhook payload:

    ```json theme={null}
    {
      "id": "Webhook:019542f5-b3e7-1d02-0000-0000000000ab",
      "type": "OUTGOING_PAYMENT.COMPLETED",
      "timestamp": "2025-10-03T15:30:01Z",
      "data": {
        "id": "Transaction:019542f5-b3e7-1d02-0000-000000000030",
        "status": "COMPLETED",
        "type": "OUTGOING",
        "source": {
          "sourceType": "ACCOUNT",
          "accountId": "InternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965"
        },
        "destination": {
          "destinationType": "ACCOUNT",
          "accountId": "ExternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123"
        },
        "sentAmount": {
          "amount": 10000,
          "currency": { "code": "USD", "symbol": "$", "decimals": 2 }
        },
        "receivedAmount": {
          "amount": 9200,
          "currency": { "code": "EUR", "symbol": "€", "decimals": 2 }
        },
        "customerId": "Customer:019542f5-b3e7-1d02-0000-000000000001",
        "platformCustomerId": "customer_12345",
        "createdAt": "2025-10-03T15:00:00Z",
        "settledAt": "2025-10-03T15:30:00Z",
        "description": "Payment for services - Invoice #1234"
      }
    }
    ```
  </Step>

  <Step title="Process events idempotently">
    Use the envelope `id`, `data.id`, and `timestamp` to ensure idempotent handling, updating your internal ledger on each status transition.
  </Step>

  <Step title="Recognize terminal states">
    When a transaction reaches a terminal state, finalize your reconciliation for that transaction.
  </Step>
</Steps>

## Reconcile via queries

Additionally, you can list transactions for a time window and compare with your internal records.

<Note>
  We recommend querying days from `00:00:00.000` to `23:59:59.999` in your preferred timezone.
</Note>

```bash cURL theme={null}
curl -X GET 'https://api.lightspark.com/grid/2025-10-13/transactions?startDate=2025-10-01T00:00:00.000Z&endDate=2025-10-01T23:59:59.999Z&limit=100' \
  -H 'Authorization: Basic $GRID_CLIENT_ID:$GRID_CLIENT_SECRET'
```

Response

```json theme={null}
{
  "data": [
    {
      "id": "Transaction:019542f5-b3e7-1d02-0000-000000000030",
      "status": "COMPLETED",
      "type": "OUTGOING",
      "source": {
        "sourceType": "ACCOUNT",
        "accountId": "InternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965"
      },
      "destination": {
        "destinationType": "ACCOUNT",
        "accountId": "ExternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123"
      },
      "sentAmount": {
        "amount": 10000,
        "currency": { "code": "USD", "symbol": "$", "decimals": 2 }
      },
      "receivedAmount": {
        "amount": 9200,
        "currency": { "code": "EUR", "symbol": "€", "decimals": 2 }
      },
      "customerId": "Customer:019542f5-b3e7-1d02-0000-000000000001",
      "platformCustomerId": "customer_12345",
      "description": "Payment for services - Invoice #1234",
      "exchangeRate": 0.92,
      "settledAt": "2025-10-03T15:30:00Z",
      "createdAt": "2025-10-03T15:00:00Z"
    }
  ],
  "hasMore": true,
  "nextCursor": "eyJpZCI6IlRyYW5zYWN0aW9uOjAxOTU0MmY1LWIzZTctMWQwMi0wMDAwLTAwMDAwMDAwMDAzMCJ9",
  "totalCount": 45
}
```

## Troubleshooting

* **Missing webhook**: Check delivery logs in the dashboard and ensure your endpoint returns `2xx`. Retries continue for 7 days.
* **Mismatched balances**: Re-query the date range and verify terminal statuses; remember outbound failures are refunded, inbound failures do not change balances.
* **Pagination gaps**: Always follow `nextCursor` until `hasMore` is `false`.
