Step 3 (PDF/image): finalize a document upload and extract text synchronously.
Call after PUT-ing the PDF or image to the signed URL. Server downloads the bytes, runs magic-byte verification, extracts text (unpdf for PDFs, Claude vision OCR for images), generates a thumbnail, creates the user_items row, and DELETES the original file from Storage (the contents row only carries the transcript + thumbnail path — PDFs and images are ephemeral in document-uploads by design). Returns status='ready' — no async polling needed. Image OCR counts against the user's transform quota; PDFs are free. Rate limit: 30/hr per token.
Call after PUT-ing the PDF or image to the signed URL. Server downloads the bytes, runs magic-byte verification, extracts text (unpdf for PDFs, Claude vision OCR for images), generates a thumbnail, creates the user_items row, and DELETES the original file from Storage (the contents row only carries the transcript + thumbnail path — PDFs and images are ephemeral in document-uploads by design). Returns status='ready' — no async polling needed. Image OCR counts against the user's transform quota; PDFs are free. Rate limit: 30/hr per token.
Authorization
bearerAuth Per-user bearer token minted at /settings/integrations. Format: 'lev_' followed by 32 base64url chars. Each token carries a capability set (read | write) and a folder scope (whole library or a list of specific folders). Per-endpoint requirements are noted on each operation.
In: header
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/uploads/finalize-document" \ -H "Content-Type: application/json" \ -d '{ "path": "string", "mime": "string", "size": 1 }'{
"status": "ready",
"user_item_id": "bdbfc5c1-4635-4d6b-a226-2cb5d7e08712",
"content_id": "713e4c61-5a69-43fb-a600-2e2699462e14",
"folder_id": "7695bac3-9397-4ec2-9335-45a2a16f1901"
}{
"error": "string",
"message": "string"
}{
"error": "string",
"message": "string"
}{
"error": "quota_exceeded",
"resource": "transcription_minutes",
"tier": "free",
"cap_per_month": 0,
"message": "string"
}{
"error": "string",
"message": "string"
}{
"error": "string",
"message": "string"
}{
"error": "string",
"message": "string"
}{
"error": "string",
"message": "string"
}{
"error": "rate_limited",
"retry_after_sec": 0
}{
"error": "string",
"message": "string"
}Step 3 (audio/video): finalize a media upload and submit for transcription. POST
Call after PUT-ing the file to the signed URL. Server downloads the bytes, runs magic-byte verification (so a renamed evil.mp3 with non-MP3 bytes is rejected), creates the contents + user_items rows, reserves transcription minutes against the user's monthly quota, and submits the file to AssemblyAI. Returns immediately with status='transcribing' — poll GET /items/{id} until transcription_status === 'done'. Single-folder-scoped tokens auto-file via the scope-size-1 rule. Rate limit: 30/hr per token.
MCP overview
The Model Context Protocol server at /api/mcp. Authentication, transport, and tools.