Skip to content

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)

See also