Ludex — trusted-data egress (Parquet exports)
For incremental, row-by-row reads, use the pull API (GET /v1/trusted/events). For bulk analytics workloads, Ludex writes Parquet objects on a schedule and exposes them through a manifest + signed URL API on the same ludex-egress service.
Exports honour the same trusted-export policy and trust_origin semantics as the pull API: only validated or governed-recovered rows are included, according to the policy configured for your (organization, project, environment) scope.
Authentication
Same as the pull API:
Authorization: Bearer <your-api-key>
Requires the read:trusted scope on a credential pinned to a single (organization_id, project_id, environment_id).
List completed export runs
GET /v1/trusted/exports
Returns recent ExportRun rows and their Parquet objects for your credential scope only. Query parameters cannot widen scope — they may only narrow or filter.
| Parameter | Default | Purpose |
|---|---|---|
project_id |
credential's project | Must match the credential (or be omitted). |
environment_id |
credential's environment | Must match the credential (or be omitted). |
status |
succeeded |
Filter by run status; pass all to include non-success terminal states. |
limit |
50 |
Page size (1–500). |
Example response (abbreviated)
{
"status": "ok",
"data": [
{
"run_id": 42,
"status": "succeeded",
"row_count": 120000,
"byte_count": 8450000,
"object_count": 1,
"from_timestamp": "2026-04-20T00:00:00Z",
"to_timestamp": "2026-04-20T01:00:00Z",
"policy_hash": "...",
"objects": [
{
"object_id": 99,
"object_key": "trusted/org/proj/env/2026/04/20/part-000.parquet",
"row_count": 120000,
"byte_count": 8450000,
"sha256": "..."
}
]
}
],
"scope": {
"organization_id": "org_abc",
"project_id": "proj_xyz",
"environment_id": "env_prod"
}
}
Download a Parquet object (signed URL)
URLs are not returned from the list endpoint. Mint a short-lived presigned GET per object:
POST /v1/trusted/exports/{run_id}/objects/{object_id}/url
| Parameter | Default | Purpose |
|---|---|---|
ttl_seconds |
service default | URL lifetime (60–86400 seconds). |
Example
curl -sS -X POST \
-H "Authorization: Bearer $LUDEX_TRUSTED_API_KEY" \
"https://api.ludex.example.com/v1/trusted/exports/42/objects/99/url"
{
"status": "ok",
"data": {
"issuance_id": 1001,
"url": "https://storage.example.com/...",
"expires_at": "2026-04-20T13:15:00Z",
"ttl_seconds": 900
}
}
Download the file with a normal HTTP GET to url before expires_at. Each issuance is audited server-side (signed_url_issuance).
Errors
| HTTP | code |
Meaning |
|---|---|---|
| 401 | auth_failed |
Missing or invalid Bearer token. |
| 403 | project_mismatch / environment_mismatch |
Query scope does not match the credential. |
| 404 | export_run_not_found |
Run id not visible in your scope. |
| 404 | export_object_not_found |
Object id not in the run (also used to avoid cross-tenant leaks). |
When to use pull vs Parquet
| Workload | Surface |
|---|---|
| Near-real-time sync, small pages, custom ETL | Pull API |
| Warehouse load, Spark/DuckDB, hourly/daily batches | Parquet exports (this page) |