For Developers
Build with the Distill API
Integrate CV anonymisation and ATS-safe formatting directly into your platform. One REST API — clean output, consistent options, predictable pricing.
Three steps to a clean CV
The pipeline is asynchronous. Submit a file, poll for completion, download the result. No webhooks required, no complex setup.
01
Submit
POST a base64-encoded CV file along with the anonymisation options you want applied. The pipeline starts immediately and returns a job ID.
02
Poll
Check the job status every 5 seconds. Extraction and generation typically complete in 15–60 seconds. Status moves through EXTRACTING → DISTILLING → PROCESSED.
03
Download
Once status is PROCESSED, fetch a short-lived signed URL for the anonymised .docx file. The URL is valid for 5 minutes — download and store it on your side.
Complete example
From raw file to anonymised .docx in under a minute.
The example on the right shows the full end-to-end flow in Python — submit, poll, download. The same pattern works in any language that can make HTTP requests.
Options are applied deterministically with no AI cost on re-runs. If you want to change the anonymisation settings after the fact, call POST /distillations/{id}/restart with the new options — the original extraction is reused.
import base64, time, requests
API_KEY = "your_key_here"
BASE = "https://api.distill.cv/v1"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
# 1 — Submit the CV
with open("CV.pdf", "rb") as f:
content = base64.b64encode(f.read()).decode()
job = requests.post(f"{BASE}/distillations", headers=HEADERS, json={
"filename": "CV.pdf",
"content": content,
"options": {
"removeName": True,
"removeContact": True
}
}).json()
job_id = job["id"]
# 2 — Poll until processed
while True:
data = requests.get(f"{BASE}/distillations/{job_id}", headers=HEADERS).json()
status = data["status"]
if status == "PROCESSED": break
if status == "FAILED": raise RuntimeError("Distillation failed")
time.sleep(5)
# 3 — Download the result
url = requests.get(
f"{BASE}/distillations/{job_id}/download", headers=HEADERS
).json()["url"]
# url is a pre-signed S3 link valid for 5 minutes
import urllib.request
urllib.request.urlretrieve(url, "CV_clean.docx")What you can build
The API is designed to slot into your existing stack, not replace it.
ATS integration
Trigger Distill automatically when a candidate is added to your applicant tracking system. Every submittal lands clean, branded, and anonymised — no manual steps.
Bulk processing
Run your entire candidate pool through the API in parallel. A simple loop over your database is all it takes to produce clean CVs at scale.
Custom workflows
Chain Distill into Zapier, Make, or your own automation. Trigger on email parse, form submit, or document upload — wherever CVs enter your pipeline.
White-label embed
Build Distill's output directly into your own platform. Apply your agency's branding, set your own anonymisation defaults, and surface clean CVs under your name.
Get your API key
API keys are scoped to your organisation and managed from the Distill dashboard. Keys are shown only once at creation — store them in your secrets manager.
Go to Settings → API KeysAuthentication
Authorization: Bearer dk_<keyId>.<secret>
Base URL
https://api.distill.cv/v1
API Reference
Full specification for all available endpoints.
/distillationsget/distillations/{distillationId}get/distillations/{distillationId}/downloadpost/distillations/{distillationId}/restart/distillationsSubmits a CV for processing. The file is sent as a base64-encoded string in the JSON body — no second upload call needed.
The pipeline starts immediately after this call returns. Poll
GET /distillations/{id} until status is PROCESSED, then call
GET /distillations/{id}/download to retrieve the result.
File size: the raw file must be ≤ 7.5 MB (base64 encoding adds ~33%, capping the total JSON body at the 10 MB API Gateway limit). CVs are typically 50 KB–3 MB.
Example (curl)
curl -s -X POST https://api.distill.cv/v1/distillations \
-H "Authorization: Bearer $DISTILL_API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"filename\": \"CV.pdf\",
\"content\": \"$(base64 < CV.pdf)\",
\"options\": { \"removeName\": true }
}"
Example (Python)
import base64, requests
with open("CV.pdf", "rb") as f:
content = base64.b64encode(f.read()).decode()
resp = requests.post(
"https://api.distill.cv/v1/distillations",
headers={"Authorization": f"Bearer {api_key}"},
json={"filename": "CV.pdf", "content": content}
)
job_id = resp.json()["id"]
Request Body
contentstringrequiredBase64-encoded file content (standard encoding, no line breaks required).
filenamestringOriginal filename including extension (`.pdf`, `.docx`, `.jpg`, `.jpeg`, `.png`). Used to infer `mimeType` when `mimeType` is not supplied.
mimeType"application/pdf" | "application/vnd.openxmlformats-officedocument.wordprocessingml.document" | "image/jpeg" | "image/png"MIME type of the file. Required when `filename` is absent or has no recognised extension.
optionsobjectAnonymization and formatting options applied during distillation. Options omitted from the object are treated as `false`. The defaults below reflect the Distill dashboard defaults — copy them to replicate the out-of-the-box blind-screening preset: ```json { "removeName": true, "removeContact": true, "removeGender": true, "removeAge": true } ```
Responses
201Job accepted. Pipeline has started; poll status to track progress.400Invalid request body.401Missing or invalid API key./distillations/{distillationId}Returns the current status and metadata of a distillation job.
Poll this endpoint until status is PROCESSED before requesting
the download URL. Typical processing time is 15–60 seconds.
Recommended polling interval: 5 seconds.
Path Parameters
distillationIdstringrequiredExample: V1StGXR8_Z5jdHi6B3Ui4
Responses
200Distillation found.401Missing or invalid API key.403Distillation belongs to a different organization.404Distillation not found./distillations/{distillationId}/downloadReturns a short-lived (5 minute) signed URL for the processed .docx output.
Only available when status is PROCESSED. Returns 409 for all other statuses.
Path Parameters
distillationIdstringrequiredExample: V1StGXR8_Z5jdHi6B3Ui4
Responses
200Signed download URL.401Missing or invalid API key.403Distillation belongs to a different organization.404Distillation not found.409Distillation not yet processed./distillations/{distillationId}/restartRe-runs the distill + generate steps using updated options.
The original LLM extraction is reused (no additional AI cost).
Requires the job to have completed its initial extraction (status was
at least EXTRACTED at some point). Returns 409 if extraction has not
yet finished.
On success the job transitions back to DISTILLING and you should
CV polling GET /distillations/{id}.
Path Parameters
distillationIdstringrequiredExample: V1StGXR8_Z5jdHi6B3Ui4
Request Body
optionsobjectAnonymization and formatting options applied during distillation. Options omitted from the object are treated as `false`. The defaults below reflect the Distill dashboard defaults — copy them to replicate the out-of-the-box blind-screening preset: ```json { "removeName": true, "removeContact": true, "removeGender": true, "removeAge": true } ```
Responses
200Restart accepted.401Missing or invalid API key.403Distillation belongs to a different organization.404Distillation not found.409Initial extraction not yet complete.