gateway ======= routes prompts, media transcription, and media downloads through upstream provider apis ROUTES: Method | Path | Description ------ | --------------------- | ---------------- POST | /api/message | generate text POST | /api/transcribe | transcribe media POST | /api/download | download media GET | /api/download/history | download history GET | /api | service metadata GET | /api/health | readiness checks GET | /api/live | process liveness GET | / | usage reference POST /api/message ================= curl -X POST http://localhost:9990/api/message \ -H "Content-Type: application/json" \ -d '{ "id": 1, "query": "Summarize the current release notes.", "provider": "openai", "conversationId": "release-notes", "model": "gpt-6.1-sol", "system": "Be concise.", "effort": "low" }' /api/message only accepts application/json send audio and video uploads or media URLs to /api/transcribe provider values are openai, fireworks, or openrouter effort values are none, minimal, low, medium, high, or xhigh conversationId defaults to String(id) and is scoped by provider model defaults to the selected provider's configured model system defaults to the selected provider's configured system prompt, if set system is stored only after the first successful turn concurrent turns in one conversation are serialized conversations expire after an hour of inactivity and oldest complete turns are trimmed to bound context when Exa is configured the selected model receives an exa_search tool REQUEST FIELDS: Field | Type | Default -------------- | ------ | ------------------ id | number | - query | string | - provider | string | "openai" conversationId | string | "String(id)" model | string | "provider default" system | string | "provider prompt" effort | string | null EXAMPLE RESPONSE: Returns the generated provider response as text/plain. ERROR RESPONSE: Error: Invalid request body. POST /api/transcribe ==================== curl -X POST http://localhost:9990/api/transcribe \ -H "Accept: application/json" \ -F "file=@./meeting.m4a" \ -F "provider=openrouter" \ -F "model=microsoft/mai-transcribe-2" \ -F "language=en" \ -F "temperature=0" curl -X POST http://localhost:9990/api/transcribe \ -F "file=@./meeting.m4a" \ -F "provider=cohere" \ -F "model=cohere-transcribe-03-2026" \ -F "language=en" curl -X POST http://localhost:9990/api/transcribe \ -H "Content-Type: application/json" \ -d '{ "url": "https://www.tiktok.com/@user/video/1234567890", "provider": "openrouter", "language": "en", "proxy": false, "audioQuality": "best" }' curl -X POST http://localhost:9990/api/transcribe \ -F "url=https://www.youtube.com/watch?v=dQw4w9WgXcQ" \ -F "provider=openrouter" \ -F "language=en" \ -F "proxy=false" accepts multipart/form-data with a file or url field, or application/json with a url field provide either file or url, not both url requests download audio with yt-dlp using the same proxy rules as /api/download provider values are cohere or openrouter provider defaults to "openrouter" and requires OPENROUTER_API_KEY cohere model defaults to "cohere-transcribe-03-2026" openrouter model defaults to "microsoft/mai-transcribe-2" cohere language values are ar, de, el, en, es, fr, it, ja, ko, nl, pl, pt, vi, or zh openrouter detects the language when language is omitted supported cohere passthrough audio extensions are flac, mp3, mpeg, mpga, ogg, and wav unsupported containers and media above the provider size budget are transcoded to mono mp3 before transcription provider-specific media size limits are listed at /api media that cannot fit the selected provider budget after compression returns 413 unknown request fields are rejected responses default to text/plain, including when the request body is application/json send Accept: application/json for a JSON transcript with model, provider, language, and durationMs wildcard-only Accept headers keep plain text; quality values are respected and explicit JSON wins ties durationMs includes request parsing, download, conversion, and upstream transcription, excluding cleanup and response delivery model is the resolved model sent upstream and language is the requested or configured language REQUEST FIELDS: Field | Type | Default --------------- | ------- | ------------------ file | File | - url | string | - provider | string | "openrouter" model | string | "provider default" language | string | null temperature | number | null proxy | boolean | false audioQuality | string | "best" Accept (header) | string | "text/plain" EXAMPLE RESPONSE: Returns the completed transcript as text/plain. with Accept: application/json: "text": "Meeting transcript", "model": "microsoft/mai-transcribe-2", "provider": "openrouter", "language": "en", "durationMs": 1234 ERROR RESPONSE: Error: Missing media input. Upload an audio or video file in the file field, or pass a media URL in the url field. with Accept: application/json (same HTTP status): "error": "Missing media input. Upload an audio or video file in the file field, or pass a media URL in the url field." POST /api/download ================== curl -X POST http://localhost:9990/api/download \ -H "Content-Type: application/json" \ -d '{ "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "mode": "both", "quality": "1080p", "audioQuality": "best", "iosCompatible": true, "proxy": false, "playlist": false }' \ --output download.mp4 /api/download only accepts application/json mode values are both, audio, or video quality only applies when mode is "both" and accepts best, 2160p, 1440p, 1080p, 720p, 480p, or 360p audioQuality only applies when mode is "audio" and accepts best, high, medium, low, lowest, or a bitrate from 32K to 320K when playlist is true, the URL must be a playlist with at most 20 items and the response is a .zip file successful inspection of a non-playlist returns 400; failed inspection returns 502 with details, and inspection timeouts return 504 media URLs must use HTTP or HTTPS on port 80 or 443 and resolve only to public addresses redirects and subsequent downloader connections follow the same destination restrictions unknown request fields are rejected proxy requires PROXY_URL; FORCE_PROXY_SERVICES can force proxy use by service force-proxy service values are youtube, tiktok, instagram, twitter, reddit, facebook, dailymotion, vimeo, soundcloud, or twitch iosCompatible transcodes single video+audio MP4 downloads to H.264/AAC when needed REQUEST FIELDS: Field | Type | Default ------------- | ------- | ------- url | string | - mode | string | "both" quality | string | "best" audioQuality | string | "best" iosCompatible | boolean | true proxy | boolean | false playlist | boolean | false EXAMPLE RESPONSE: Streams an MP3, MP4, or ZIP file with Content-Disposition: attachment and Proxy-Used response headers. ERROR RESPONSE: Error: Missing 'url' in request body GET /api/download/history ========================= curl -G http://localhost:9990/api/download/history \ --data-urlencode "limit=25" \ --data-urlencode "offset=0" history requires DATABASE_URL; without it the route returns 501 limit is capped at 200 generation and delivery are tracked separately; status is ready while streaming, success on stream completion, error on failure, or aborted on cancellation/timeout streamed_bytes counts bytes handed to the response consumer; new delivery fields are null for historical rows REQUEST FIELDS: Field | Type | Default ------ | ------ | ------- limit | number | 50 offset | number | 0 EXAMPLE RESPONSE: "history": [ { "id": "550e8400-e29b-41d4-a716-446655440000", "created_at": "2026-05-22T10:30:00.000Z", "request_id": "0198bb1a-0000-7000-8000-000000000001", "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "service": "youtube", "quality": "best", "mode": "both", "audio_quality": "best", "audio_only": false, "video_only": false, "ios_compatible": true, "proxied": false, "proxy_forced": false, "is_playlist": false, "item_count": null, "output_filename": "download.mp4", "output_bytes": 12345678, "status": "success", "error": null, "generation_status": "success", "delivery_status": "completed", "streamed_bytes": 12345678, "generation_duration_ms": 4500, "delivery_duration_ms": 1200, "delivery_finished_at": "2026-05-22T10:30:05.700Z" } ], "limit": 25, "offset": 0 ERROR RESPONSE: Error: Download history is not available (DATABASE_URL not configured)