API Documentation
Complete guide with code examples in multiple languages
🚀 Quick Start
Get Started in 3 Steps
- Sign up and get your API key from the API Keys page
- Request a signed upload URL with your desired OCR mode
- Upload your image and poll for results
Base URL
Supported Image Formats
🔐 Authentication
All API requests require authentication using an API key in the request header.
X-API-Key: ocr_your_api_key_here
Account Tiers
| Tier | Monthly Limit | Duration |
|---|---|---|
| Trial | 1,000 requests | 30 days |
| Standard | 1,000 requests | Monthly |
| Pro | 10,000 requests | Monthly |
| Enterprise | Unlimited | Custom |
📡 API Endpoints
List Available OCR Modes
/ocr-modes
Get all OCR modes available for your account, including custom modes.
curl -X GET "https://api.deepreadocr.com/api/v1/ocr-modes" \
-H "X-API-Key: your_api_key_here"
import requests
response = requests.get(
"https://api.deepreadocr.com/api/v1/ocr-modes",
headers={"X-API-Key": "your_api_key_here"}
)
modes = response.json()
print(modes)
const axios = require('axios');
const response = await axios.get(
'https://api.deepreadocr.com/api/v1/ocr-modes',
{ headers: { 'X-API-Key': 'your_api_key_here' } }
);
console.log(response.data);
Response Example
[
{
"name": "ocr",
"display_name": "General OCR",
"description": "Extract all text from the image",
"is_default": true
},
{
"name": "table",
"display_name": "Table Recognition",
"description": "Extract tables and structured data",
"is_default": false
}
]
Get Upload Signed URL
/upload/signed-url
Request a pre-signed S3 URL for uploading your image.
Query Parameters
| mode | (optional) OCR mode to use. Defaults to your account's default mode. |
Request Body
{
"filename": "document.png",
"content_type": "image/png"
}
curl -X POST "https://api.deepreadocr.com/api/v1/upload/signed-url?mode=ocr" \
-H "X-API-Key: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"filename": "document.png",
"content_type": "image/png"
}'
import requests
response = requests.post(
"https://api.deepreadocr.com/api/v1/upload/signed-url",
headers={"X-API-Key": "your_api_key_here"},
params={"mode": "ocr"},
json={
"filename": "document.png",
"content_type": "image/png"
}
)
data = response.json()
print(data)
const axios = require('axios');
const response = await axios.post(
'https://api.deepreadocr.com/api/v1/upload/signed-url?mode=ocr',
{
filename: 'document.png',
content_type: 'image/png'
},
{ headers: { 'X-API-Key': 'your_api_key_here' } }
);
console.log(response.data);
Response Example
{
"upload_url": "https://s3.amazonaws.com/bucket/uploads/...",
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"s3_key": "uploads/user123/550e8400-.../document.png",
"expires_in": 3600
}
Upload Image to S3
{upload_url}
Upload your image file to the pre-signed URL from the previous step.
curl -X PUT "$UPLOAD_URL" \
-H "Content-Type: image/png" \
--data-binary "@document.png"
import requests
with open("document.png", "rb") as f:
requests.put(
upload_url,
headers={"Content-Type": "image/png"},
data=f
)
const fs = require('fs');
const axios = require('axios');
const imageBuffer = fs.readFileSync('document.png');
await axios.put(uploadUrl, imageBuffer, {
headers: { 'Content-Type': 'image/png' }
});
List Processing Jobs
/processing-jobs
List all processing jobs with their status. Filter by mode or filename.
Query Parameters
| mode | (optional) Filter by OCR mode (e.g., "table", "ocr") |
| filename | (optional) Filter by filename (partial match) |
# List all jobs
curl -X GET "https://api.deepreadocr.com/api/v1/processing-jobs" \
-H "X-API-Key: your_api_key_here"
# Filter by mode
curl -X GET "https://api.deepreadocr.com/api/v1/processing-jobs?mode=table" \
-H "X-API-Key: your_api_key_here"
# Filter by filename
curl -X GET "https://api.deepreadocr.com/api/v1/processing-jobs?filename=invoice" \
-H "X-API-Key: your_api_key_here"
import requests
# List all jobs
response = requests.get(
"https://api.deepreadocr.com/api/v1/processing-jobs",
headers={"X-API-Key": "your_api_key_here"}
)
jobs = response.json()
# Filter by mode
response = requests.get(
"https://api.deepreadocr.com/api/v1/processing-jobs",
headers={"X-API-Key": "your_api_key_here"},
params={"mode": "table", "filename": "invoice"}
)
filtered_jobs = response.json()
const axios = require('axios');
// List all jobs
const response = await axios.get(
'https://api.deepreadocr.com/api/v1/processing-jobs',
{ headers: { 'X-API-Key': 'your_api_key_here' } }
);
// Filter by mode and filename
const filtered = await axios.get(
'https://api.deepreadocr.com/api/v1/processing-jobs',
{
headers: { 'X-API-Key': 'your_api_key_here' },
params: { mode: 'table', filename: 'invoice' }
}
);
Response Example
{
"files": [
{
"filename": "sales_table.png",
"mode": "table",
"status": "completed",
"output_key": "table/sales_table.json",
"size": 18826,
"last_modified": "2025-11-17T14:42:48+00:00"
}
],
"total_count": 1,
"completed_count": 1,
"pending_count": 0
}
Download Result File
/download/signed-url
Get a signed URL to download the OCR result. Use the simplified output_key from processing-jobs.
Query Parameters
| file_path | Use the output_key from processing-jobs (e.g., "table/sales_table.json") |
curl -X POST "https://api.deepreadocr.com/api/v1/download/signed-url?file_path=table/sales_table.json" \
-H "X-API-Key: your_api_key_here"
# Response includes signed URL
# Download the file using the URL
curl -o result.json "$DOWNLOAD_URL"
Response Example
{
"url": "https://s3.amazonaws.com/deepreadocr/...?signature=...",
"file_key": "client-uuid/output/table/sales_table.json",
"expires_in": 3600
}
🎯 OCR Modes
Choose the right OCR mode for your use case. You can also create custom modes in your dashboard.
💡 Multi-Mode Processing
Process the same image with different modes! Each mode creates a separate result file with the mode in the path:
ocr/document.json,
table/document.json,
formula/document.json
📄 General OCR
Extract all text from documents, receipts, and forms.
mode=ocr
📊 Table Recognition
Extract tables and structured data from spreadsheets.
mode=table
🔢 Formula Recognition
Extract mathematical formulas in LaTeX format.
mode=formula
📈 Chart Recognition
Extract data from charts and visualizations.
mode=chart
📝 Document Analysis
Analyze and format documents as structured Markdown.
mode=document
⚡ Rate Limits & Usage
Requests are tracked per calendar month. When your limit is exceeded, the API returns 403 Forbidden.
Rate Limit Headers
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 847
X-RateLimit-Reset: 2024-02-01T00:00:00Z
✓ Check your current usage in the dashboard
✓ Upgrade your tier for higher limits
✓ Implement exponential backoff for retry logic
⚠️ Error Handling
HTTP Status Codes
Error Response Format
{
"detail": "Error message describing what went wrong"
}
💻 Complete Code Examples
🐍 Python (Complete Workflow)
import requests
import time
from pathlib import Path
class DeepReadOCR:
def __init__(self, api_key, base_url="https://api.deepreadocr.com/api/v1"):
self.api_key = api_key
self.base_url = base_url
self.headers = {"X-API-Key": api_key}
def list_modes(self):
"""List available OCR modes."""
response = requests.get(f"{self.base_url}/ocr-modes", headers=self.headers)
response.raise_for_status()
return response.json()
def process_image(self, image_path, mode="ocr", poll_interval=2):
"""Process an image with OCR and return results."""
filename = Path(image_path).name
content_type = self._get_content_type(Path(image_path).suffix)
# Step 1: Get upload URL
response = requests.post(
f"{self.base_url}/upload/signed-url",
headers=self.headers,
params={"mode": mode}
)
response.raise_for_status()
upload_data = response.json()
# Step 2: Upload to S3
with open(image_path, "rb") as f:
form_data = upload_data['fields'].copy()
# Replace placeholder in key
key = form_data.get('key', '').replace('${filename}', filename)
form_data['key'] = key
form_data['Content-Type'] = content_type
requests.post(
upload_data['url'],
data=form_data,
files={'file': (filename, f, content_type)}
)
# Step 3: Poll for completion
base_name = filename.rsplit('.', 1)[0]
while True:
response = requests.get(
f"{self.base_url}/processing-jobs",
headers=self.headers,
params={"filename": base_name, "mode": mode}
)
jobs = response.json()
# Find our job
for job in jobs['files']:
if job['status'] == 'completed' and job['output_key']:
# Step 4: Download result
dl_resp = requests.post(
f"{self.base_url}/download/signed-url",
headers=self.headers,
params={"file_path": job['output_key']}
)
download_url = dl_resp.json()['url']
result = requests.get(download_url).json()
return result
time.sleep(poll_interval)
def _get_content_type(self, extension):
types = {
".png": "image/png",
".jpg": "image/jpeg",
".jpeg": "image/jpeg",
".bmp": "image/bmp",
".pdf": "application/pdf"
}
return types.get(extension.lower(), "application/octet-stream")
# Usage
ocr = DeepReadOCR(api_key="your_api_key_here")
# List modes
modes = ocr.list_modes()
print("Available modes:", [m["name"] for m in modes])
# Process an image
result = ocr.process_image("document.png", mode="table")
print("Mode used:", result["mode"])
print("Extracted text:", result["extracted_text"])
print("Tokens:", result["usage"]["total_tokens"])
🟢 Node.js (Complete Workflow)
const axios = require('axios');
const fs = require('fs');
const path = require('path');
const FormData = require('form-data');
class DeepReadOCR {
constructor(apiKey, baseURL = 'https://api.deepreadocr.com/api/v1') {
this.apiKey = apiKey;
this.baseURL = baseURL;
this.headers = { 'X-API-Key': apiKey };
}
async listModes() {
const response = await axios.get(`${this.baseURL}/ocr-modes`, {
headers: this.headers
});
return response.data;
}
async processImage(imagePath, mode = 'ocr', pollInterval = 2000) {
const fileName = path.basename(imagePath);
const contentType = this.getContentType(path.extname(imagePath));
// Get upload URL
const uploadResponse = await axios.post(
`${this.baseURL}/upload/signed-url?mode=${mode}`,
null,
{ headers: this.headers }
);
const { url, fields, key_prefix } = uploadResponse.data;
// Upload to S3
const form = new FormData();
Object.keys(fields).forEach(key => {
let value = fields[key];
if (key === 'key') value = value.replace('${filename}', fileName);
form.append(key, value);
});
form.append('Content-Type', contentType);
form.append('file', fs.createReadStream(imagePath));
await axios.post(url, form, { headers: form.getHeaders() });
// Poll for completion
const baseName = fileName.replace(/\.[^/.]+$/, '');
while (true) {
const jobsResp = await axios.get(`${this.baseURL}/processing-jobs`, {
headers: this.headers,
params: { filename: baseName, mode }
});
const job = jobsResp.data.files.find(j =>
j.status === 'completed' && j.mode === mode
);
if (job) {
// Download result
const dlResp = await axios.post(
`${this.baseURL}/download/signed-url`,
null,
{ headers: this.headers, params: { file_path: job.output_key } }
);
const result = await axios.get(dlResp.data.url);
return result.data;
}
await new Promise(resolve => setTimeout(resolve, pollInterval));
}
}
getContentType(extension) {
const types = {
'.png': 'image/png',
'.jpg': 'image/jpeg',
'.jpeg': 'image/jpeg',
'.bmp': 'image/bmp',
'.pdf': 'application/pdf'
};
return types[extension.toLowerCase()] || 'application/octet-stream';
}
}
// Usage
(async () => {
const ocr = new DeepReadOCR('your_api_key_here');
const modes = await ocr.listModes();
console.log('Available modes:', modes.map(m => m.name));
const result = await ocr.processImage('./document.png', 'table');
console.log('Mode used:', result.mode);
console.log('Extracted text:', result.extracted_text);
console.log('Tokens:', result.usage.total_tokens);
})();
🔧 cURL (Bash Script)
#!/bin/bash
API_KEY="your_api_key_here"
BASE_URL="https://api.deepreadocr.com/api/v1"
IMAGE_FILE="document.png"
MODE="table"
# Get upload URL
UPLOAD_RESPONSE=$(curl -s -X POST "${BASE_URL}/upload/signed-url?mode=${MODE}" \
-H "X-API-Key: ${API_KEY}")
UPLOAD_URL=$(echo "$UPLOAD_RESPONSE" | jq -r '.url')
KEY=$(echo "$UPLOAD_RESPONSE" | jq -r '.fields.key' | sed "s/\${filename}/${IMAGE_FILE}/")
echo "Uploading to: ${KEY}"
# Upload to S3 (multipart form)
curl -X POST "${UPLOAD_URL}" \
-F "key=${KEY}" \
-F "AWSAccessKeyId=$(echo "$UPLOAD_RESPONSE" | jq -r '.fields.AWSAccessKeyId')" \
-F "policy=$(echo "$UPLOAD_RESPONSE" | jq -r '.fields.policy')" \
-F "signature=$(echo "$UPLOAD_RESPONSE" | jq -r '.fields.signature')" \
-F "Content-Type=image/png" \
-F "file=@${IMAGE_FILE}"
# Poll for completion
BASE_NAME="${IMAGE_FILE%.*}"
while true; do
JOBS=$(curl -s "${BASE_URL}/processing-jobs?filename=${BASE_NAME}&mode=${MODE}" \
-H "X-API-Key: ${API_KEY}")
STATUS=$(echo "$JOBS" | jq -r '.files[0].status')
echo "Status: ${STATUS}"
if [ "$STATUS" = "completed" ]; then
OUTPUT_KEY=$(echo "$JOBS" | jq -r '.files[0].output_key')
# Get download URL
DOWNLOAD=$(curl -s -X POST "${BASE_URL}/download/signed-url?file_path=${OUTPUT_KEY}" \
-H "X-API-Key: ${API_KEY}")
DOWNLOAD_URL=$(echo "$DOWNLOAD" | jq -r '.url')
# Download and display result
curl -s "$DOWNLOAD_URL" | jq
break
fi
sleep 2
done
🐘 PHP (Click to expand)
apiKey = $apiKey;
$this->baseURL = $baseURL;
}
public function processImage($imagePath, $mode = 'ocr') {
// Get upload URL
$fileName = basename($imagePath);
$contentType = $this->getContentType($imagePath);
$ch = curl_init($this->baseURL . '/upload/signed-url?mode=' . $mode);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'X-API-Key: ' . $this->apiKey,
'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'filename' => $fileName,
'content_type' => $contentType
]));
$response = curl_exec($ch);
curl_close($ch);
$uploadData = json_decode($response, true);
$jobId = $uploadData['job_id'];
// Upload to S3
$imageData = file_get_contents($imagePath);
$ch = curl_init($uploadData['upload_url']);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_POSTFIELDS, $imageData);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: ' . $contentType]);
curl_exec($ch);
curl_close($ch);
// Poll for results
while (true) {
$ch = curl_init($this->baseURL . '/results/' . $jobId);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-Key: ' . $this->apiKey]);
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
if ($result['status'] === 'completed') return $result;
if ($result['status'] === 'failed') throw new Exception($result['error']);
sleep(2);
}
}
private function getContentType($path) {
$ext = strtolower(pathinfo($path, PATHINFO_EXTENSION));
$types = ['png' => 'image/png', 'jpg' => 'image/jpeg', 'pdf' => 'application/pdf'];
return $types[$ext] ?? 'application/octet-stream';
}
}
$ocr = new DeepReadOCR('your_api_key_here');
$result = $ocr->processImage('document.png');
echo $result['result']['extracted_text'];
🔷 Go (Click to expand)
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
"time"
)
type DeepReadOCR struct {
APIKey string
BaseURL string
Client *http.Client
}
func NewDeepReadOCR(apiKey string) *DeepReadOCR {
return &DeepReadOCR{
APIKey: apiKey,
BaseURL: "https://api.deepreadocr.com/api/v1",
Client: &http.Client{Timeout: 30 * time.Second},
}
}
func (ocr *DeepReadOCR) ProcessImage(imagePath, mode string) (map[string]interface{}, error) {
// Get upload URL
body, _ := json.Marshal(map[string]string{
"filename": "document.png",
"content_type": "image/png",
})
req, _ := http.NewRequest("POST",
fmt.Sprintf("%s/upload/signed-url?mode=%s", ocr.BaseURL, mode),
bytes.NewBuffer(body))
req.Header.Set("X-API-Key", ocr.APIKey)
req.Header.Set("Content-Type", "application/json")
resp, _ := ocr.Client.Do(req)
var uploadData map[string]interface{}
json.NewDecoder(resp.Body).Decode(&uploadData)
resp.Body.Close()
// Upload to S3
imageData, _ := os.ReadFile(imagePath)
s3Req, _ := http.NewRequest("PUT", uploadData["upload_url"].(string), bytes.NewBuffer(imageData))
s3Req.Header.Set("Content-Type", "image/png")
ocr.Client.Do(s3Req)
// Poll for results
jobID := uploadData["job_id"].(string)
for {
req, _ := http.NewRequest("GET", fmt.Sprintf("%s/results/%s", ocr.BaseURL, jobID), nil)
req.Header.Set("X-API-Key", ocr.APIKey)
resp, _ := ocr.Client.Do(req)
var result map[string]interface{}
json.NewDecoder(resp.Body).Decode(&result)
resp.Body.Close()
if result["status"] == "completed" {
return result, nil
}
time.Sleep(2 * time.Second)
}
}
func main() {
ocr := NewDeepReadOCR("your_api_key_here")
result, _ := ocr.ProcessImage("document.png", "ocr")
fmt.Println(result)
}
💎 Ruby (Click to expand)
require 'net/http'
require 'json'
class DeepReadOCR
def initialize(api_key, base_url = 'https://api.deepreadocr.com/api/v1')
@api_key = api_key
@base_url = base_url
end
def process_image(image_path, mode = 'ocr')
# Get upload URL
uri = URI("#{@base_url}/upload/signed-url?mode=#{mode}")
request = Net::HTTP::Post.new(uri)
request['X-API-Key'] = @api_key
request['Content-Type'] = 'application/json'
request.body = { filename: File.basename(image_path), content_type: 'image/png' }.to_json
response = Net::HTTP.start(uri.hostname, uri.port) { |http| http.request(request) }
upload_data = JSON.parse(response.body)
# Upload to S3
uri = URI(upload_data['upload_url'])
request = Net::HTTP::Put.new(uri)
request['Content-Type'] = 'image/png'
request.body = File.read(image_path)
Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
# Poll for results
loop do
uri = URI("#{@base_url}/results/#{upload_data['job_id']}")
request = Net::HTTP::Get.new(uri)
request['X-API-Key'] = @api_key
response = Net::HTTP.start(uri.hostname, uri.port) { |http| http.request(request) }
result = JSON.parse(response.body)
return result if result['status'] == 'completed'
sleep 2
end
end
end
ocr = DeepReadOCR.new('your_api_key_here')
result = ocr.process_image('document.png')
puts result['result']['extracted_text']