Errors
When a request fails, the API returns a JSON response with an error field and an appropriate HTTP status code.
Error format
Section titled “Error format”All error responses use the same structure:
{ "error": "Human-readable error message"}The error field contains a description of what went wrong. The HTTP status code indicates the error category.
Error reference
Section titled “Error reference”| HTTP Status | Error Type | Description |
|---|---|---|
400 | ValidationError | The request is malformed or missing required fields. |
401 | InvalidApiKeyError | The API key is missing, malformed, or has been revoked. |
404 | ScanNotFoundError | No scan exists with the given ID. |
429 | QuotaExceededError | Monthly scan quota exhausted (free plan only). |
502 | UpstreamError | An internal scan engine failed or timed out. |
400 — ValidationError
Section titled “400 — ValidationError”The request body is missing required fields or contains invalid values.
Example responses
Section titled “Example responses”{ "error": "webhook_url is required"}{ "error": "Invalid scan_types"}{ "error": "metadata must be a valid JSON object"}Common causes
Section titled “Common causes”| Cause | Fix |
|---|---|
Missing webhook_url in scan request | Add the webhook_url field. It is required for all scan submissions. |
Invalid scan_types value | Use only "virus" and/or "nsfw" in the array. |
| Malformed JSON body | Ensure the request body is valid JSON when using Content-Type: application/json. |
metadata too large | Keep metadata under 4 KB. |
Missing file field in multipart request | Include the file field when using multipart form upload. |
401 — InvalidApiKeyError
Section titled “401 — InvalidApiKeyError”The API key is not valid.
Example response
Section titled “Example response”{ "error": "Invalid or missing API key"}Common causes
Section titled “Common causes”| Cause | Fix |
|---|---|
No x-api-key header | Add the x-api-key header to every request. |
| Typo in the API key | Copy the full key from Settings in the dashboard. Keys are 36 characters starting with fs_live_. |
| Key was regenerated | If you regenerated your key, the old one is permanently revoked. Use the new key. |
| Using the wrong header name | The header must be x-api-key, not Authorization, api-key, or X-Api-Key. Header names are case-sensitive. |
Debugging
Section titled “Debugging”Verify your key works by calling the usage endpoint:
curl -v https://api.filesafety.dev/v1/usage \ -H "x-api-key: YOUR_API_KEY"If this returns 200, your key is valid. If it returns 401, the key itself is the problem.
404 — ScanNotFoundError
Section titled “404 — ScanNotFoundError”The scan ID does not match any existing scan.
Example response
Section titled “Example response”{ "error": "Scan not found"}Common causes
Section titled “Common causes”| Cause | Fix |
|---|---|
| Typo in the scan ID | Scan IDs start with scn_ followed by a ULID. Double-check the full ID. |
| Using a scan ID from a different account | Scan IDs are scoped to your API key. You cannot access scans from other accounts. |
| Scan ID was never created | Ensure the POST /v1/scan request succeeded before polling. |
429 — QuotaExceededError
Section titled “429 — QuotaExceededError”Your free plan scan quota has been reached for the current billing period.
Example response
Section titled “Example response”{ "error": "Quota exceeded"}Details
Section titled “Details”This error only occurs on the free plan, which has a hard limit of 10 scans per month. When the quota is reached, scan submissions are blocked until the billing period resets.
Paid plans do not return 429. Instead, scans beyond the quota are allowed and billed as overage at $0.01 per scan.
Resolution
Section titled “Resolution”| Option | How |
|---|---|
| Wait for reset | Your quota resets on the first of each month (free plan) or your billing date (paid plans). |
| Upgrade your plan | Go to the dashboard and select a paid plan. The upgrade takes effect immediately. |
| Check your usage | Call GET /v1/usage to see how many scans remain. |
502 — UpstreamError
Section titled “502 — UpstreamError”An internal scan engine encountered an error while processing your file.
Example response
Section titled “Example response”{ "error": "Scan engine unavailable"}Details
Section titled “Details”This is a server-side error. It means the ClamAV or Rekognition engine failed to return a result for your file. The scan will have a failed verdict.
Resolution
Section titled “Resolution”| Action | Details |
|---|---|
| Retry the scan | Submit the same file again. Transient failures typically resolve on retry. |
| Check scan result | Poll GET /v1/scan/{id} — the scan may have partially completed. |
| Contact support | If the error persists across multiple retries, contact support with the scan ID. |
Handling errors in code
Section titled “Handling errors in code”Node.js
Section titled “Node.js”const res = await fetch("https://api.filesafety.dev/v1/scan", { method: "POST", headers: { "x-api-key": process.env.FILESAFETY_API_KEY }, body: formData,});
if (!res.ok) { const { error } = await res.json();
switch (res.status) { case 400: throw new Error(`Bad request: ${error}`); case 401: throw new Error("Invalid API key. Check your FILESAFETY_API_KEY."); case 429: throw new Error("Quota exceeded. Upgrade your plan."); case 502: console.warn("Upstream error, retrying..."); break; default: throw new Error(`Unexpected error (${res.status}): ${error}`); }}Python
Section titled “Python”response = requests.post( "https://api.filesafety.dev/v1/scan", headers={"x-api-key": os.environ["FILESAFETY_API_KEY"]}, files={"file": open("document.pdf", "rb")}, data={"webhook_url": "https://your-app.com/webhooks/filesafety"},)
if response.status_code != 200: error = response.json()["error"]
if response.status_code == 401: raise Exception("Invalid API key") elif response.status_code == 429: raise Exception("Quota exceeded — upgrade your plan") elif response.status_code == 502: print(f"Upstream error: {error}. Retrying...") else: raise Exception(f"API error ({response.status_code}): {error}")