code you can match on.
Registering a target
create_target runs one live probe. On failure it returns a category and saves
nothing, so fix what it names and call it again.
Authentication errors
Signing in an app
When an app signs in, Enoki opens in your browser. If it can’t let the app in, the page says why:Rate limits (429)
Each API key and each connected app is rate-limited per minute. Every request counts against the Standard tier; the three expensive tools additionally count against the stricter Expensive tier.
On breach you get a 429 with code
rate_limited. Because expensive tools
spend both budgets, a burst of cheap calls can exhaust the Standard tier and 429
the next create_target.
Per-caller limits
Two further limits apply to every request, keyed on the calling IP address rather than on your key or app. They exist to stop path scanning, and normal integration traffic does not come close to either.
The client-error bucket is the one to know about, because a full bucket refuses
every request from that IP for the rest of the minute — not just the ones
that were erroring. Two habits fill it:
- Retrying a 404. A 404 means the resource is not there; a retry returns the same 404 and spends another entry. Do not retry them.
- Polling for a resource before it exists. Poll the parent listing, or the run’s status, rather than the not-yet-created child.
scope_denied counts too, so fix the scopes rather than
looping on the failure.
429s from these two limits carry a Retry-After header and a plain detail
message rather than a code field, so branch on the status and the header, not
on a code, when handling them.
Daily assessment budget
Separately from the per-minute tiers above, each workspace has a budget of 20 assessment runs per rolling 24 hours. This one is not per API key and not per minute: it is shared across the dashboard, the external API, and MCP, because what it protects is the cost of running an assessment rather than request volume. Every run the workspace starts counts, whatever its outcome and whoever started it — including runs you did not trigger by hand, such as scheduled runs, safety assessments, and reporting top-ups started from the dashboard. So the budget can be spent before you have made 20 explicit trigger calls. The error message always reports the actual count, so read that number rather than assuming it matches your own triggers. The same budget refuses those creators too. A safety assessment or a reporting top-up started when the workspace has no slot left gets the same 429 withtrigger_quota_exceeded and the same Retry-After; in the
dashboard, all three lenses show the same “Daily assessment budget reached”
notice.
A reporting top-up is a run you start in Reporting when a risk needs more testing
before its report can be downloaded. It tests those risks and re-tests the fixes
you reported.
On breach you get a 429 with code trigger_quota_exceeded — so a 429 from a
trigger carries one of two codes, and they mean different things:
How the reset reaches you depends on the surface. On REST, both codes carry a
Retry-After header, and trigger_quota_exceeded additionally carries
retryAfterSeconds in the response body. On MCP, neither does — tool errors
are plain text with no headers — so trigger_assessment puts the reset time in
the message itself. Treat that time as the earliest a slot can open, not a
guarantee: runs started while you wait push it later.
If you are hitting this from a release hook that triggers an assessment on every
deploy, a scheduled re-run is the supported way to get a recurring cadence — talk
to us and we will set it up rather than have you spend the budget on hook volume.
Assessment allowance (403)
Every workspace has a per-lens allowance, and a spent one returns 403. Which refusal you get depends on your plan, and thecode in the body tells them
apart.
Your monthly allowance is spent
A paid workspace gets a fixed number of runs per lens, per calendar month: security assessments, safety assessments and reporting top-ups are counted separately, so spending one does not reduce the others. The month is UTC and the counts reset on the 1st. Only completed runs count, in every lens. A run that ends inerror, and
one you cancel, costs no allowance and can be retried.
When a lens’s allowance is spent, the trigger returns 403 with code
assessment_allowance_spent, and the body names the count, the ceiling and the
reset date:
resets_at — but it carries no
Retry-After, because that can be most of a month away and is not a wait a
client should sit through. Schedule around the date, or get in touch and we will
raise the ceiling.
You are on an evaluation
Workspaces on an evaluation get a fixed number of security assessments for the life of the evaluation rather than per month. Safety assessments and reporting top-ups are not part of an evaluation and are refused outright, so there are two more refusals here. When the security allowance is spent, the trigger returns 403 with codetrial_lens_limit_reached, and the body names the count and the ceiling:
trial_lens_not_included instead. That is not a spent
allowance, so it carries no counts:
lens value is compliance.
Neither of the two evaluation refusals resets — do not retry them. Unlike
the monthly allowance above and the two 429s, no amount of waiting frees a slot;
we lift the ceiling or add the lens, so get in touch. A run that ends in error
does release its slot, so a run that fails on our side does not cost you an
assessment.
All three refusals share one body shape, so branch on code and read the counts
where they apply. The examples above show only the fields each refusal fills in;
the rest are present and null — resets_at on both evaluation refusals, and
used and limit on trial_lens_not_included, which short-circuits before
anything is counted.
One more refusal applies to an evaluation only. It runs full assessments, so a
trigger that passes categories returns 403 with code
trial_focus_not_included. Unlike the two above, you clear this one yourself:
leave categories out and trigger again. Its body carries the code and the
message and nothing else:
trigger_assessment tool error carrying the
message and nothing else — an MCP tool error has no body, so there is no code
to branch on there. Use the REST trigger if your client needs to tell them
apart.
Category list (403)
Listing the categories (GET /api/v1/category, or the list_categories MCP
tool) is part of the platform plan. A trial workspace is refused it:
categories when you trigger one.
A run that could not start (502)
If Enoki accepts a trigger but cannot start the run, the trigger returns 502:trigger_assessment returns a tool error saying the run could not be started.
”Not found” for something you expect to exist
A finding, run, or target in a different workspace returns not-found, not 403, so IDs can’t be probed across workspaces. If you get not-found for an ID you believe is valid, check your key or app is connected to the right workspace.Can’t connect at all
- Endpoint: confirm the URL is exactly
https://mcp.enokilabs.ai/mcp(streamable HTTP). - Auth header: the key goes in the
Authorization: Bearer …header, not a query parameter. - Signing in: if your client never opens Enoki in your browser, it can’t sign in to Enoki; connect it with an API key.
- Client support: for a client without native remote-MCP support, use the
mcp-remotebridge (see Connect your agent).