curl -X POST https://api.doctly.ai/api/v1/documents \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "file=@document.pdf" \
-F "accuracy=ultra"
POST /api/v1/documents
Upload a document to convert it to Markdown or process it with a custom extractor. The API supports PDF, DOCX, and image files up to 100MB.
Request
Bearer token authentication. Example: Bearer YOUR_API_KEY
Must be multipart/form-data
Body Parameters
The document file to process. Supported formats: PDF, DOCX, PNG, JPG, JPEG, WEBP, GIF. Provide either file or url, not both.
URL to download the document from. The file will be fetched and processed. Provide either file or url, not both.
Processing accuracy level for Markdown conversion:
lite — Fast processing with great accuracy (default)
ultra — Highest accuracy for complex documents
UUID of a custom extractor to use instead of standard Markdown conversion.
Include page break markers (---) in the Markdown output.
When true, images are not extracted or transcribed from the document.
Webhook URL to receive a POST request when processing completes.
EU Endpoint
For data residency requirements, an EU-based endpoint is available at api.eu.doctly.ai. Documents processed through this endpoint are stored and processed entirely within the European Union.
The EU endpoint only supports the url parameter. Direct file uploads using the file parameter are not available on this endpoint.
curl -X POST https://api.eu.doctly.ai/api/v1/documents \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "url=https://example.com/report.pdf" \
-F "accuracy=ultra"
import requests
url = "https://api.eu.doctly.ai/api/v1/documents"
headers = { "Authorization" : "Bearer YOUR_API_KEY" }
data = {
"url" : "https://example.com/report.pdf" ,
"accuracy" : "ultra"
}
response = requests.post(url, headers = headers, data = data)
print (response.json())
Example Requests
Convert to Markdown
curl -X POST https://api.doctly.ai/api/v1/documents \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "file=@document.pdf" \
-F "accuracy=ultra"
import requests
url = "https://api.doctly.ai/api/v1/documents"
headers = { "Authorization" : "Bearer YOUR_API_KEY" }
with open ( "document.pdf" , "rb" ) as f:
files = { "file" : ( "document.pdf" , f, "application/pdf" )}
data = { "accuracy" : "ultra" }
response = requests.post(url, headers = headers, files = files, data = data)
print (response.json())
const formData = new FormData ();
formData . append ( 'file' , fileInput . files [ 0 ]);
formData . append ( 'accuracy' , 'ultra' );
const response = await fetch ( 'https://api.doctly.ai/api/v1/documents' , {
method: 'POST' ,
headers: {
'Authorization' : 'Bearer YOUR_API_KEY'
},
body: formData
});
const data = await response . json ();
Convert from URL
curl -X POST https://api.doctly.ai/api/v1/documents \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "url=https://example.com/report.pdf" \
-F "accuracy=lite"
import requests
url = "https://api.doctly.ai/api/v1/documents"
headers = { "Authorization" : "Bearer YOUR_API_KEY" }
data = {
"url" : "https://example.com/report.pdf" ,
"accuracy" : "lite"
}
response = requests.post(url, headers = headers, data = data)
print (response.json())
curl -X POST https://api.doctly.ai/api/v1/documents \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "file=@invoice.pdf" \
-F "extractor_id=987fcdeb-a654-3210-9876-543210987654"
import requests
url = "https://api.doctly.ai/api/v1/documents"
headers = { "Authorization" : "Bearer YOUR_API_KEY" }
with open ( "invoice.pdf" , "rb" ) as f:
files = { "file" : ( "invoice.pdf" , f, "application/pdf" )}
data = { "extractor_id" : "987fcdeb-a654-3210-9876-543210987654" }
response = requests.post(url, headers = headers, files = files, data = data)
print (response.json())
Response
Unique identifier (UUID) for the document
Original filename of the uploaded document
Size of the file in bytes
Number of pages in the document (null until processed)
Processing status: PENDING, PROCESSING, COMPLETED, FAILED, or EXPIRED
Selected accuracy level: lite or ultra
UUID of the extractor used (if any)
Extractor details (if using custom extraction)
ISO 8601 timestamp of creation
Example Responses
200 OK — Markdown Conversion
200 OK — With Extractor
400 Bad Request
400 Bad Request — Password Protected
413 Payload Too Large
422 Unprocessable Entity
{
"id" : "123e4567-e89b-12d3-a456-426614174000" ,
"file_name" : "document.pdf" ,
"file_size" : 1048576 ,
"page_count" : 12 ,
"status" : "PENDING" ,
"accuracy" : "ultra" ,
"created_at" : "2024-03-21T13:45:00Z"
}
{
"id" : "123e4567-e89b-12d3-a456-426614174000" ,
"file_name" : "invoice.pdf" ,
"file_size" : 524288 ,
"page_count" : 2 ,
"status" : "PENDING" ,
"extractor_id" : "987fcdeb-a654-3210-9876-543210987654" ,
"extractor" : {
"id" : "987fcdeb-a654-3210-9876-543210987654" ,
"name" : "Invoice Extractor" ,
"slug" : "invoice-extractor" ,
"cost_type" : "PER_PAGE" ,
"cost_credits" : 5
},
"created_at" : "2024-03-21T13:45:00Z"
}
{
"detail" : "Unsupported file type '.exe'. Supported types are: .pdf, .docx, .png, .jpg, .jpeg, .webp, .gif"
}
{
"detail" : "Cannot process password-protected PDF files"
}
{
"detail" : "File size exceeds maximum limit of 100MB"
}
{
"detail" : [
{
"loc" : [ "body" , "file" ],
"msg" : "field required" ,
"type" : "value_error.missing"
}
]
}
Webhooks
When callback_url is provided, a POST request is sent when processing completes:
{
"document_id" : "123e4567-e89b-12d3-a456-426614174000" ,
"file_name" : "document.pdf" ,
"status" : "COMPLETED"
}
Webhooks retry up to 3 times with 5-second delays if delivery fails. URLs must be HTTPS and publicly accessible.
Next Steps
After creating a document, poll Get Document until status is COMPLETED or FAILED. The output_file_url provides a signed download link for the result.
# Poll until complete
DOC_ID = "123e4567-e89b-12d3-a456-426614174000"
while true ; do
RESP = $( curl -s https://api.doctly.ai/api/v1/documents/ $DOC_ID \
-H "Authorization: Bearer YOUR_API_KEY" )
STATUS = $( echo $RESP | jq -r '.status' )
echo "Status: $STATUS "
if [ " $STATUS " = "COMPLETED" ] || [ " $STATUS " = "FAILED" ]; then
echo $RESP | jq '.output_file_url'
break
fi
sleep 5
done
import time
import requests
doc_id = "123e4567-e89b-12d3-a456-426614174000"
headers = { "Authorization" : "Bearer YOUR_API_KEY" }
while True :
resp = requests.get(
f "https://api.doctly.ai/api/v1/documents/ { doc_id } " ,
headers = headers
).json()
print ( f "Status: { resp[ 'status' ] } " )
if resp[ "status" ] in ( "COMPLETED" , "FAILED" ):
if resp[ "status" ] == "COMPLETED" :
print ( f "Download: { resp[ 'output_file_url' ] } " )
break
time.sleep( 5 )