Integration Guide
Integrate powerful AI document extraction into your application with our simple API and embeddable UI components.
Create an API key from your dashboard under Settings → API Keys
Use our embeddable UI, React components, or REST API
Upload documents and receive structured data instantly
File type and size limits vary by endpoint. Maximum file size is 10MB for all uploads.
| Endpoint | Accepted types |
|---|---|
POST /api/embed/extract | PDF (application/pdf), JPEG, PNG, WebP (image/jpeg, image/png, image/webp) |
POST /api/embed/files | PDF, JPEG, PNG, WebP, plain text (text/plain), Word (.doc, .docx) |
The simplest way to integrate. Just add an iframe to your page and you're ready to go.
Embed the file upload interface for users to upload and extract documents.
<iframe
src="https://extractor.decoded.digital/embed?apiKey=YOUR_API_KEY&userEmail=user@example.com&appName=my-app"
width="100%"
height="600"
frameborder="0"
allow="clipboard-write"
></iframe>Embed the documents management page to create, edit, and delete document templates with custom extraction fields.
<iframe
src="https://extractor.decoded.digital/embed/documents?apiKey=YOUR_API_KEY&userEmail=user@example.com&appName=my-app"
width="100%"
height="700"
frameborder="0"
></iframe>Embed the extractions page with tabbed navigation by document type, search, and pagination.
<iframe
src="https://extractor.decoded.digital/embed/extractions?apiKey=YOUR_API_KEY&userEmail=user@example.com&appName=my-app"
width="100%"
height="700"
frameborder="0"
></iframe>Embed the settings page with tabbed UI for managing Microsoft integrations, outbound webhooks, and API keys.
<iframe
src="https://extractor.decoded.digital/embed/settings?apiKey=YOUR_API_KEY&userEmail=user@example.com&appName=my-app"
width="100%"
height="700"
frameborder="0"
style="border: 1px solid #e5e7eb; border-radius: 8px;"
></iframe>/embed - File upload and extraction/embed/documents - Document template management (create, edit, delete)/embed/extractions - View all extractions with search, filters, and file preview/embed/settings - Settings with tabs for Microsoft integrations, webhooks, and API keys// Listen for extraction completion
window.addEventListener('message', (event) => {
if (event.data.type === 'extraction-complete') {
console.log('Extraction completed:', event.data.data);
// { extractionId, fileName, status, ... }
}
if (event.data.type === 'extraction-selected') {
console.log('Extraction selected:', event.data.data);
// Full extraction details including extractedData
}
});Full API access for custom integrations. All endpoints require API key authentication.
All requests require an API key and user email. The user must exist in your tenant.
# Method 1: Custom headers (recommended)
X-API-Key: ext_xxx... # Your API key
X-User-Email: user@example.com # User email (must exist in tenant)
X-App-Name: my-app # Optional: identify your app
# Method 2: Bearer token
Authorization: Bearer ext_xxx...
# Method 3: Query parameters (for iframes)
?apiKey=ext_xxx...&userEmail=user@example.com&appName=my-app/api/embed/verifyVerify API key and user, get tenant information
curl -H "X-API-Key: ext_xxx" \
-H "X-User-Email: user@example.com" \
https://extractor.decoded.digital/api/embed/verifyResponse (data):
{
"valid": true,
"tenantId": "507f1f77bcf86cd799439011",
"apiKeyName": "My API Key",
"userEmail": "user@example.com",
"message": "API key is valid"
}/api/embed/extractUpload a file and start extraction
curl -X POST \
-H "X-API-Key: ext_xxx" \
-H "X-User-Email: user@example.com" \
-H "X-App-Name: my-app" \
-F "file=@document.pdf" \
https://extractor.decoded.digital/api/embed/extractResponse:
{
"data": {
"success": true,
"extractionId": "507f1f77bcf86cd799439011",
"fileName": "document.pdf",
"fileType": "application/pdf",
"fileUrl": "https://...",
"status": "processing",
"message": "File uploaded and extraction started"
},
"error": null
}/api/embed/extractionsList all extractions with pagination and optional filters
Query Parameters:
page - Page number (default: 1)limit - Items per page (default: 20)status - Filter by status (uploaded, analyzing, analyzed, extracting, completed, analysis failed, extraction failed, failed)documentId - Filter by document template IDsearch - Search by file namecurl -H "X-API-Key: ext_xxx" \
-H "X-User-Email: user@example.com" \
"https://extractor.decoded.digital/api/embed/extractions?page=1&limit=20&status=completed"Response (data):
{
"items": [
{
"id": "...",
"fileName": "doc.pdf",
"fileType": "application/pdf",
"fileSize": 12345,
"fileUrl": "https://...",
"status": "completed",
"documentId": "...",
"documentName": "Invoice",
"source": "embed",
"appName": "my-app",
"email": {
"from": { "emailAddress": { "name": "John", "address": "john@example.com" } },
"toRecipients": [
{ "emailAddress": { "name": "Jane", "address": "jane@example.com" } }
],
"ccRecipients": [],
"subject": "Invoice #1234",
"bodyPreview": "Please find attached..."
},
"createdAt": "...",
"updatedAt": "..."
}
],
"pagination": {
"page": 1,
"limit": 20,
"totalCount": 100,
"totalPages": 5,
"hasNextPage": true,
"hasPrevPage": false
}
}/api/embed/extractions/:idGet extraction details including extracted data
curl -H "X-API-Key: ext_xxx" \
-H "X-User-Email: user@example.com" \
https://extractor.decoded.digital/api/embed/extractions/507f1f77bcf86cd799439011Response (data):
{
"id": "507f1f77bcf86cd799439011",
"fileName": "doc.pdf",
"fileType": "application/pdf",
"fileSize": 12345,
"fileUrl": "https://...",
"status": "completed",
"extractedData": { "vendor_name": "...", "total": "..." },
"error": null,
"documentId": "...",
"document": {
"id": "...",
"name": "Invoice",
"description": "...",
"fields": []
},
"source": "embed",
"appName": "my-app",
"email": {
"from": { "emailAddress": { "name": "John", "address": "john@example.com" } },
"toRecipients": [
{ "emailAddress": { "name": "Jane", "address": "jane@example.com" } }
],
"ccRecipients": [],
"subject": "Invoice #1234",
"bodyPreview": "Please find attached...",
"body": { "contentType": "html", "content": "<html>...</html>" }
},
"createdAt": "...",
"updatedAt": "..."
}/api/embed/documentsList available document templates with pagination
Query Parameters:
page - Page number (default: 1)limit - Items per page (default: 20)search - Search by name or descriptioncurl -H "X-API-Key: ext_xxx" \
-H "X-User-Email: user@example.com" \
"https://extractor.decoded.digital/api/embed/documents?page=1&limit=20"Response (data):
{
"items": [
{
"_id": "...",
"name": "Invoice",
"description": "...",
"fields": [{ "key": "...", "type": "String", "description": "..." }],
"createdAt": "...",
"updatedAt": "..."
}
],
"pagination": {
"page": 1,
"limit": 20,
"totalCount": 10,
"totalPages": 1,
"hasNextPage": false,
"hasPrevPage": false
}
}/api/embed/documents/:idGet a specific document template with field definitions
curl -H "X-API-Key: ext_xxx" \
-H "X-User-Email: user@example.com" \
https://extractor.decoded.digital/api/embed/documents/507f1f77bcf86cd799439011Response (data):
{
"id": "507f1f77bcf86cd799439011",
"name": "Invoice",
"description": "Invoice template",
"fields": [{ "key": "vendor_name", "type": "String", "description": "Vendor name" }],
"createdAt": "...",
"updatedAt": "..."
}/api/embed/documentsCreate a new document template with extraction fields. Each field requires a key, type, and description.
Supported Field Types:
StringNumberBooleanDateObjectList<String>List<Object>Use children array on Object and List<Object> fields to define nested field structures.
curl -X POST \
-H "X-API-Key: ext_xxx" \
-H "X-User-Email: user@example.com" \
-H "Content-Type: application/json" \
-d '{
"name": "Invoice",
"description": "Invoice document template",
"fields": [
{ "id": "1", "key": "vendor_name", "type": "String", "description": "Vendor name" },
{ "id": "2", "key": "total", "type": "String", "description": "Total amount" }
]
}' \
https://extractor.decoded.digital/api/embed/documentsResponse (data):
{
"_id": "507f1f77bcf86cd799439011",
"name": "Invoice",
"description": "Invoice document template",
"fields": [...],
"createdAt": "...",
"updatedAt": "..."
}/api/embed/documents/:idUpdate an existing document template
curl -X PUT \
-H "X-API-Key: ext_xxx" \
-H "X-User-Email: user@example.com" \
-H "Content-Type: application/json" \
-d '{
"name": "Invoice (Updated)",
"description": "Updated invoice template",
"fields": [...]
}' \
https://extractor.decoded.digital/api/embed/documents/507f1f77bcf86cd799439011Response (data): same shape as Create Document
/api/embed/documents/:idDelete a document template
curl -X DELETE \
-H "X-API-Key: ext_xxx" \
-H "X-User-Email: user@example.com" \
https://extractor.decoded.digital/api/embed/documents/507f1f77bcf86cd799439011Response (data):
{ "deleted": true, "id": "507f1f77bcf86cd799439011" }/api/embed/extractions/:idDelete an extraction
curl -X DELETE \
-H "X-API-Key: ext_xxx" \
-H "X-User-Email: user@example.com" \
https://extractor.decoded.digital/api/embed/extractions/507f1f77bcf86cd799439011Response (data):
{ "deleted": true, "id": "507f1f77bcf86cd799439011" }/api/embed/extractions/:id/retryRetry a failed extraction. Only extractions with status analysis failed, extraction failed, or failed can be retried.
curl -X POST \
-H "X-API-Key: ext_xxx" \
-H "X-User-Email: user@example.com" \
https://extractor.decoded.digital/api/embed/extractions/507f1f77bcf86cd799439011/retryResponse (data):
{
"success": true,
"extractionId": "507f1f77bcf86cd799439011",
"message": "Extraction retry initiated"
}/api/embed/filesList all uploaded files with pagination
Query Parameters:
page - Page number (default: 1)limit - Items per page (default: 20)search - Search by file namefileType - Filter by MIME typecurl -H "X-API-Key: ext_xxx" \
-H "X-User-Email: user@example.com" \
"https://extractor.decoded.digital/api/embed/files?page=1&limit=20"Response (data):
{
"items": [
{
"id": "...",
"fileName": "doc.pdf",
"fileType": "application/pdf",
"fileSize": 12345,
"fileUrl": "https://...",
"status": "uploaded",
"source": "embed",
"appName": "my-app",
"createdAt": "...",
"updatedAt": "..."
}
],
"pagination": {
"page": 1,
"limit": 20,
"totalCount": 50,
"totalPages": 3,
"hasNextPage": true,
"hasPrevPage": false
}
}/api/embed/filesUpload a file without immediate extraction (supports PDF, images, text, Word docs)
curl -X POST \
-H "X-API-Key: ext_xxx" \
-H "X-User-Email: user@example.com" \
-H "X-App-Name: my-app" \
-F "file=@document.pdf" \
-F "description=Invoice document" \
https://extractor.decoded.digital/api/embed/filesResponse (data):
{
"id": "507f1f77bcf86cd799439011",
"fileName": "document.pdf",
"fileType": "application/pdf",
"fileSize": 12345,
"fileUrl": "https://...",
"status": "uploaded",
"message": "File uploaded successfully"
}/api/embed/webhooksList all webhooks for the authenticated tenant
curl -H "X-API-Key: ext_xxx" \
-H "X-User-Email: user@example.com" \
https://extractor.decoded.digital/api/embed/webhooksResponse (data):
[
{
"_id": "507f1f77bcf86cd799439011",
"name": "My Webhook",
"url": "https://example.com/webhook",
"scope": "all",
"documentIds": [],
"isActive": true,
"tenantId": "...",
"createdAt": "...",
"updatedAt": "..."
}
]/api/embed/webhooksCreate a new outbound webhook to receive notifications when extractions complete
curl -X POST \
-H "X-API-Key: ext_xxx" \
-H "X-User-Email: user@example.com" \
-H "Content-Type: application/json" \
-d '{
"name": "My Webhook",
"url": "https://example.com/webhook",
"scope": "all",
"documentIds": []
}' \
https://extractor.decoded.digital/api/embed/webhooksRequest Body:
name (required) - Webhook display nameurl (required) - HTTPS endpoint URLscope - "all" (default) or "selected"documentIds - Array of document template IDs (required when scope is "selected")Response (data): created webhook object (HTTP 201)
/api/embed/webhooks/:idUpdate an existing webhook. All fields are optional.
curl -X PUT \
-H "X-API-Key: ext_xxx" \
-H "X-User-Email: user@example.com" \
-H "Content-Type: application/json" \
-d '{
"name": "Updated Webhook",
"url": "https://example.com/new-webhook",
"isActive": false,
"scope": "selected",
"documentIds": ["507f1f77bcf86cd799439011"]
}' \
https://extractor.decoded.digital/api/embed/webhooks/507f1f77bcf86cd799439011Response (data): updated webhook object
/api/embed/webhooks/:idDelete a webhook
curl -X DELETE \
-H "X-API-Key: ext_xxx" \
-H "X-User-Email: user@example.com" \
https://extractor.decoded.digital/api/embed/webhooks/507f1f77bcf86cd799439011Response (data):
{ "message": "Webhook deleted successfully", "deletedId": "507f1f77bcf86cd799439011" }/api/embed/api-keysList all API keys for the authenticated tenant
curl -H "X-API-Key: ext_xxx" \
-H "X-User-Email: user@example.com" \
https://extractor.decoded.digital/api/embed/api-keysResponse (data):
[
{
"_id": "507f1f77bcf86cd799439011",
"name": "Production Key",
"key": "ext_abc123...",
"isActive": true,
"expiresAt": null,
"allowedDomains": ["example.com"],
"usageCount": 42,
"lastUsedAt": "...",
"createdAt": "...",
"updatedAt": "..."
}
]/api/embed/api-keysCreate a new API key. The full key is only returned once in this response — store it securely.
curl -X POST \
-H "X-API-Key: ext_xxx" \
-H "X-User-Email: user@example.com" \
-H "Content-Type: application/json" \
-d '{
"name": "Staging Key",
"expiresAt": "2026-12-31T00:00:00Z",
"allowedDomains": ["staging.example.com"]
}' \
https://extractor.decoded.digital/api/embed/api-keysRequest Body:
name (required) - Display name for the keyexpiresAt (optional) - ISO 8601 expiration date (must be in the future)allowedDomains (optional) - Array of allowed domains for iframe embedsResponse (data): created API key object with full key value (HTTP 201)
/api/embed/api-keys/:idUpdate an existing API key. You cannot deactivate the key you are currently using for authentication.
curl -X PUT \
-H "X-API-Key: ext_xxx" \
-H "X-User-Email: user@example.com" \
-H "Content-Type: application/json" \
-d '{
"name": "Renamed Key",
"isActive": true,
"expiresAt": "2027-06-30T00:00:00Z",
"allowedDomains": ["example.com", "*.example.com"]
}' \
https://extractor.decoded.digital/api/embed/api-keys/507f1f77bcf86cd799439011Response (data): updated API key object
/api/embed/api-keys/:idDelete an API key. You cannot delete the key you are currently using for authentication.
curl -X DELETE \
-H "X-API-Key: ext_xxx" \
-H "X-User-Email: user@example.com" \
https://extractor.decoded.digital/api/embed/api-keys/507f1f77bcf86cd799439011Response (data):
{ "message": "API key deleted successfully", "deletedId": "507f1f77bcf86cd799439011" }/api/embed/tenants/:idGet your tenant details including integration status. You can only access your own tenant.
curl -H "X-API-Key: ext_xxx" \
-H "X-User-Email: user@example.com" \
https://extractor.decoded.digital/api/embed/tenants/507f1f77bcf86cd799439011Response (data):
{
"_id": "507f1f77bcf86cd799439011",
"name": "Acme Corp",
"status": "active",
"integrations": {
"microsoft": {
"accounts": [
{
"accountId": "...",
"email": "user@acme.com",
"connectedAt": "..."
}
]
}
},
"createdAt": "...",
"updatedAt": "..."
}If you're integrating Extractor into your application, use these endpoints to onboard your organization and manage users programmatically. This creates a tenant, admin user, and API key in one call.
/api/embed/onboardSetup Key RequiredCreate a new tenant, owner user, and API key in one call. This is used for initial integration setup. Store the returned API key securely - it won't be shown again.
X-Setup-Key: your-setup-key # Provided by Extractor team{
"organizationName": "Acme Corp", // Required: Your organization name
"firstName": "John", // Required: Admin user first name
"lastName": "Doe", // Required: Admin user last name
"email": "john@acme.com", // Required: Admin user email
"apiKeyName": "Production API Key", // Optional: Custom name for API key
"allowedDomains": ["acme.com", "*.acme.com"], // Optional: Domain restrictions
"hasExpiry": false, // Optional: Set true for expiring key
"expiryDays": 90, // Optional: Days until expiry (1-365)
"appName": "my-app" // Optional: Identify your app for source tracking
}curl -X POST \
-H "Content-Type: application/json" \
-H "X-Setup-Key: your-setup-key" \
-d '{
"organizationName": "Acme Corp",
"firstName": "John",
"lastName": "Doe",
"email": "john@acme.com"
}' \
https://extractor.decoded.digital/api/embed/onboard{
"data": {
"message": "Successfully onboarded. Store the API key securely - it won't be shown again.",
"tenant": {
"id": "507f1f77bcf86cd799439011",
"name": "Acme Corp"
},
"user": {
"id": "507f1f77bcf86cd799439012",
"firstName": "John",
"lastName": "Doe",
"email": "john@acme.com",
"role": "owner",
"isExistingUser": false
},
"apiKey": {
"id": "507f1f77bcf86cd799439013",
"name": "Acme Corp - Embed API Key",
"key": "ext_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"expiresAt": null,
"allowedDomains": []
}
},
"error": null
}/api/embed/usersAPI Key RequiredCreate a new user in your tenant. Use this when a new user signs up in your application and needs access to Extractor features. Note: This endpoint does NOT require X-User-Email header since you're creating a new user.
{
"firstName": "Jane", // Required
"lastName": "Smith", // Required
"email": "jane@acme.com", // Required
"role": "member" // Optional: "owner", "admin", or "member" (default)
}curl -X POST \
-H "Content-Type: application/json" \
-H "X-API-Key: ext_xxx..." \
-d '{
"firstName": "Jane",
"lastName": "Smith",
"email": "jane@acme.com",
"role": "member"
}' \
https://extractor.decoded.digital/api/embed/users{
"data": {
"message": "User created successfully",
"user": {
"id": "507f1f77bcf86cd799439014",
"firstName": "Jane",
"lastName": "Smith",
"email": "jane@acme.com",
"role": "member",
"createdAt": "2026-03-11T10:30:00.000Z"
}
},
"error": null
}Note: If the user already exists globally but is not yet a member of your tenant, they will be added to your tenant and the response will return HTTP 200 with message "User added to tenant successfully" instead of 201. If the user already exists in your tenant, you will receive a 409 Conflict error.
/api/embed/usersList all users in your tenant with pagination and search.
Query Parameters:
page - Page number (default: 1)limit - Items per page (default: 20)search - Search by name or emailcurl -H "X-API-Key: ext_xxx..." \
-H "X-User-Email: admin@acme.com" \
"https://extractor.decoded.digital/api/embed/users?page=1&limit=20"Response (data):
{
"items": [
{
"id": "...",
"firstName": "Jane",
"lastName": "Smith",
"email": "jane@acme.com",
"role": "member",
"createdAt": "...",
"updatedAt": "..."
}
],
"pagination": {
"page": 1,
"limit": 20,
"totalCount": 5,
"totalPages": 1,
"hasNextPage": false,
"hasPrevPage": false
}
}/api/embed/onboard with your setup key to create your organization, admin user, and get your API key.POST /api/embed/users to create them in your tenant.{
"data": {
// Response data here
},
"error": null
}{
"data": null,
"error": "Error message describing what went wrong"
}All errors return { "data": null, "error": "message" }. Use the HTTP status code and error message to resolve issues.
firstName is required, Invalid email format)X-API-Key, Authorization: Bearer, or apiKey query param)/api/embed/onboard)allowedDomains)POST /api/embed/users)When creating an API key, you can restrict which domains can use it for iframe embedding. This prevents unauthorized sites from using your embed.
# Examples of domain restrictions:
example.com # Exact match
*.example.com # All subdomains
app.example.com # Specific subdomain
localhost # Local developmentExtractions with status analysis failed, extraction failed, or failed can be retried via POST /api/embed/extractions/:id/retry. The extraction will be reset to uploaded and re-processed from the beginning.
Our team is here to help you integrate Extractor into your application. Reach out for technical support or custom integration requirements.