Automate with the API and CI

Keep recipes in your repository, next to the tests that use them, and let CI generate fresh data before the suite runs.

1. Create a key for the job

In Account → API keys, create a key for this pipeline only:

  • Scopes: generate and jobs:read — nothing else.
  • Valid for: as short as your rotation allows; at most 90 days.
  • Credit limit: what the pipeline may spend in total. A runaway loop stops there instead of draining your balance.

Store it as a CI secret, for example GB_KEY. The key is shown once; if it leaks, revoke it and create another.

2. A reusable script

scripts/generate.sh
#!/usr/bin/env sh
# Usage: generate.sh recipe.yaml output-file
set -eu
API=https://api.ghostbakery.com
AUTH="Authorization: Bearer $GB_KEY"

job=$(curl -fsS "$API/api/v1/generate" -H "$AUTH" \
  -H "Content-Type: application/x-yaml" --data-binary @"$1" | jq -r .job_id)

for _ in $(seq 120); do
  status=$(curl -fsS "$API/api/v1/jobs/$job" -H "$AUTH" | jq -r .status)
  case "$status" in
    completed) curl -fsS "$API/api/v1/jobs/$job/download" -H "$AUTH" -o "$2"; exit 0 ;;
    failed|expired) curl -fsS "$API/api/v1/jobs/$job" -H "$AUTH" | jq -r .error >&2; exit 1 ;;
  esac
  sleep 1
done
echo "timed out waiting for job $job" >&2; exit 1

curl -f turns HTTP errors into a failed step. A recipe that does not validate returns 422 with every problem listed, so CI fails before spending anything.

3. Wire it into CI

.github/workflows/test.yml
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Generate fixtures
        env:
          GB_KEY: ${{ secrets.GB_KEY }}
        run: sh scripts/generate.sh testdata/customers.yaml testdata/customers.csv
      - name: Test
        run: make test

Good practice

  • Assert invariants, not values. Every run draws new values. Check formats, uniqueness and relationships, not specific names.
  • Generate once per pipeline. Hosted generation belongs in setup or integration stages; unit tests can read the file it produced.
  • Download promptly. Results expire a while after the job completes.
  • Check the cost as you grow. POST /api/v1/estimate returns the exact cost; put it in a pre-merge check when recipes change often.
  • Failures cost nothing. A job that fails is refunded, and the error is in the job status.

See the API reference for every endpoint and scope.