curl --request POST \
--url https://api.example.com/api/v1/analyze \
--header 'Content-Type: multipart/form-data' \
--form 'schema=<string>' \
--form 'file=<string>' \
--form 'url=<string>' \
--form 'url_headers=<string>' \
--form include_steps=false \
--form sync=true \
--form 'webhook_url=<string>' \
--form file.0='@example-file'import requests
url = "https://api.example.com/api/v1/analyze"
files = { "file.0": ("example-file", open("example-file", "rb")) }
payload = {
"schema": "<string>",
"file": "<string>",
"url": "<string>",
"url_headers": "<string>",
"include_steps": "false",
"sync": "true",
"webhook_url": "<string>"
}
response = requests.post(url, data=payload, files=files)
print(response.text)const form = new FormData();
form.append('schema', '<string>');
form.append('file', '<string>');
form.append('url', '<string>');
form.append('url_headers', '<string>');
form.append('include_steps', 'false');
form.append('sync', 'true');
form.append('webhook_url', '<string>');
form.append('file.0', '{
"fileName": "example-file"
}');
const options = {method: 'POST'};
options.body = form;
fetch('https://api.example.com/api/v1/analyze', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/api/v1/analyze",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"schema\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"url\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"url_headers\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"include_steps\"\r\n\r\nfalse\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"sync\"\r\n\r\ntrue\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"webhook_url\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file.0\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n{\r\n \"fileName\": \"example-file\"\r\n}\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Content-Type: multipart/form-data"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/api/v1/analyze"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"schema\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"url\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"url_headers\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"include_steps\"\r\n\r\nfalse\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"sync\"\r\n\r\ntrue\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"webhook_url\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file.0\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n{\r\n \"fileName\": \"example-file\"\r\n}\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("POST", url, payload)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.example.com/api/v1/analyze")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"schema\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"url\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"url_headers\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"include_steps\"\r\n\r\nfalse\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"sync\"\r\n\r\ntrue\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"webhook_url\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file.0\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n{\r\n \"fileName\": \"example-file\"\r\n}\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/api/v1/analyze")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"schema\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"url\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"url_headers\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"include_steps\"\r\n\r\nfalse\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"sync\"\r\n\r\ntrue\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"webhook_url\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file.0\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n{\r\n \"fileName\": \"example-file\"\r\n}\r\n-----011000010111000001101001--"
response = http.request(request)
puts response.read_body{
"confidence": {
"is_overdue": 0.72,
"total_cost": 0.95
},
"content_type": "application/pdf",
"credits_used": 10,
"data": {
"is_overdue": true,
"total_cost": 1500
},
"filename": "invoice.pdf",
"model_used": "gpt-5.1",
"reasoning": {
"is_overdue": "Due date 2025-01-15 has passed.",
"total_cost": "Summed 3 line items: $500 + $600 + $400"
},
"sources": {
"is_overdue": [
"Due Date: January 15, 2025"
],
"total_cost": [
"Item A: $500",
"Item B: $600",
"Item C: $400"
]
},
"success": true,
"text_length": 3200,
"total_pages": 5
}{
"detail": "File size exceeds maximum allowed (50MB)",
"error": "validation_error",
"success": false
}{
"detail": "File size exceeds maximum allowed (50MB)",
"error": "validation_error",
"success": false
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>",
"input": "<unknown>",
"ctx": {}
}
]
}{
"detail": "File size exceeds maximum allowed (50MB)",
"error": "validation_error",
"success": false
}Analyze Document
Analyze a document by asking questions. Unlike /extract, this endpoint
can compute, reason, and derive values that aren’t explicitly written
in the document.
Upload a file (or provide a URL) along with a typed schema. Each field
must have a type and description.
Example schema:
{
"total_cost": {"type": "number", "description": "Sum all line item amounts"},
"is_auto_renew": {"type": "boolean", "description": "Does this contract auto-renew?"},
"risk_level": {"type": "string", "enum": ["low", "medium", "high"], "description": "Legal risk level"}
}
Supported types: string, number, integer, boolean, array, object
Every answer includes:
- The computed answer (type-enforced)
- Reasoning explaining how it was derived
- Source text snippets from the document
- Confidence level
Pricing: 2 credits/page (min 5) for documents, 10 credits for websites.
curl --request POST \
--url https://api.example.com/api/v1/analyze \
--header 'Content-Type: multipart/form-data' \
--form 'schema=<string>' \
--form 'file=<string>' \
--form 'url=<string>' \
--form 'url_headers=<string>' \
--form include_steps=false \
--form sync=true \
--form 'webhook_url=<string>' \
--form file.0='@example-file'import requests
url = "https://api.example.com/api/v1/analyze"
files = { "file.0": ("example-file", open("example-file", "rb")) }
payload = {
"schema": "<string>",
"file": "<string>",
"url": "<string>",
"url_headers": "<string>",
"include_steps": "false",
"sync": "true",
"webhook_url": "<string>"
}
response = requests.post(url, data=payload, files=files)
print(response.text)const form = new FormData();
form.append('schema', '<string>');
form.append('file', '<string>');
form.append('url', '<string>');
form.append('url_headers', '<string>');
form.append('include_steps', 'false');
form.append('sync', 'true');
form.append('webhook_url', '<string>');
form.append('file.0', '{
"fileName": "example-file"
}');
const options = {method: 'POST'};
options.body = form;
fetch('https://api.example.com/api/v1/analyze', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/api/v1/analyze",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"schema\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"url\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"url_headers\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"include_steps\"\r\n\r\nfalse\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"sync\"\r\n\r\ntrue\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"webhook_url\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file.0\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n{\r\n \"fileName\": \"example-file\"\r\n}\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Content-Type: multipart/form-data"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/api/v1/analyze"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"schema\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"url\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"url_headers\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"include_steps\"\r\n\r\nfalse\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"sync\"\r\n\r\ntrue\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"webhook_url\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file.0\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n{\r\n \"fileName\": \"example-file\"\r\n}\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("POST", url, payload)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.example.com/api/v1/analyze")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"schema\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"url\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"url_headers\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"include_steps\"\r\n\r\nfalse\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"sync\"\r\n\r\ntrue\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"webhook_url\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file.0\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n{\r\n \"fileName\": \"example-file\"\r\n}\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/api/v1/analyze")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"schema\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"url\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"url_headers\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"include_steps\"\r\n\r\nfalse\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"sync\"\r\n\r\ntrue\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"webhook_url\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file.0\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n{\r\n \"fileName\": \"example-file\"\r\n}\r\n-----011000010111000001101001--"
response = http.request(request)
puts response.read_body{
"confidence": {
"is_overdue": 0.72,
"total_cost": 0.95
},
"content_type": "application/pdf",
"credits_used": 10,
"data": {
"is_overdue": true,
"total_cost": 1500
},
"filename": "invoice.pdf",
"model_used": "gpt-5.1",
"reasoning": {
"is_overdue": "Due date 2025-01-15 has passed.",
"total_cost": "Summed 3 line items: $500 + $600 + $400"
},
"sources": {
"is_overdue": [
"Due Date: January 15, 2025"
],
"total_cost": [
"Item A: $500",
"Item B: $600",
"Item C: $400"
]
},
"success": true,
"text_length": 3200,
"total_pages": 5
}{
"detail": "File size exceeds maximum allowed (50MB)",
"error": "validation_error",
"success": false
}{
"detail": "File size exceeds maximum allowed (50MB)",
"error": "validation_error",
"success": false
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>",
"input": "<unknown>",
"ctx": {}
}
]
}{
"detail": "File size exceeds maximum allowed (50MB)",
"error": "validation_error",
"success": false
}Headers
Body
JSON schema — keys are field names, values describe what to compute or answer
File to analyze
URL to fetch file from
JSON-encoded headers for URL auth
Include the agent's reasoning trace (tool calls) in each answer
Set to false to process asynchronously. Returns a task_id to poll.
URL to POST the result to when async processing completes. Signed with HMAC-SHA256 (see GET /api/v1/jobs/{task_id}/deliveries for verification docs).
Response
Successful Response
Response for document analysis — flat parallel dicts matching /extract.
Computed/derived values keyed by field name
Original filename or URL
Model used for analysis
Length of extracted text
Per-field confidence scores (0.0–1.0)
Show child attributes
Show child attributes
Per-field source text snippets from the document
Show child attributes
Show child attributes
Per-field step-by-step explanation of how the answer was derived
Show child attributes
Show child attributes
Per-field agent reasoning trace (tool calls). Empty unless include_steps=true.
Show child attributes
Show child attributes
Detected MIME type
Total pages in the document (0 for non-paginated files)
Credits consumed
Schema format: always 'typed'
typed