API
Upload a PDF, image, or text file and receive a copy with metadata stripped. Sanitize routes use a Bearer key only - session cookies are ignored.
Version 1 · Content is never stored on our servers.
Base URL
https://scrubfiles.com/api/v1
Authentication
Mint a key in the dashboard. The secret is shown once. Send it on every sanitize request:
Authorization: Bearer ds_live_<64 hex characters>
| Header | Required | Description |
|---|---|---|
| Authorization | Yes (sanitize) | Bearer token. Format ds_live_ + 64 hex chars. |
| Accept | No | application/json for JSON; otherwise the cleaned file bytes. |
| Cookie | Ignored | Sanitize routes never use the dashboard session cookie. |
/sanitizeStrip metadata from a single file. Body is multipart form data.
Request body
| Field | Type | Description |
|---|---|---|
| file | File | Required. JPEG, PNG, WEBP, PDF, or UTF-8 text. Max 50 MB. |
| groups | string | Optional comma-separated strip groups (gps,author,revisions,pii,device,dates,attachments). Default: all. |
| rules | string | Optional JSON array of { pattern, flags, replacement }. |
Example
curl -X POST https://scrubfiles.com/api/v1/sanitize \ -H "Authorization: Bearer ds_live_…" \ -H "Accept: application/json" \ -F file=@resume.pdf
Responses
| Status | Body |
|---|---|
| 200 + Accept: application/json | { "fileBase64": "…", "report": { … } } |
| 200 (default) | Cleaned file bytes. Header X-DataScrub-Report is base64 JSON. |
| 401 | { "error": "unauthorized" } |
| 403 | { "error": "forbidden" } |
| 413 | { "error": "too_large" } |
| 415 | { "error": "unsupported" | "polyglot" | … } |
| 429 | { "error": "rate_limited", "retryAfterSec": 1 } |
/sanitize/batchClean many files in one request. Send a zip as file or multiple file parts.
| Constraint | Value |
|---|---|
| Files per request | 25 |
| Zip size | 200 MB |
| Uncompressed zip | 250 MB, ratio ≤ 20:1 |
| Nested zip / Zip-Slip | Rejected (415) |
curl -X POST https://scrubfiles.com/api/v1/sanitize/batch \ -H "Authorization: Bearer ds_live_…" \ -F file=@folder.zip \ -o datascrub.clean.zip
Response is a zip containing cleaned files plus manifest.json.
/keysList keys for the signed-in dashboard user (session cookie). Sanitize Bearer keys cannot call this.
POST /keys - mint a key. JSON { "name": "workbench" }. Secret returned once.
DELETE /keys?id=RECORD_ID - revoke.
/rulesList custom redaction rules for the signed-in user.
PUT /rules - replace all rules. Max 50 patterns, 200 characters each. Nested quantifiers are rejected.
{ "rules": [{ "pattern": "\\b[A-Z]{2}\\d{6}\\b", "flags": "g", "replacement": "[id]" }] }/usageDaily and monthly file counts for each of your keys. Session cookie required.
Errors
JSON body is { "error": "<code>" } unless noted.
| HTTP | Code | When |
|---|---|---|
| 401 | unauthorized | Missing or malformed Bearer token |
| 403 | forbidden | Key revoked or not yours |
| 413 | too_large | File or zip over the size cap |
| 415 | unsupported / polyglot / zip_slip | Type not on the allowlist, or hostile archive |
| 422 | encrypted / pages / pixels / timeout | Encrypted PDF, too many pages, image too large, or per-file timeout |
| 429 | rate_limited | RPM, burst, concurrency, or daily/monthly quota |
Rate limits
Applied per API key. Successful responses include:
| Header | Meaning |
|---|---|
| X-RateLimit-Limit | 120 requests per sliding minute |
| X-RateLimit-Remaining | Requests left in the current window |
| X-RateLimit-Reset | Unix time when the window rolls |
| X-RateLimit-FileQuota-Day | Files left today (UTC) |
| Retry-After | Seconds to wait (429 only) |
| Quota | Value |
|---|---|
| Requests / minute | 120 |
| Burst | 20 tokens, refill 2/s |
| Concurrent | 5 |
| Files / UTC day | 2,000 |
| Files / UTC month | 20,000 |
| Per file | 50 MB, 15s |
| Request | 60s |