BlackBat AI handbook · 11 of 13
How to Trigger BlackBat AI from Your CI/CD Pipeline
Call the CI/CD API from GitHub Actions, GitLab CI, or any pipeline to start an exploration or test run and gate a deploy on the result.
By the end of this guide, your pipeline will start a BlackBat AI run on its own — on a merge, before a release, whenever you say — and your deploy step will wait on the result instead of someone checking the dashboard by hand.
CI/CD triggering is available on paid plans. The free plan and trials aren't included: the trigger endpoint answers 403 with /billing/feature-not-available/ci-triggers until you upgrade.
Step 1 — Create an API key
From Settings → CI/CD (OWNER or ADMIN only), create a key and give it a name that says where it's used, e.g. "GitHub Actions – web". The key is shown once — copy it straight into your CI provider's secrets (BLACKBAT_API_KEY or similar). If you lose it, revoke it and create a new one; there's no way to view it again.
[Screenshot: the CI/CD settings page with a newly generated key]
By default (Notifications: Off), runs triggered by a key notify no one — your pipeline is expected to read the result from the API. Set a key's Notifications to Failures only to notify people only about failed, timed-out or cancelled runs, or to All outcomes to notify about every run. Each person's own notification preferences still apply on top of this.
Step 2 — Trigger a run
POST /v1/ci/runs, authenticated with your key, sent as an x-api-key: <key> header (or as Authorization: Bearer <key> if you prefer). It returns immediately with 202 and a run id to poll; every other endpoint below takes the key the same way. The examples below use the production API at https://api.blackbat.dev.
Exploration (full or diff crawl):
curl -X POST https://api.blackbat.dev/v1/ci/runs \
-H "x-api-key: $BLACKBAT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"projectId": "<project-id>",
"environmentId": "<environment-id>",
"type": "CRAWL",
"crawlingMode": "DIFF",
"idempotencyKey": "'"$GITHUB_SHA"'"
}'
A DIFF crawl needs a prior full crawl on the environment to diff against — run a FULL crawl first if this is a new environment.
Test execution (a suite or a single plan):
curl -X POST https://api.blackbat.dev/v1/ci/runs \
-H "x-api-key: $BLACKBAT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"projectId": "<project-id>",
"environmentId": "<environment-id>",
"type": "TEST_EXECUTION",
"testSuiteId": "<test-suite-id>",
"idempotencyKey": "'"$GITHUB_SHA"'"
}'
Provide exactly one of testSuiteId or testPlanId. projectId and environmentId are visible on the project/environment pages in the dashboard.
The idempotencyKey is optional but worth setting to something stable for the trigger, like the commit SHA — if a retry sends the same key again, you get the original run back (200 with idempotentReplay: true, not a second run) instead of starting a duplicate. You can also set externalRef (a branch, commit or pipeline URL) and it's shown on the run.
Optional settings
Beyond the fields above, a trigger can set the same limits and options as a run started from the dashboard:
- Limits (crawls):
maxPages,maxDepth,maxPageTemplates,templateSampleSize(1–30, default 3),maxCredits,maxRunTime(minutes, up to 1440),crawlWorkers(1–10) andallowSubdomainCrawling. - Access to the site:
loginInstructions,registrationInstructions,paymentInstructions,oauthAllowedIdpOrigins,proxyServer(withproxyUsername/proxyPassword) andhttpAuthUsername/httpAuthPassword. These are saved on the environment the first time they're sent, the same as a manual run. - Site documentation (crawls only):
generateDocumentation,generateUserStories(needsgenerateDocumentation) and a requiredintelligenceMaxCreditsspend limit, in credits as shown in the dashboard. Pick the limit yourself; the dashboard shows a cost estimate when you start documentation by hand. The work runs as a separate billed job after the crawl, stops at the limit and keeps what it finished, and the person who created the API key is notified when it ends. This needs a plan that includes site documentation, otherwise the call returns403with/billing/feature-not-available/site-intelligence. ADIFFcrawl can send these only when the crawl it compares with has fully documented the site (otherwise400,/validation/not-allowed/intelligence-without-current-documentation), and then only changed pages and sections are paid for. Sending them on a test execution is a400(/validation/not-allowed/intelligence-on-this-run). - Active security probes (crawls only):
activeProbes,loginProbes,bruteForceProbe,unauthReplayMaxEndpointsandactiveProbeBudgetMs. Turning a probe on needs consent for the environment: an Owner or Admin must enable active security testing for it in Settings → Environments. Without consent no probe runs, and sending one astruereturns400(/validation/consent-required/activeProbes). Probe settings on anything other than a crawl are also a400.
Step 3 — Poll for the result — your deploy gate
GET /v1/ci/runs/:id returns the current status:
QUEUED/RUNNING/PROCESSING— still going, keep polling.PASSED— proceed with the deploy.FAILED/TIMEOUT/CANCELLED— block the deploy.
curl https://api.blackbat.dev/v1/ci/runs/$RUN_ID \
-H "x-api-key: $BLACKBAT_API_KEY"
Every response also has creditsSpent, bugCount, startedAt / endedAt, and a reportUrl deep link into the dashboard. For a test-execution run it carries a tests object (total, passed, failed, errored, pending). status goes terminal as soon as the run itself is done, so the gate never sits waiting on the AI write-up to finish generating.
For per-test detail in your pipeline log — which test failed and why — call GET /v1/ci/runs/:id/results. It returns one entry per executed test plan with its status (PASSED, FAILED, ERROR or PENDING), the failure reason, per-step traces (including any self-healing) and a written interpretation. It's an empty list for exploration runs.
Step 4 — Wire it into your pipeline
The same trigger-then-poll shape works anywhere curl and jq are available — here it is as a GitHub Actions step and a GitLab CI job.
GitHub Actions
Add BLACKBAT_API_KEY as a repository secret, then:
- name: BlackBat AI test gate
env:
BLACKBAT_API_KEY: ${{ secrets.BLACKBAT_API_KEY }}
run: |
RUN_ID=$(curl -sf -X POST https://api.blackbat.dev/v1/ci/runs \
-H "x-api-key: $BLACKBAT_API_KEY" -H "Content-Type: application/json" \
-d '{"projectId":"'"$BLACKBAT_PROJECT_ID"'","environmentId":"'"$BLACKBAT_ENVIRONMENT_ID"'",
"type":"TEST_EXECUTION","testSuiteId":"'"$BLACKBAT_SUITE_ID"'",
"idempotencyKey":"'"$GITHUB_SHA"'"}' | jq -r .runId)
while :; do
STATUS=$(curl -sf https://api.blackbat.dev/v1/ci/runs/$RUN_ID \
-H "x-api-key: $BLACKBAT_API_KEY" | jq -r .status)
case $STATUS in
PASSED) echo "BlackBat AI tests passed"; exit 0 ;;
FAILED|TIMEOUT|CANCELLED) echo "BlackBat AI tests did not pass"; exit 1 ;;
*) sleep 15 ;;
esac
done
GitLab CI
Add BLACKBAT_API_KEY as a masked CI/CD variable (Settings → CI/CD → Variables), then:
blackbat_test_gate:
stage: test
image: alpine:latest
before_script:
- apk add --no-cache curl jq
script:
- |
RUN_ID=$(curl -sf -X POST https://api.blackbat.dev/v1/ci/runs \
-H "x-api-key: $BLACKBAT_API_KEY" -H "Content-Type: application/json" \
-d '{"projectId":"'"$BLACKBAT_PROJECT_ID"'","environmentId":"'"$BLACKBAT_ENVIRONMENT_ID"'",
"type":"TEST_EXECUTION","testSuiteId":"'"$BLACKBAT_SUITE_ID"'",
"idempotencyKey":"'"$CI_COMMIT_SHA"'"}' | jq -r .runId)
while :; do
STATUS=$(curl -sf https://api.blackbat.dev/v1/ci/runs/$RUN_ID \
-H "x-api-key: $BLACKBAT_API_KEY" | jq -r .status)
case $STATUS in
PASSED) echo "BlackBat AI tests passed"; exit 0 ;;
FAILED|TIMEOUT|CANCELLED) echo "BlackBat AI tests did not pass"; exit 1 ;;
*) sleep 15 ;;
esac
done
CircleCI, Jenkins, and any other pipeline that can run curl follow the same shape — trigger, poll, exit non-zero on a bad status.
Running against a private target instead of the cloud
If the environment isn't reachable from BlackBat AI's cloud runners, add "executionEnv": "LOCAL" and "platform" (LINUX, MAC_SILICON, MAC_INTEL, or WINDOWS) to the trigger body. The 202 response includes a package with a downloadUrl and a short-lived runKey (the key the runner authenticates with, so keep it out of your logs). Your pipeline downloads the runner zip, executes it inside your network, and you poll the run as usual. The zip is also available at GET /v1/ci/runs/:id/package, which only works for runs created with executionEnv: LOCAL and a platform. This is the CI equivalent of a private-environment Runner.
API specification
The full request and response schemas are available as an OpenAPI 3 file: download blackbat-ci.yaml. Import it into Postman, Insomnia or a client generator, or hand it to your AI coding assistant when it writes the pipeline step.
Errors and rate limits
| Status | Meaning |
|---|---|
| 400 | The request doesn't describe a valid target: crawlingMode missing on a crawl, not exactly one of testSuiteId / testPlanId on a test execution, platform missing on a local run, or /runs/diff-requires-full-crawl when a DIFF crawl has no baseline. Field problems come back as /validation/<constraint>/<field>. |
| 401 | The key is missing, invalid, revoked or expired (/auth/missing-api-key or /auth/invalid-api-key). |
| 402 | The organization has no credits left. |
| 403 | Your plan doesn't include CI triggering (/billing/feature-not-available/ci-triggers), or the run isn't a local run (/ci/package-not-available, package download only). |
| 404 | The project, environment, suite, plan or run isn't in the key's organization. |
| 429 | Too many requests for this key (60 per minute by default). |
Every authenticated response carries X-RateLimit-Limit-ci-trigger, X-RateLimit-Remaining-ci-trigger and X-RateLimit-Reset-ci-trigger (seconds until the window resets), so a pipeline can back off before it's throttled. A 15-second poll interval stays well inside the limit.
Tips and common mistakes
- Poll, don't sleep-and-hope. A run's duration depends on what it finds — poll on an interval and act on
status, not a fixed timeout. - Set
idempotencyKeyto something tied to the trigger, like the commit SHA. A retried CI step then resumes the same run instead of starting a second one and doubling your credit spend. DIFFcrawls need a baseline. If the environment has never had a full crawl, triggerFULLfirst — aDIFFon a fresh environment is rejected with400(/runs/diff-requires-full-crawl).- Match run depth to the moment, the same as any other trigger — see fitting BlackBat AI into your release process for what to run on a merge versus before a release.
- One key per pipeline makes it easy to see which pipeline is spending credits, and to revoke just that one if a secret leaks.
What to try next
- How to Fit BlackBat AI Into Your Release Process — where the CI trigger fits next to schedules and on-demand runs.
- How to Test a Staging or Private Environment with the BlackBat AI Runner — the same idea for a target CI can't reach directly.
- How to Review a Run — reading the results the gate is acting on.
Generate an API key and add the trigger step to your pipeline.
Try it on your own app
Point BlackBat AI at a URL and see what it finds — no scripts, no setup. Free, no credit card.