Skip to content

POST /v1/scan

Submit a file for scanning. Supports two modes: direct upload (send the file, get the result in one request) or presigned URL (get an upload URL for large files, poll for results).

POST https://api.filesafety.dev/v1/scan

Requires x-api-key header. See Authentication.


Send the file as multipart form data. The API waits for the scan to complete and returns the full result in the response (typically 10–25 seconds).

Best for files under 4MB and simple integrations where you want results in a single request.

Content-Type: multipart/form-data

FieldTypeRequiredDescription
filebinaryYesThe file to scan (max 4MB via direct upload). For larger files, use the presigned URL flow below.
webhook_urlstringNoHTTPS URL where scan results will also be POSTed.
scan_typesJSON stringNoArray of scan types. Options: "virus", "nsfw". Defaults to both.
metadataJSON stringNoArbitrary key-value object (max 4 KB) returned with results.
Terminal window
curl -X POST https://api.filesafety.dev/v1/scan \
-H "x-api-key: fs_live_aBcDeFgHiJkLmNoPqRsTuVwXyZ012345" \
-F "file=@./document.pdf"

With optional webhook and metadata:

Terminal window
curl -X POST https://api.filesafety.dev/v1/scan \
-H "x-api-key: fs_live_aBcDeFgHiJkLmNoPqRsTuVwXyZ012345" \
-F "file=@./document.pdf" \
-F "webhook_url=https://your-app.com/webhooks/filesafety" \
-F 'metadata={"user_id":"usr_123"}'
{
"scan_id": "scn_01HX7Z9K3M2N4P5Q6R7S8T9U0V",
"status": "complete",
"verdict": "clean",
"virus": {
"clean": true,
"signature": null
},
"nsfw": {
"clean": true,
"categories": [],
"confidence": 0.01
},
"file_hash": "sha256:e3b0c44298fc1c149afbf4c8...",
"completed_at": "2025-01-15T10:30:45.123Z"
}
FieldTypeDescription
scan_idstringUnique scan identifier.
statusstring"complete" or "failed". If the scan takes longer than ~25 seconds, returns "scanning" with the scan_id for polling.
verdictstringOne of: clean, infected, nsfw, mixed, failed.
virusobjectVirus scan result. clean: true if no threats found. signature contains the threat name if infected.
nsfwobjectNSFW detection result. clean: true if safe. categories lists flagged content types.
file_hashstringCryptographic hash of the scanned file.
completed_atstringISO 8601 timestamp of scan completion.

If the file was previously scanned (matched by hash), the cached result returns instantly.


Request a presigned upload URL for large files (up to 200MB). After uploading, poll GET /v1/scan/{id} for results, or provide a webhook_url to receive them automatically.

Content-Type: application/json

{
"webhook_url": "https://your-app.com/webhooks/filesafety",
"scan_types": ["virus", "nsfw"],
"metadata": {"user_id": "usr_123"}
}
FieldTypeRequiredDescription
webhook_urlstringNoHTTPS URL where scan results will be POSTed on completion.
scan_typesarrayNoArray of scan types. Options: "virus", "nsfw". Defaults to both.
metadataobjectNoArbitrary key-value object (max 4 KB) returned with scan results.
Terminal window
curl -X POST https://api.filesafety.dev/v1/scan \
-H "x-api-key: fs_live_aBcDeFgHiJkLmNoPqRsTuVwXyZ012345" \
-H "Content-Type: application/json" \
-d '{"webhook_url": "https://your-app.com/webhooks/filesafety"}'
{
"scan_id": "scn_01HX8A1B2C3D4E5F6G7H8I9J0K",
"status": "awaiting_upload",
"upload_url": "https://upload.filesafety.dev/scn_01HX8A1B2C3D4E5F6G7H8I9J0K?..."
}
FieldTypeDescription
scan_idstringUnique scan identifier.
statusstring"awaiting_upload" — waiting for the file.
upload_urlstringPresigned URL. PUT the file here to begin scanning. Expires in 15 minutes.
Terminal window
curl -X PUT "UPLOAD_URL_FROM_RESPONSE" \
-H "Content-Type: application/octet-stream" \
--data-binary @./document.pdf

Once the upload succeeds, scanning begins automatically. Poll GET /v1/scan/{id} for results.


StatusErrorCause
400"Invalid JSON body"Malformed JSON in request body.
400"Invalid scan_types"scan_types contains an unrecognized value.
401"Invalid or missing API key"Missing or invalid x-api-key header.
413"File too large for direct upload"File exceeds 4MB. Use the presigned URL flow for larger files.
429"Monthly scan quota exceeded"Free plan quota reached. Upgrade to continue scanning.

VerdictMeaning
cleanNo threats detected.
infectedVirus or malware detected. Check virus.signature for the threat name.
nsfwExplicit or suggestive content detected. Check nsfw.categories for details.
mixedBoth virus and NSFW issues detected.
failedScan could not be completed. Retry the request.

TypeWhat it detects
virusViruses, malware, trojans, ransomware, adware.
nsfwExplicit nudity, suggestive content, graphic violence.

Both scan types are included in every plan at no extra cost.