# Data export

Executive summary
**The Portfolio Data Export Service generates reconciliation-grade financial reports from Ripple Custody as downloadable CSV or JSON files.**

- The service offers two report types: **Position Reports** (point-in-time balance snapshots) and **Movement Reports** (transaction history over a date range).
- Every export includes request metadata and financial control totals, so you can prove a file is complete and untampered.
- The service exposes REST endpoints only, so you can automate extractions from your own scheduled jobs.
- The service enforces access per domain: you receive data only for domains where you hold a role with read access.


Why this matters
Finance, Compliance, and Operations teams need a standardized, auditable way to extract cross-system data for daily reconciliation, regulatory reporting, and audit evidence. The export service replaces custom database queries and one-off scripts with a single, consistent data contract that feeds your core banking system, data lake, and reconciliation pipelines directly—without post-processing.

**For architects and operators**: Column order, names, and types are fixed contracts. Schema-breaking changes trigger a version bump and a changelog entry, so you can build stable downstream pipelines against these reports.

Availability
The export service delivers REST APIs only in this release. A UI export experience and additional report types are planned for later phases. The service integrates Ripple Custody as its first data source.

## What you can export

The service provides two report types. Each report is a separate endpoint that returns a single file per request.

| Report | What it contains | Use it to |
|  --- | --- | --- |
| [Position Report](/products/custody/data-export/position-report) | A point-in-time balance snapshot. Each row is one account-and-asset balance as of a timestamp you choose. | Verify end-of-day balances against your core systems, calculate regulatory capital, and generate tax reporting. |
| [Movement Report](/products/custody/data-export/movement-report) | A transaction history for a date range. Each row is one transfer, including amounts, fees, on-chain details, and counterparties. | Reconcile movements for specific audit periods, remediate reconciliation breaks, and satisfy tax reporting requirements. |


## How the service works

You request a report by sending an authenticated `POST` request to the relevant endpoint with your scope and filters in the request body. The service authorizes the request, gathers the data, converts every financial value to human-readable decimal form, computes control totals, and returns the result as a CSV or JSON file.


```mermaid
flowchart LR
    A["Your service or job"] -->|"1. POST request with filters"| B["Export service"]
    B -->|"2. Verify domain access"| C["Authorization"]
    C -->|"3. Gather data"| D["Balances and transactions"]
    D -->|"4. Convert decimals + sum control totals"| E["Report builder"]
    E -->|"5. Return CSV or JSON"| A
```

1. **Request**: You send a `POST` request with a bearer token and a JSON body that defines the target domain, scope, and filters.
2. **Authorize**: The service verifies that you hold a role with read access in the target domain. It checks access *before* running any data query.
3. **Gather data**: The service reads balances or transactions for the accounts in scope. Position balances are sourced point-in-time; movement data reflects recorded transfers.
4. **Convert and verify**: The service converts every financial value from its raw blockchain denomination to its native decimal unit, and sums each financial column into a control total.
5. **Return**: The service returns the report as a single file with a metadata header.


## Key concepts

### Export metadata

Every export carries a metadata header that identifies who generated it and with what parameters. This gives you a self-describing, auditable artifact.

| Field | Description |
|  --- | --- |
| Export ID | A UUID for the export. The service also returns this value in the `X-Export-Id` response header for support tracing. |
| Request author | The identity that generated the export, in `providerId:loginId` form. |
| Generation timestamp | The UTC time when the service generated the export. |
| Filters | The exact set of filters the service applied to the request. |
| Record count | The number of rows in the report. |
| Control totals | Financial column sums for reconciliation. See [Control totals](#control-totals). |


### Control totals

Every export includes financial control totals—the sums of each monetary column, computed as the service builds the file. This is a banking-standard integrity check.

When your downstream system ingests a report, it re-sums the same columns and compares its result against the control totals in the metadata header. If the totals and the record count match, the file is complete and uncorrupted. If they diverge, your system can reject the file and request a new export. Because the totals travel inside the file, you can verify integrity without calling back to the service.

Control totals are integrity checksums, not real-world monetary values. A single total can aggregate rows across multiple assets with different decimal scales, so the number doesn't represent a portfolio value or a per-asset total. Use it only to confirm that your extract matches the source, by re-summing the same column and comparing.

### Financial precision

The service exports all amounts as decimal strings in the asset's native unit, with precision matching the asset's decimal places—for example, `3.000000` XRP rather than `3000000` drops. It never exports raw blockchain denominations (except the Movement Report's explicit `rawTransactionValue` column) or scientific notation.

Financial values are always **strings**, in both CSV and JSON. Parse them as strings, never as floating-point numbers: bare numbers lose precision beyond roughly 15 significant digits, and some assets carry many more decimal places than that. For details, see [Financial precision](/products/custody/data-export/reference#financial-precision).

### Domain scope and access control

The service checks access against the **target domain only**. To generate a report for a domain, you must hold a profile in that exact domain with a role that grants read access to the relevant entity type—accounts for Position Reports, transactions for Movement Reports. A profile in a parent domain doesn't grant access to its children.

To consolidate data across a domain tree, set `includeChildDomains` to `true`. The service checks each child domain individually and includes only the ones you can access. It silently omits children you can't access—you receive a valid report for the domains you're entitled to.

For the full access model, see [Access control](/products/custody/data-export/reference#access-control).

### Output formats

The service provides two machine-readable formats. Select one with the `format` field:

- **CSV**: UTF-8 with a byte order mark for spreadsheet compatibility. Financial values are quoted strings.
- **JSON**: A metadata envelope with a `data` array of row objects.


For the full format specification, see [Output formats](/products/custody/data-export/reference#output-formats).

## Next steps

| Page | Description |
|  --- | --- |
| [Position Report](/products/custody/data-export/position-report) | Generate a point-in-time balance snapshot, including request fields, filters, and output columns. |
| [Movement Report](/products/custody/data-export/movement-report) | Generate a transaction history for a date range, including status filters and output columns. |
| [Export reference](/products/custody/data-export/reference) | Look up output formats, financial precision rules, access control, operational limits, and error responses. |