API Specification — Accessible Video Processing Platform
Generated: 2026-05-01
Quick Navigation
Agent Entry
| Signal |
Value |
| Purpose |
Authoritative REST API contract for all backend routes |
| Read When |
You need endpoint paths, auth requirements, or request/response shapes |
| Skip When |
You need DB schema → database_schema.md; infrastructure → infrastructure.md |
| Canonical |
Yes |
| Next Docs |
Architecture, Database Schema |
| Primary Sources |
backend/app/api/v1/routes_*.py |
Base URLs
| Environment |
URL |
| Production |
https://optical-dev.oliver.solutions/video-accessibility-back |
| Local (Docker) |
http://localhost:8012 |
| OpenAPI (Swagger) |
{base_url}/docs |
All routes are prefixed with /api/v1/.
Authentication
Scheme: Bearer token (access token in memory) + HttpOnly refresh cookie.
| Header / Cookie |
Description |
Authorization: Bearer <access_token> |
Required for all protected endpoints |
refresh_token cookie (HttpOnly) |
Used by /auth/refresh only |
Roles: client, linguist, reviewer, production, project_manager, admin.
Auth Endpoints
| Method |
Path |
Auth |
Description |
| POST |
/auth/login |
None |
Email/password login; returns access token + sets refresh cookie |
| POST |
/auth/microsoft |
None |
Microsoft OIDC token validation; returns access + refresh |
| POST |
/auth/refresh |
Cookie |
Exchange refresh cookie for new access token |
| POST |
/auth/logout |
Bearer |
Revoke refresh token, clear cookie |
Login request:
{ "email": "user@example.com", "password": "secret" }
Login response:
{ "access_token": "eyJ...", "token_type": "bearer", "user": { "id": "...", "email": "...", "role": "admin" } }
Jobs
Upload (resumable)
| Method |
Path |
Auth |
Description |
| POST |
/jobs/upload/init |
Bearer |
Initialise resumable GCS upload; returns signed upload URL |
| POST |
/jobs/upload/complete |
Bearer |
Finalise upload; creates Job record and enqueues ingestion |
/jobs/upload/init request:
{ "filename": "video.mp4", "content_type": "video/mp4", "size_bytes": 104857600 }
/jobs/upload/complete request:
{
"gcs_uri": "gs://accessible-video/jobs/{job_id}/source.mp4",
"filename": "video.mp4",
"source_language": "en",
"requested_outputs": {
"captions_vtt": true,
"audio_description_vtt": true,
"audio_description_mp3": true,
"accessible_video_mp4": false,
"languages": ["fr", "de"],
"tts_preferences": { "provider": "gemini", "model": "flash", "default_voice": "Kore" }
}
}
Job CRUD & Listing
| Method |
Path |
Auth |
Description |
| POST |
/jobs |
Bearer |
Create job directly (small upload, no resumable) |
| GET |
/jobs |
Bearer |
List jobs (paginated, filterable by status/org/client/project) |
| GET |
/jobs/{job_id} |
Bearer |
Get single job with full language output map |
| PATCH |
/jobs/{job_id} |
Bearer |
Update job metadata (title, notes, requested outputs) |
| DELETE |
/jobs/{job_id} |
Bearer |
Soft-delete job |
| POST |
/jobs/{job_id}/clone |
Bearer |
Clone a job (new upload, same config) |
| POST |
/jobs/{job_id}/cancel |
Bearer |
Cancel a running job |
| POST |
/jobs/{job_id}/retry |
Bearer |
Retry failed job from the failed step |
| GET |
/jobs/{job_id}/validate |
Bearer |
Validate all GCS assets exist for a completed job |
Job list query params: status, org_id, client_id, project_id, page, size, sort.
Job list response:
{ "items": [ { "id": "...", "status": "pending_qc", "title": "...", "created_at": "..." } ], "total": 42, "page": 1, "size": 20 }
Job State Transitions (Actions)
| Method |
Path |
Auth |
Roles |
Description |
| POST |
/jobs/{job_id}/actions/approve_source |
Bearer |
reviewer, production, admin |
Approve source language VTT |
| POST |
/jobs/{job_id}/actions/approve_english |
Bearer |
reviewer, production, admin |
Approve English source specifically |
| POST |
/jobs/{job_id}/actions/reject |
Bearer |
reviewer, production, admin |
Reject job, return to creator |
| POST |
/jobs/{job_id}/actions/complete |
Bearer |
project_manager, admin |
Mark job fully complete |
| POST |
/jobs/{job_id}/actions/reject_final |
Bearer |
project_manager, admin |
Reject at final review stage |
| POST |
/jobs/{job_id}/actions/return_to_qc |
Bearer |
project_manager, admin |
Return from final review to QC |
| POST |
/jobs/{job_id}/actions/blocked_on_source |
Bearer |
production, admin |
Flag source video issue |
| POST |
/jobs/{job_id}/actions/promote_to_qc |
Bearer |
production, admin |
Manually advance to pending_qc |
| POST |
/jobs/{job_id}/actions/retry_tts |
Bearer |
production, admin |
Retry TTS generation for a language |
Bulk Job Actions
| Method |
Path |
Auth |
Description |
| DELETE |
/jobs/bulk |
Bearer |
Bulk delete jobs by IDs |
| POST |
/jobs/bulk/approve |
Bearer |
Bulk approve source for multiple jobs |
| POST |
/jobs/bulk/return-to-qc |
Bearer |
Bulk return jobs to QC |
| POST |
/jobs/bulk/download |
Bearer |
Generate signed download ZIP for multiple jobs |
VTT Editing
| Method |
Path |
Auth |
Description |
| GET |
/jobs/{job_id}/vtt |
Bearer |
Get VTT content for a language/kind (?lang=en&kind=captions) |
| PATCH |
/jobs/{job_id}/vtt |
Bearer |
Save edited VTT content (creates new version) |
| POST |
/jobs/{job_id}/vtt/adjust-timing |
Bearer |
Bulk shift cue timestamps |
VTT Versions
| Method |
Path |
Auth |
Description |
| GET |
/jobs/{job_id}/vtt/versions |
Bearer |
List VTT version history |
| GET |
/jobs/{job_id}/vtt/versions/{version} |
Bearer |
Get specific version content |
| GET |
/jobs/{job_id}/vtt/versions/diff |
Bearer |
Diff two versions |
| POST |
/jobs/{job_id}/vtt/versions/restore |
Bearer |
Restore an earlier version |
Downloads & Accessible Video
| Method |
Path |
Auth |
Description |
| GET |
/jobs/{job_id}/downloads |
Bearer |
Get signed GCS download URLs for all assets |
| GET |
/jobs/{job_id}/accessible-video/{language}/edit-state |
Bearer |
Get pause-point edit state |
| PATCH |
/jobs/{job_id}/accessible-video/{language}/pause-points/{cue_index} |
Bearer |
Adjust a pause point timestamp |
Language QC
| Method |
Path |
Auth |
Description |
| GET |
/language-qc/jobs/{job_id}/language-qc |
Bearer |
Get QC state map for all languages |
| POST |
/language-qc/jobs/{job_id}/languages/{lang}/assign |
Bearer |
Assign linguist to language |
| POST |
/language-qc/jobs/{job_id}/languages/{lang}/reassign |
Bearer |
Reassign linguist |
| POST |
/language-qc/jobs/{job_id}/languages/{lang}/assign-reviewer |
Bearer |
Assign reviewer |
| POST |
/language-qc/jobs/{job_id}/languages/{lang}/reassign-reviewer |
Bearer |
Reassign reviewer |
| POST |
/language-qc/jobs/{job_id}/languages/bulk-assign |
Bearer |
Bulk assign linguist/reviewer for multiple languages |
| POST |
/language-qc/jobs/{job_id}/languages/{lang}/start-work |
Bearer |
Linguist starts working |
| POST |
/language-qc/jobs/{job_id}/languages/{lang}/submit |
Bearer |
Linguist submits for review |
| POST |
/language-qc/jobs/{job_id}/languages/{lang}/open-review |
Bearer |
Reviewer opens language for review |
| POST |
/language-qc/jobs/{job_id}/languages/{lang}/approve |
Bearer |
Reviewer approves language |
| POST |
/language-qc/jobs/{job_id}/languages/{lang}/reject |
Bearer |
Reviewer rejects language |
| POST |
/language-qc/jobs/{job_id}/languages/{lang}/reopen |
Bearer |
Reopen after rejection |
| POST |
/language-qc/jobs/{job_id}/languages/{lang}/mark-cue-reviewed |
Bearer |
Mark individual VTT cue reviewed |
| GET |
/language-qc/jobs/{job_id}/languages/{lang}/comments |
Bearer |
List reviewer comments |
| POST |
/language-qc/jobs/{job_id}/languages/{lang}/comments |
Bearer |
Add reviewer comment |
| GET |
/language-qc/me/language-qc-queue |
Bearer |
Get current user's QC queue |
Files
| Method |
Path |
Auth |
Description |
| POST |
/files/signed-upload |
Bearer |
Get a signed GCS upload URL for arbitrary file upload |
TTS
| Method |
Path |
Auth |
Description |
| GET |
/tts/voices |
Bearer |
List available voices per provider |
| GET |
/tts/languages |
Bearer |
List supported language codes |
| GET |
/tts/options |
Bearer |
Get provider/model options |
| POST |
/tts/preview |
Bearer |
Generate a short TTS audio preview for a voice |
Briefs
| Method |
Path |
Auth |
Description |
| GET |
/briefs |
Bearer |
List briefs (filtered by org/status) |
| POST |
/briefs |
Bearer |
Create a brief (draft) |
| GET |
/briefs/{brief_id} |
Bearer |
Get brief detail |
| PATCH |
/briefs/{brief_id} |
Bearer |
Update brief (draft only) |
| POST |
/briefs/{brief_id}/submit |
Bearer |
Submit brief for PM approval |
| POST |
/briefs/{brief_id}/approve |
Bearer |
PM approves brief |
Glossaries
| Method |
Path |
Auth |
Description |
| GET |
/glossaries |
Bearer |
List glossaries for current client |
| POST |
/glossaries |
Bearer |
Create glossary (XLSX upload) |
| GET |
/glossaries/{glossary_id} |
Bearer |
Get glossary detail |
| GET |
/glossaries/{glossary_id}/terms |
Bearer |
List terms (paginated) |
| POST |
/glossaries/{glossary_id}/versions |
Bearer |
Upload new version (XLSX) |
| POST |
/glossaries/{glossary_id}/activate |
Bearer |
Activate a glossary version |
| POST |
/glossaries/{glossary_id}/versions/{version_id}/reembed |
Bearer |
Re-trigger embedding for a version |
| DELETE |
/glossaries/{glossary_id} |
Bearer |
Archive/delete glossary |
Organizations
| Method |
Path |
Auth |
Description |
| GET |
/organizations |
Bearer |
List organisations |
| POST |
/organizations |
Bearer (admin) |
Create organisation |
| GET |
/organizations/{org_id} |
Bearer |
Get organisation |
| PATCH |
/organizations/{org_id} |
Bearer (admin) |
Update organisation |
| GET |
/organizations/{org_id}/members |
Bearer |
List members |
| POST |
/organizations/{org_id}/members |
Bearer (admin) |
Add member |
| PATCH |
/organizations/{org_id}/members/{user_id} |
Bearer (admin) |
Update member role |
| DELETE |
/organizations/{org_id}/members/{user_id} |
Bearer (admin) |
Remove member |
| GET |
/organizations/me/memberships |
Bearer |
Get current user's org memberships |
Clients, Teams & Projects
| Method |
Path |
Auth |
Description |
| GET |
/clients |
Bearer |
List clients |
| POST |
/clients |
Bearer (admin) |
Create client |
| GET |
/clients/{client_id} |
Bearer |
Get client |
| PATCH |
/clients/{client_id} |
Bearer (admin) |
Update client |
| DELETE |
/clients/{client_id} |
Bearer (admin) |
Delete client |
| POST |
/clients/{client_id}/pm |
Bearer (admin) |
Assign PM to client |
| DELETE |
/clients/{client_id}/pm/{user_id} |
Bearer (admin) |
Remove PM from client |
| GET |
/clients/{client_id}/pm |
Bearer |
List PMs for client |
| GET |
/clients/{client_id}/teams |
Bearer |
List teams |
| POST |
/clients/{client_id}/teams |
Bearer (admin) |
Create team |
| PATCH |
/clients/{client_id}/teams/{team_id} |
Bearer (admin) |
Update team |
| DELETE |
/clients/{client_id}/teams/{team_id} |
Bearer (admin) |
Delete team |
| POST |
/clients/{client_id}/teams/{team_id}/members |
Bearer |
Add team member |
| DELETE |
/clients/{client_id}/teams/{team_id}/members/{user_id} |
Bearer |
Remove team member |
| GET |
/clients/all-projects |
Bearer |
List all projects across clients |
| GET |
/clients/{client_id}/projects |
Bearer |
List client projects |
| POST |
/clients/{client_id}/projects |
Bearer (admin) |
Create project |
| PATCH |
/clients/{client_id}/projects/{project_id} |
Bearer (admin) |
Update project |
| DELETE |
/clients/{client_id}/projects/{project_id} |
Bearer (admin) |
Delete project |
Share Tokens
| Method |
Path |
Auth |
Description |
| POST |
/share/jobs/{job_id}/share |
Bearer |
Create share token for a job |
| GET |
/share/jobs/{job_id}/share |
Bearer |
List active share tokens |
| DELETE |
/share/jobs/{job_id}/share/{token_id} |
Bearer |
Revoke share token |
| GET |
/share/public/share/{token} |
None |
Public job preview (client portal) |
Invitations
| Method |
Path |
Auth |
Description |
| POST |
/invitations/preview |
None |
Preview invitation details from token |
| POST |
/invitations/accept |
None |
Accept invitation and create/link account |
Review Notes
| Method |
Path |
Auth |
Description |
| GET |
/jobs/{job_id}/review-notes |
Bearer |
List timestamped notes for a job asset |
| POST |
/jobs/{job_id}/review-notes |
Bearer |
Create note at a video timestamp |
| GET |
/jobs/{job_id}/review-notes/{note_id} |
Bearer |
Get single note |
| PATCH |
/jobs/{job_id}/review-notes/{note_id} |
Bearer |
Update note |
| DELETE |
/jobs/{job_id}/review-notes/{note_id} |
Bearer |
Delete note |
Admin
| Method |
Path |
Auth |
Roles |
Description |
| GET |
/admin/users |
Bearer |
admin |
List all users |
| POST |
/admin/users |
Bearer |
admin |
Create user |
| GET |
/admin/users/{user_id} |
Bearer |
admin |
Get user |
| PATCH |
/admin/users/{user_id} |
Bearer |
admin |
Update user |
| DELETE |
/admin/users/{user_id} |
Bearer |
admin |
Delete user |
| POST |
/admin/users/{user_id}/reset-password |
Bearer |
admin |
Trigger password reset email |
| POST |
/admin/users/{user_id}/password/reset |
Bearer |
admin |
Set new password directly |
| GET |
/admin/stats |
Bearer |
admin |
Platform-wide stats |
| GET |
/admin/jobs/stats |
Bearer |
admin |
Job pipeline stats |
| GET |
/admin/health/detailed |
Bearer |
admin |
Detailed health check (DB, Redis, queues) |
| POST |
/admin/maintenance/reprocess-job/{job_id} |
Bearer |
admin |
Force reprocess a stuck job |
| GET |
/admin/audit-logs |
Bearer |
admin |
List audit log entries |
| GET |
/admin/audit-logs/user/{user_id} |
Bearer |
admin |
Audit log for a specific user |
| GET |
/admin/audit-logs/security |
Bearer |
admin |
Security-related audit events |
| DELETE |
/admin/audit-logs/cleanup |
Bearer |
admin |
Purge old audit logs |
Production / Admin Production
| Method |
Path |
Auth |
Roles |
Description |
| GET |
/production/failures |
Bearer |
production, admin |
List failed jobs |
| POST |
/production/bulk-retry |
Bearer |
production, admin |
Bulk retry failed jobs |
| GET |
/production/queue-stats |
Bearer |
production, admin |
Celery queue depths and worker counts |
| POST |
/production/jobs/{job_id}/upload-final-vtt |
Bearer |
production, admin |
Manually upload a corrected VTT file |
WebSocket
| Method |
Path |
Auth |
Description |
| GET |
/ws/status |
Bearer |
WebSocket endpoint for real-time job status updates |
Standard Error Responses
| Status |
Meaning |
| 400 |
Validation error — see detail field |
| 401 |
Missing or expired access token |
| 403 |
Insufficient role permissions |
| 404 |
Resource not found |
| 409 |
Conflict (e.g. duplicate email) |
| 422 |
Pydantic schema validation failure |
| 500 |
Internal server error |
Error body:
{ "detail": "Job not found" }
Maintenance
Last Updated: 2026-05-01
Update Triggers:
- New route file added (
routes_*.py)
- Existing endpoint path or method changes
- New request/response fields in schemas
- Auth requirements change for an endpoint
Verification: