Pipelines
ETL pipelines that transform source data and load it into Pact objects — companies, contacts, events, opportunities, 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). Every execution attempt is
recorded as its own etl_runs row with full timing, record counts, and a log
payload — so the run history is real even where the execution is simulated.
Execution is an inline simulation today
Pipeline CRUD and the run-history table are fully real and tenant-isolated. The
execute step runs inline as a mock — _run_pipeline_mock() in
api/routes/etl.py inserts a running row, generates records_in /
records_out / records_failed plus a synthetic log, and writes the terminal
status back. No real transform is applied and no records land in the target
object yet. The route contract is stable, so a production dispatcher can replace
the mock without changing the API.
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 there is no
background scheduler dispatching scheduled runs yet — runs are triggered
explicitly via the API or the inline trigger on each pipeline card.
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 enqueue + execute (inline mock)
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.