Skip to Content
Reconciliation

Reconciliation

Reconciliation compares the virtual balances in our ledger with the balances that you report. Its purpose is to find a drift between the two sides within hours, before it grows. This page explains when reconciliation runs, what it compares and where you read the result.

When it runs

Reconciliation runs for every tenant on two schedules:

  • Hourly incremental run. It compares only the accounts that had movements since the last completed run. A drift is found within one hour at the latest.
  • Daily full run. It compares all the user accounts of your tenant. It covers the accounts that the incremental run skipped, and it covers a missed hourly run.

You do not need to wait for reconciliation to get an instant comparison. Every balance-sync response returns the resulting balance on our side. Compare this value with your own record (Getting started).

What it compares

The basis of the comparison is the resulting_balance field that you send in balance syncs. This field is the balance that your system shows after the movement.

For an account, we take the last resulting_balance that you sent. To this value we add the movements that happened on our side after that sync: position openings, position settlements and market void refunds. If the result is not equal to the balance in our ledger, we open a reconciliation discrepancy for the account. Balance syncs that you sent after that sync are not part of the sum, because your next resulting_balance already includes them.

A debit movement that we rejected with 409 would_overdraw always opens a discrepancy. This rejection shows that the views of the two sides already differ (FAQ).

Accounts with no resulting_balance

If you never sent a resulting_balance for an account, there is no balance to compare. Reconciliation treats this account as unverifiable. An unverifiable account is not a discrepancy: we open no discrepancy record and we send no webhook. The status appears once in the reconciliation report as “unverifiable” and is not repeated in every run.

To make your accounts verifiable, send resulting_balance in every balance sync.

When a discrepancy is found

When reconciliation finds a discrepancy, it sends you the reconciliation.discrepancy event. The Webhook guide explains what you must do.

We do not report an open discrepancy again in every run. While an account has an open discrepancy, later runs open no new discrepancy record for it and send no new event. If the drift continues after our team resolves the discrepancy, the next run finds it again and reports it to you again.

Where you read the result

The result of reconciliation is in the reconciliation_statement report. This report is an account statement: the opening balance, the ledger movements of the period in order, the closing balance and the list of discrepancies of the period. You can request the report for one user or for the total of your tenant.

You can request the report in two ways:

  • From the Reports screen of the tenant portal. The Settlement screen of the portal shows the statement for the total of your tenant.
  • With POST /v1/reports, using a key that has the read:reports scope. For the statement of one user, give the external_user_id filter.

We generate the report in the background. When it is ready, the report.ready event arrives. You can also poll the status with GET /v1/reports/{id}. The report downloads in JSON or CSV format. The API reference has the details.

The go-live item

The Go-live checklist asks for one clean reconciliation run: at least one full scheduled run over your sandbox traffic, with zero discrepancies. You show it in sandbox like this:

  1. Register users in sandbox and send balance syncs. Send resulting_balance in every sync. If you do not, the accounts stay unverifiable.
  2. Open positions on the sandbox markets and watch them settle.
  3. Wait for one daily full run to pass.
  4. Request the reconciliation_statement report for the total of your tenant, for the period that the run covers. The discrepancy list must be empty.

During this time, no reconciliation.discrepancy event must arrive. Our team verifies the item from the sandbox run records.

Last updated on