Skip to main content

Trigger ETL Pipeline via REST API

Zynexa Semantic Layer Architecture

Zynexa exposes an async REST API to trigger ingester, dbt, and full pipeline runs without SSH access. Jobs run in the background — fire the trigger, get a jobId, and poll for status.

Prerequisites
  • PIPELINE_ENABLED=true in .env.production
  • Lakehouse DB running (docker compose --profile lakehouse up -d lakehouse-db)

See Pipeline Orchestration for all configuration variables.


Quick Start

# On the target server, use localhost (Zynexa listens on port 3000)
BASE=http://localhost:3000

# Or from a remote machine, use the server IP
# BASE=http://{IP_ADDRESS}:3000

# 1. Trigger full pipeline (ingester + dbt)
curl -s -X POST "$BASE/api/data-analytics/pipeline/trigger" \
-H "Content-Type: application/json" \
-d '{"pipeline": "full"}' | jq .

# 2. Poll for completion
curl -s "$BASE/api/data-analytics/pipeline/trigger?jobId=<jobId>" | jq .
Testing on the server

SSH into the server and use http://localhost:3000 directly — no DNS or reverse proxy needed. This is the simplest way to verify the pipeline API is working.


Trigger Request

POST /api/data-analytics/pipeline/trigger

Request Body

FieldTypeRequiredDefaultDescription
pipelinestringYes"ingester", "dbt", or "full"
commandstringNo"daily"dbt command: "daily", "run", "build", "test", "deps", "elementary"
enableOpenlineagebooleanNoServer defaultOverride ENABLE_OPENLINEAGE for this run
enableElementarybooleanNoServer defaultOverride ENABLE_ELEMENTARY for this run

Pipeline Types

TypeWhat it runsTypical duration
ingesterDLT ingester → Bronze (~46 tables)2–5 min
dbtdbt deps → build → elementary5–15 min
fullIngester first, then dbt (sequential)10–20 min

dbt Commands

CommandWhat it does
dailydbt depsdbt builddbt run --select elementary (default)
rundbt run only (skip tests)
builddbt build (models + tests)
testdbt test only
depsdbt deps only (install packages)
elementaryElementary report generation only

Response

The API returns immediately with HTTP 202 Accepted:

{
"success": true,
"output": "Pipeline \"dbt\" started in background.",
"exitCode": -1,
"jobId": "dbt-1710460800000-abc123",
"status": "running"
}

Response Fields

FieldDescription
successtrue when the trigger was accepted, false when the API itself failed
jobIdUnique ID for polling
status"running""completed" or "failed"
exitCodeContainer exit code (-1 while running, 0 = clean, non-zero = pipeline errors)
outputLast 10 KB of container stdout+stderr
success vs exitCode
  • success = whether the trigger command itself worked (container ran to completion)
  • exitCode = pipeline-level result (missing tables, test failures → non-zero)

A job with status: "completed" and exitCode: 1 means the trigger worked but dbt had errors. Check logs for details.


Poll for Status

GET /api/data-analytics/pipeline/trigger?jobId=<jobId>

Completed Successfully

{
"success": true,
"exitCode": 0,
"jobId": "dbt-1710460800000-abc123",
"status": "completed",
"output": "...Finished running 271 models, 197 tests...\nDone. PASS=271 WARN=5 ERROR=0..."
}

Completed with Pipeline Errors

{
"success": true,
"exitCode": 1,
"jobId": "dbt-1710460800000-abc123",
"status": "completed",
"output": "...ERROR=5 (missing bronze tables)..."
}

List All Jobs

GET /api/data-analytics/pipeline/trigger

Returns all active and recently completed jobs (cleaned up after 1 hour).


Example Payloads

All examples use BASE=http://localhost:3000 (run from the target server). Replace with http://{IP_ADDRESS}:3000 for remote access.

Run Ingester Only

curl -s -X POST "$BASE/api/data-analytics/pipeline/trigger" \
-H "Content-Type: application/json" \
-d '{"pipeline": "ingester"}' | jq .

dbt Daily — All Features Enabled (Default)

Runs dbt with OpenLineage (Marquez lineage) and Elementary reports using server defaults:

curl -s -X POST "$BASE/api/data-analytics/pipeline/trigger" \
-H "Content-Type: application/json" \
-d '{
"pipeline": "dbt",
"command": "daily"
}' | jq .

dbt Daily — Without OpenLineage (No Marquez)

Skip lineage emission — uses plain dbt instead of dbt-ol:

curl -s -X POST "$BASE/api/data-analytics/pipeline/trigger" \
-H "Content-Type: application/json" \
-d '{
"pipeline": "dbt",
"command": "daily",
"enableOpenlineage": false
}' | jq .

dbt Daily — Without Elementary

Skip the Elementary report generation step:

curl -s -X POST "$BASE/api/data-analytics/pipeline/trigger" \
-H "Content-Type: application/json" \
-d '{
"pipeline": "dbt",
"command": "daily",
"enableElementary": false
}' | jq .

dbt Daily — Minimal (No Marquez, No Elementary)

Fastest run — plain dbt build only, no lineage, no reports:

curl -s -X POST "$BASE/api/data-analytics/pipeline/trigger" \
-H "Content-Type: application/json" \
-d '{
"pipeline": "dbt",
"command": "daily",
"enableOpenlineage": false,
"enableElementary": false
}' | jq .

dbt Daily — With OpenLineage, Without Elementary

Track lineage in Marquez but skip the Elementary report:

curl -s -X POST "$BASE/api/data-analytics/pipeline/trigger" \
-H "Content-Type: application/json" \
-d '{
"pipeline": "dbt",
"command": "daily",
"enableOpenlineage": true,
"enableElementary": false
}' | jq .

Full Pipeline (Ingester → dbt)

curl -s -X POST "$BASE/api/data-analytics/pipeline/trigger" \
-H "Content-Type: application/json" \
-d '{"pipeline": "full", "command": "daily"}' | jq .

dbt Build Only (Models + Tests, No Elementary)

curl -s -X POST "$BASE/api/data-analytics/pipeline/trigger" \
-H "Content-Type: application/json" \
-d '{"pipeline": "dbt", "command": "build"}' | jq .

Poll Until Done (bash)

JOB_ID="dbt-1710460800000-abc123"

while true; do
RESULT=$(curl -s "$BASE/api/data-analytics/pipeline/trigger?jobId=$JOB_ID")
STATUS=$(echo "$RESULT" | jq -r '.status')
echo "Status: $STATUS"

if [[ "$STATUS" != "running" ]]; then
echo "$RESULT" | jq .
break
fi
sleep 10
done

Toggle Summary

PayloadOpenLineageElementaryUse Case
{} (defaults)Server defaultServer defaultNormal daily run
"enableOpenlineage": falseOffServer defaultSkip Marquez lineage
"enableElementary": falseServer defaultOffSkip report generation
Both falseOffOffFastest — plain dbt only
"enableOpenlineage": true, "enableElementary": falseOnOffLineage only, no report

Error Responses

HTTP StatusMeaning
202Job accepted and running in background
400Invalid pipeline type or dbt command
403PIPELINE_ENABLED=false — pipeline API disabled
404Job ID not found
409Container already running (ingester or dbt)
500Server error

See Also