Pipelines
ETL pipelines that transform source data and load it into Pact objects — companies, contacts, events, deals, tags — with per-run history.
Pipelines
A pipeline takes data from a source, applies a transform, and loads the
result into a Pact object. Pipelines are managed at /v1/etl/pipelines
(backed by the etl_pipelines + etl_runs tables, alembic 0098_etl_pipelines)
and listed in the app under Data → Pipelines.
Each pipeline row holds its definition plus a rolled-up snapshot of its most
recent run (last_run_at, last_run_status), and every run is its own
etl_runs row.
Pipelines can't run yet
Pipeline CRUD is real and tenant-isolated, but Pact has no ETL executor:
nothing reads a pipeline's source, applies its transform or loads its
destination. So Run is not offered. POST /v1/etl/pipelines/{id}/runs
answers status: "unsupported" with a gap that says what is missing and what
you can do instead, and it writes nothing: no run row and no last-run snapshot.
- If the pipeline's source is Salesforce, HubSpot or Pipedrive, that source's Sync now (Data → Sources) runs the real connector and reports the records it imported and updated.
- Otherwise, the import wizard (Admin → Import) loads a file and reports the rows it wrote.
An earlier build recorded simulated runs with invented counts. Those rows are kept, but they are reported as Not measured, with no counts, timings or log. Seeded sample pipelines keep their figures, labeled Sample.
Destinations
A pipeline's destination is the Pact object it loads into, validated against a
fixed allowlist (ALLOWED_DESTINATIONS):
companies · contacts · events · opportunities · tags ·
tracking_events · custom
Pipelines carry a schedule field (default manual) and a user-settable
status of active or paused. The schedule value is stored, but nothing
dispatches scheduled runs, and nothing executes a run.
Endpoints
POST /v1/etl/pipelines create
GET /v1/etl/pipelines list
GET /v1/etl/pipelines/{id} fetch one
PATCH /v1/etl/pipelines/{id} update
DELETE /v1/etl/pipelines/{id} delete + cascade runs
GET /v1/etl/pipelines/{id}/runs paginated run history
POST /v1/etl/pipelines/{id}/runs run, or refuse with a gap (no executor yet)
curl -X POST https://api.pact.place/v1/etl/pipelines \
-H "Authorization: Bearer $PACT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Salesforce → Contacts","destination":"contacts","transform":{}}'
A pipeline optionally references a source_id; the transform is stored as
transform_json. Deleting a pipeline cascades its etl_runs rows.