Sign in

Guides

Start runs from CI

Give your CI a key that can start runs on one project, call one endpoint, and hear back when a person needs to look.

About 10 minutesA workspace admin makes the keyScopes: runs:write, runs:read

  1. Before you start

    You need a project nightlab can already run: setup’s four required steps are done. A run you start with a key is like one started by hand in the portal: it starts as soon as there’s a slot, and doesn’t wait for anyone to approve it. While your workspace’s writes are off, it’s a dry run: nothing is written to your repository or tracker.

  2. Make a key

    A workspace admin makes it in the portal, under Settings › Integrations › API keys, or through the workspace’s admin API, POST /workspace/api-keys. Give it runs:write (start and cancel runs) and runs:read, only the project your CI builds, and an expiry; 90 days is the default. If your CI calls from fixed addresses, add them to the key’s allow-list.

    A key can start, read and cancel runs. It can’t approve a run, merge, or change a setting, and a person still reviews every draft pull request. It sees every run in its projects, whatever a person’s tracker access allows, so give it to systems, not people.

  3. Store it in your CI

    The key is shown once. Copy it into your CI’s secrets as NIGHTLAB_API_KEY. It never appears in these pages, signed in or not. To check it works, ask which key it is:

    curl -sS https://<workspace>.nightlab.io/v1/key -H "Authorization: Bearer $NIGHTLAB_API_KEY"

    The answer names the key, its scopes and projects, and when it expires.

  4. Start a run

    Call POST /v1/runs with the issue. The issue picks the project. Send an Idempotency-Key, so a retried job gets the first answer back instead of starting a second run, and your own external_ref, which comes back on the run and on every event about it.

    - name: Ask nightlab to build the issue
      run: |
        curl --fail-with-body -sS https://<workspace>.nightlab.io/v1/runs \
          -H "Authorization: Bearer $NIGHTLAB_API_KEY" \
          -H "Content-Type: application/json" \
          -H "Idempotency-Key: $GITHUB_RUN_ID" \
          -d "{\"issue\": \"SHOP-1431\", \"external_ref\": \"$GITHUB_RUN_ID\"}"
      env:
        NIGHTLAB_API_KEY: ${{ secrets.NIGHTLAB_API_KEY }}

    It answers 201 with the run: keep its id. A retry with the same Idempotency-Key and body gets that same answer for 24 hours, marked Idempotent-Replayed: true.

  5. Hear back

    Recommended: a webhook

    Rather than polling, have a workspace admin add a webhook for run.waiting (a person needs to answer a question), run.pr_opened and run.failed: nightlab tells you the moment a person is needed, and your job can fail its own check when the run does. Each delivery is signed, and carries the run with your external_ref, so you can match it to the job.

    Polling works too: GET /v1/runs/{id}, or GET /v1/runs?external_ref=… to find it by your reference, with runs:read.

  6. When it fails

    Every refusal is application/problem+json, with a sentence saying what to change.

    • 401: no key, or one that’s unknown, revoked or expired.
    • 403: the key lacks the scope, the issue’s project isn’t one of the key’s, or the call came from outside its allow-list.
    • 409: setup isn’t finished, the project has no repository nightlab can reach, the issue already has a run in progress (the answer names it, so follow it with GET /v1/runs/{id}), or a request with the same Idempotency-Key is still being answered.
    • 422: a field is wrong, or the Idempotency-Key was used with a different body.
    • 429: the key’s rate limit, 600 reads and 60 writes a minute, with Retry-After saying when to try again; or the workspace’s run slots are all in use.
    • 402: the budget is used up until it renews, or an admin raises it.