API reference

Automation & CI

A working pipeline, plus the list endpoints that let a job answer 'what ran, and did it work?'

Everything here works with an API key. No browser, no session.

A working GitHub Actions job

name: Seed test data
on:
  workflow_dispatch:
  schedule:
    - cron: '0 2 * * *'

jobs:
  seed:
    runs-on: ubuntu-latest
    steps:
      - name: Push test data
        env:
          SEEDQL_KEY: ${{ secrets.SEEDQL_KEY }}
          TARGET_DSN: ${{ secrets.STAGING_DSN }}
        run: |
          set -euo pipefail
          API=https://seedql-production.up.railway.app

          RESPONSE=$(curl -sS -X POST "$API/api/generate/push" \
            -H "Authorization: Bearer $SEEDQL_KEY" \
            -H "Content-Type: application/json" \
            -d "{
              \"connection\": { \"db_type\": \"postgresql\", \"connection_string\": \"$TARGET_DSN\" },
              \"tables\": [
                { \"table_name\": \"users\",  \"row_count\": 1000, \"enabled\": true },
                { \"table_name\": \"orders\", \"row_count\": 8000, \"enabled\": true }
              ],
              \"truncate_first\": true
            }")

          echo "$RESPONSE"

          # Fail the job on a partial or empty write, not just on HTTP status.
          echo "$RESPONSE" | jq -e '.pushed_to_db == true' > /dev/null
          echo "$RESPONSE" | jq -e '.total_rows == .requested_rows' > /dev/null

          # Record the seed so this exact dataset can be reproduced.
          echo "seed=$(echo "$RESPONSE" | jq -r '.seed // "n/a"')" >> "$GITHUB_STEP_SUMMARY"

The two jq -e assertions matter. A push that writes nothing still returns 200; pushed_to_db is what tells you whether rows landed.

Long-running pushes

Above roughly 100,000 rows, use the async path so the job is not holding an HTTP connection:

JOB=$(curl -sS -X POST "$API/api/generate/push-async" \
  -H "Authorization: Bearer $SEEDQL_KEY" -H "Content-Type: application/json" \
  -d "$PAYLOAD" | jq -r .job_id)

while :; do
  STATUS=$(curl -sS "$API/api/jobs/$JOB" -H "Authorization: Bearer $SEEDQL_KEY" | jq -r .status)
  case "$STATUS" in
    completed) echo "done"; break ;;
    failed|cancelled) echo "job $STATUS"; exit 1 ;;
    *) sleep 5 ;;
  esac
done

Reading what happened

Four org-scoped list endpoints exist so a job can answer questions in one request instead of walking every project.

GET /api/generations?org_id=…      # run history
GET /api/snapshots?org_id=…        # captures, including scheduled ones
GET /api/schedule-runs?org_id=…    # every scheduled fire
GET /api/activity?org_id=…         # the audit stream

All accept limit (max 500) and offset; generations and snapshots also accept project_id, and generations and schedule-runs accept status.

Did last night's scheduled backups fail?

curl -s "$API/api/schedule-runs?org_id=$ORG&status=error" \
  -H "Authorization: Bearer $SEEDQL_KEY" | jq length

Did anything fail to generate today?

curl -s "$API/api/generations?org_id=$ORG&status=failed&limit=20" \
  -H "Authorization: Bearer $SEEDQL_KEY"

These lists are restricted to projects you can actually open. If a project has an explicit member roster and you are not on it, its rows never appear, even though you are in the org, and even if you name the project explicitly.

Reproducing a run

Every generation returns the seed it used. Given the same seed and the same table config, you get the same rows.

curl -s "$API/api/generations?org_id=$ORG&limit=1" \
  -H "Authorization: Bearer $SEEDQL_KEY" | jq '.[0].seed'

Feed that back as "seed": <value> to recreate the dataset a failing test ran against. This is the difference between a bug report and a rumour.

Practical notes

Store the key as a secret, never in the repo. It carries your permissions.

Use one key per pipeline, named for its consumer. Revoking one then does not break the others, and last_used_at tells you which are actually live.

A 503 with Retry-After means the backend is briefly saturated. Honour the header and retry; it is not a failure.

Rate limits apply per account. Sustained parallel pushes from many jobs will hit them; stagger schedules rather than firing every pipeline at midnight.