Upload Session API
Planned direct-to-R2 ingestion contract for OCR and compliance uploads.
This page describes the planned upload-session API. It is intentionally separate from the live API reference because these routes are not mounted in convex/http.ts yet.
Status
Preview only as of 2026-03-23.
Do not build production integrations against these routes until they are shipped and added to the live OpenAPI reference.
What is live today vs planned
Live /api/v1 routes today:
GET /api/v1/companiesGET /api/v1/jobs/{sessionId}POST /api/v1/webhooks/test
Planned routes on this page are not mounted yet in convex/http.ts.
Planned flow
The target ingestion model is a four-step sequence:
- Create a session and receive presigned R2 upload URLs.
- Upload files directly to Cloudflare R2.
- Submit the session for processing.
- Receive completion via webhook or
GET /api/v1/jobs/{sessionId}.
Planned endpoints
| Method | Path | Intended purpose |
|---|---|---|
POST | /api/v1/ocr/sessions | Create an OCR upload session |
POST | /api/v1/ocr/sessions/{sessionId}/submit | Trigger OCR processing |
POST | /api/v1/compliance/sessions | Create a compliance upload session |
POST | /api/v1/compliance/sessions/{sessionId}/submit | Trigger compliance processing |
POST | /api/v1/workflows/{slug}/sessions | Future generic workflow entrypoint |
Recommended direction
The current backend is workflow-driven, so the clean long-term shape is:
POST /api/v1/workflows/{slug}/sessionsPOST /api/v1/workflows/{slug}/sessions/{sessionId}/submit
The OCR and compliance paths can still exist as compatibility wrappers, but they should map onto system workflow slugs rather than reintroducing separate pipeline-specific backends.
Planned contract highlights
Based on the repository's design docs and supporting backend code:
- session TTL: 30 minutes
- presigned upload URL TTL: 15 minutes
- supported image formats:
image/jpeg,image/png - reserved rate limit bucket for session creation: 60 req/min per API key
- reserved rate limit bucket for session submit: 20 req/min per API key
The design also targets:
- up to 20 pages for OCR sessions
- up to 5 photos for compliance sessions
- async processing backed by the existing
apiSessionstable - signed result webhooks plus polling fallback
Missing implementation work
The repository already has part of the supporting infrastructure:
apiKeysand admin key managementapiSessionspersistence- API-key auth helpers
- presigned R2 upload utilities
- job polling
- webhook signing and retry helpers
- reserved create and submit rate-limit buckets
What is still missing is the route-to-engine lifecycle:
- session-creation HTTP handlers
- validation of workflow slug, company, counts, and file types
- server-side submission bootstrap for API callers
- session-submit handlers
- final external result payload normalization for jobs and webhooks
- end-to-end tests for the full flow
Why it is documented separately
The repository already contains:
apiSessionspersistence and lifecycle helpers- reserved rate-limit buckets for create and submit flows
- R2 presigned upload utilities
- a detailed design doc in
docs/external-api.md
What is still missing is the actual HTTP routing for session creation and submission. Until those routes are present, the canonical live contract remains the smaller /api/v1 surface documented under API Reference.