API access is available on Enterprise plans. Every request is authenticated with a bearer token scoped to a single workspace. This page covers key generation, request signing, error handling, and rate limits.
Generating an API key
Open Settings, then API Keys, then Generate Key. You will be asked to name the key and choose a scope. Name it after the system that will use it rather than the person who created it, because keys outlive employees.
The key is displayed exactly once, at the moment of creation. It is stored hashed and cannot be retrieved afterwards. If you lose it, revoke it and generate a replacement; there is no recovery path, by design.
Scopes
Keys carry one of three scopes. Read only keys can list websites, scans, and findings. Read and write keys can additionally create websites and trigger scans. Admin keys can manage team membership. Choose the narrowest scope that does the job, and generate separate keys for separate integrations so that revoking one does not break the others.
Authenticating a request
Pass the key in the Authorization header as a bearer token:
curl https://api.leovoid.com/v1/websites \
-H "Authorization: Bearer lv_live_xxxxxxxxxxxxxxxx" \
-H "Accept: application/json"
Keys are never accepted as query parameters. Query strings end up in server logs, browser history, and referrer headers, which makes them an unacceptable place for a credential.
Listing websites
A GET against the websites collection returns every website in the workspace the key belongs to, paginated at fifty per page.
GET /v1/websites?page=2&per_page=50
The response includes an identifier, hostname, business name, verification status, and the timestamp of the most recent completed scan for each website.
Triggering a scan
Scans are created by posting to the scans collection with a website identifier and a list of paths. The endpoint returns immediately with a scan identifier and a status of queued; it does not block until the scan completes.
POST /v1/scans
{
"website_id": "web_a1b2c3",
"paths": ["/", "/services", "/contact"]
}
The same plan limits that apply in the interface apply here. Exceeding your link selection limit returns a 422 with a body explaining which limit was hit and what the ceiling is.
Polling for results
Fetch a scan by identifier to check status. Statuses progress through queued, discovering, scanning, and complete. Poll no more than once every ten seconds; there is no benefit to polling faster, since scan status is not updated more frequently than that internally.
Webhooks instead of polling
Polling is supported but webhooks are better. Register an endpoint and Leovoid posts a signed payload when a scan reaches a terminal state. Verify the signature header before trusting the body, and respond with a 2xx quickly, doing any real work asynchronously. Delivery is retried with exponential backoff for up to twenty four hours.
Error responses
Errors use conventional status codes. A 401 means the key is missing, malformed, or revoked. A 403 means the key is valid but lacks the scope for this operation. A 404 means the resource does not exist or belongs to another workspace, deliberately indistinguishable so the API cannot be used to probe for identifiers that exist elsewhere. A 422 means the request was well formed but semantically invalid. A 429 means you have exceeded the rate limit.
Every error body carries a machine readable code and a human readable message. Branch on the code, never on the message text, which may be reworded without notice.
Rate limits
Requests are limited to one hundred and twenty per minute per key, measured as a rolling window rather than a fixed bucket. Every response includes headers reporting your limit, remaining allowance, and reset time. Exceeding the limit returns a 429 with a Retry After header giving the number of seconds to wait.
Honour Retry After rather than retrying immediately. Clients that ignore it and hammer the endpoint may have their key throttled more aggressively.
Versioning
The version is part of the path. Breaking changes ship as a new version; additive changes such as new response fields may appear within a version without notice, so parse defensively and ignore fields you do not recognise. Deprecated versions are supported for at least twelve months after their replacement ships, with deprecation announced in advance.
Security notes
Treat keys as production credentials. Store them in a secrets manager or an environment variable, never in source control. Rotate them on a schedule and immediately whenever someone with access leaves. Revoke rather than delete when investigating anything suspicious, since a revoked key retains its audit trail and a deleted one does not.