Barrion Docs
Public API

Errors and limits

The error shape, what each code means, rate limits and retrying safely.

Errors

Every error has the same shape, so a pipeline can branch on code rather than on the message:

{
  "code": "API_KEY_CAP_EXCEEDED",
  "message": "This run reserves 1000 credits and this API key's budget of 500 this cycle has 300 left. Raise the key's budget in the dashboard.",
  "statusCode": 403
}

Some validation errors add a field naming the part of the request that was wrong. Messages are written for people and may change; codes will not.

StatusCodeMeaning
400VALIDATION_ERRORThe request is missing something or has an invalid value
401UNAUTHORIZEDNo key, or the key is invalid, expired, revoked or for a different environment
402INSUFFICIENT_CREDITSYour balance does not cover the run
403FORBIDDENThe key, or its creator's role, lacks the permission for this call, or a pentest target is not assigned to you in the organization
403ACCOUNT_SUSPENDEDThe account is suspended
403API_KEY_CAP_EXCEEDEDThe run would take the key past its credit budget
403ORG_CREDIT_CAP_EXCEEDEDThe run would take you past your spending allowance in the organization
403TARGET_API_RUNS_DISABLEDAPI runs are turned off for this target
403TARGET_NOT_ASSIGNEDIn an organization, the domain you asked to scan is not assigned to you
403PLAN_LIMIT_EXCEEDEDYour plan does not allow this, for example its scan limit is reached
404NOT_FOUNDNo such scan, pentest or target verification in this account
409IDEMPOTENCY_IN_PROGRESSThe first request with this Idempotency-Key is still running
422IDEMPOTENCY_KEY_REUSEDThis Idempotency-Key was already used with a different request
429RATE_LIMITEDToo many requests. Wait for Retry-After
429PENTEST_CONCURRENCY_EXCEEDEDYou already have as many pentests running as your account allows. Wait for one to finish
500INTERNAL_ERRORSomething went wrong on our side. Retry with the same Idempotency-Key

RATE_LIMITED and PENTEST_CONCURRENCY_EXCEEDED are both 429 but need different handling: back off and retry the first, wait for one of your running pentests to finish before the second.

Rate limits

LimitPerAllowance
Readskey120 a minute
Readsaccount600 a minute, across all your keys
Starts and cancelskey10 a minute

Every answer carries the limit you are closest to:

RateLimit-Limit: 120
RateLimit-Remaining: 117
RateLimit-Reset: 42

RateLimit-Reset is the number of seconds until the window starts over. A refused request answers 429 with Retry-After, in seconds. A refused request still counts, so retrying before Retry-After only keeps you refused.

A very high request rate from one IP address can also be refused by Barrion's network edge, before it reaches the API. That 429 has no JSON body and no RateLimit-* headers. Treat it like any other 429: wait, then retry. Polling a scan or a pentest every 15 to 30 seconds stays well inside the limits.

Idempotency

POST /v1/pentests and POST /v1/scans need an Idempotency-Key header: any string of up to 255 visible characters, with no spaces. It is what lets you retry a start safely.

  • The same key and the same body within 24 hours gets the first answer back, with the header Idempotent-Replayed: true. Nothing is started or charged a second time.
  • The same key with a different body is refused with 422 IDEMPOTENCY_KEY_REUSED.
  • A retry while the first request is still running is refused with 409 IDEMPOTENCY_IN_PROGRESS. Wait a few seconds and send the same request again.
  • Only a success is remembered. If a start is refused, say for lack of credits, fix the cause and send the same request with the same key: it runs again, rather than repeating the refusal.
  • If a start fails on our side with a 500, retry with the same key. If the run had already been created, you get that run back rather than a second one. The key is held for two minutes after the failure, so a retry inside that window is refused with 409: wait and try again. Retry within a few minutes: a run whose start failed and was not retried is marked FAILED after about five minutes, and its credits are returned. A retry after that answers that FAILED run. Nothing was charged for it, so start again with a new key.

Body fields are compared regardless of their order, so a client that rebuilds the same request is still recognised.

In CI, build the key from something that stays the same when a run is retried:

  • Pentests: use the pipeline's run id alone, for example pentest-$GITHUB_RUN_ID. Re-running a failed workflow run then gets the same pentest back instead of starting, and paying for, a second one. A new scheduled or manual run has a new run id and starts a fresh pentest. Do not add $GITHUB_RUN_ATTEMPT: GitHub increases it on every re-run, so each re-run would send a new key.
  • Scans: the attempt number is fine to include, since scans are free.