Authentication
Send the API key in the Authorization header. Both of these are accepted:
Authorization: Bearer $EFFLUX_TOKEN
Authorization: $EFFLUX_TOKENWebSocket streams use a different header. See Streams.
Pass tenant_view=true on list and get routes when the key can read the tenant. The response then includes resources for the tenant, not only the key owner.
Responses
A single resource is a DocumentResponse:
{
"data": {},
"links": {
"self": "https://api.efflux.io/v3/scans/scan_abc123"
}
}links.self is always present. Extra links (results, summary, screenshot variants, and so on) appear when that resource has them.
A list is a PagedResponse:
{
"data": [],
"pagination": {
"limit": 20,
"page": 1,
"total": 150,
"total_pages": 8,
"has_next": true,
"has_prev": false
}
}Pass page (starting at 1) and limit. Read pagination for the page size, the totals, and whether another page exists. A limit above the maximum is capped. It is not an error.
| Endpoints | Default | Max |
|---|---|---|
| Scans, tasks, surveys, schedules | 20 | 1000 |
| Schedule history | 100 | 1000 |
| Permutations, checks, captures, usage | 100 | 1000 |
| Capture network logs and cookies | 500 | 1000 |
| Lists, rules, webhooks, callback deliveries, monitoring | 20 | 200 |
| Certificates | 50 | 500 |
| Host search | 50 | 200 |
| Your host search | 20 | 100 |
| API keys | 10 | 50 |
| Advanced search | 20 | 100 |
Advanced search does not use page. It returns a SearchPagedResponse with next_token. Send that value back as search_after. See Search.
Scan results, the scan summary, and callback reads return the resource directly, without a data wrapper.
Errors
Errors use Content-Type: application/problem+json (RFC 7807).
{
"type": "https://api.efflux.io/v3/docs/index.html#/Scans",
"title": "Bad Request",
"status": 400,
"detail": "target is required",
"instance": "/v3/scans",
"errors": [
{ "field": "hosts", "message": "required" }
]
}type is a URI for the error. Validation failures include errors with field and message. Quota failures use a type under /v3/limits.
Rate limits
Every response includes:
| Header | Meaning |
|---|---|
RateLimit-Limit | Requests allowed in the current window |
RateLimit-Remaining | Requests left in that window |
RateLimit-Reset | Unix time when the window resets |
X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset repeat those three values. A 429 also sends Retry-After, the seconds to wait.
The 429 body adds rate_limit:
{
"type": "https://api.efflux.io/v3/limits",
"title": "Rate Limit Exceeded",
"status": 429,
"detail": "rate limit exceeded",
"rate_limit": {
"limit": 60,
"remaining": 0,
"reset_at": "2026-03-13T12:00:00Z",
"retry_after_seconds": 42
}
}| Field | Meaning |
|---|---|
limit | Requests allowed in the window that was exceeded |
remaining | Requests left in that window |
reset_at | When the window resets |
retry_after_seconds | Seconds to wait before retrying |
Plan quotas (pending scans, monthly request budget, list sizes) are separate and are returned by GET /limits.