{"openapi":"3.1.0","info":{"title":"MetaPlatho API","version":"0.1.0","description":"REST API for video and image processing: compression, format conversion,\nresizing, trimming, subtitles and speech-to-text transcription, GIFs and\nthumbnails, Telegram video notes (circles), watermarks, metadata stripping and\nmulti-GB uploads. No FFmpeg or servers to run.\n\n**Authentication** — one header on every request: `X-Api-Key: ca_live_...`.\nCreate a key on the developer page: https://metaplatho.com/docs/api\n\n**Integration is two requests:**\n\n1. `POST /api/v1/jobs/upload` — multipart with `file`, `service_slug`,\n   `operation_key` and `params` (a JSON string) → `201 {\"id\", \"status\"}`.\n2. `GET /api/v1/jobs/{job_id}` — poll until `status` is `done`, then read\n   `result.output_url`.\n\nThe operation catalog (`GET /api/v1/studio/tools`, no auth) is the source of\ntruth for every `service_slug` / `operation_key`, its credit cost and params.\n\nFull guides: https://metaplatho.com/docs/index.html ·\nsingle-file reference for agents: https://metaplatho.com/llms-full.txt\n","contact":{"name":"DVO Corp","email":"help@dvocorp.com","url":"https://dvocorp.com"},"termsOfService":"https://metaplatho.com/terms"},"paths":{"/api/v1/me/ping":{"get":{"tags":["me"],"summary":"Ping","description":"Cheap authenticated no-op: validates the API key, spends nothing.","operationId":"ping_api_v1_me_ping_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PingOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/me/features":{"get":{"tags":["me"],"summary":"My Features","description":"The resolved switches for the caller, plus the audiences they landed in.\n\nPublic features only (see services/features.public_map) — an internal\nexperiment must not be readable from devtools, and for a gate like payments\nthe list of early accounts is itself information.\n\nAnonymous callers get the defaults: they have no segments, and the open\nstudio's behaviour must not depend on rules written about accounts. The\nendpoint answers rather than 401s precisely so the SPA can ask once, before\nit knows whether anyone is signed in.\n\n`segments` is advisory — it exists so support can ask \"what do you see?\" and\nget an answer that explains itself. Nothing may be authorised from it: the\ngate is the feature value, resolved here, and re-checked by the endpoint\nthat does the work.","operationId":"my_features_api_v1_me_features_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response My Features Api V1 Me Features Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/jobs":{"get":{"tags":["jobs"],"summary":"List Jobs","operationId":"list_jobs_api_v1_jobs_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"mine","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Mine"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/JobOut"},"title":"Response List Jobs Api V1 Jobs Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/jobs/api":{"post":{"tags":["jobs"],"summary":"Submit Job Api","operationId":"submit_job_api_api_v1_jobs_api_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobSubmit"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/jobs/upload":{"post":{"tags":["jobs"],"summary":"Submit Job Upload","description":"ONE call: send the file and what to do with it, get a job back.\n\nThe two-step flow (POST /uploads → POST /jobs/api) still exists and is the\nonly option for big files — the CDN caps proxied bodies at ~100 MB, so\nmulti-GB video must go straight to storage via the presigned routes. For\neverything else this is the whole API: submit here, then poll GET /jobs/{id}.\n\n`params` is a JSON object as a form field; `file_url` is injected from the\nuploaded file and always wins, so callers can't point the job at someone\nelse's object by smuggling a file_url in.","operationId":"submit_job_upload_api_v1_jobs_upload_post","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_submit_job_upload_api_v1_jobs_upload_post"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/jobs/{job_id}":{"get":{"tags":["jobs"],"summary":"Get Job","operationId":"get_job_api_v1_jobs__job_id__get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/jobs/{job_id}/delivered":{"post":{"tags":["jobs"],"summary":"Mark Delivered","description":"The client has the file. For a GUEST, delete both copies now.\n\nAn account keeps its results until the lifecycle rule sweeps them — that is\nwhat the journal is for, and re-downloading yesterday's result is a feature\nsomebody pays for. A guest has no journal: the moment the download lands\nnobody can ever ask for that object again, and leaving it to sit for up to\na day is storage we hold for no one. So the guest path deletes the source\nand the result immediately (services/purge.py), and the studio then says so\n— the privacy promise made visible rather than merely written down.\n\nOwnership is the model GET/cancel already use — the shared anonymous user's\njob addressed by its unguessable id — plus the browser scope wherever the\njob carries one, so one guest cannot purge another's work by guessing an\nid. An authed caller gets a plain 200 with purged=false, which keeps this a\nfire-and-forget call the client can always make.","operationId":"mark_delivered_api_v1_jobs__job_id__delivered_post","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeliveredOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/jobs/{job_id}/repeat":{"post":{"tags":["jobs"],"summary":"Repeat Job","description":"Re-run one of YOUR jobs with its original operation + params (fresh file\nURLs and all). Same billing as a fresh submit — the estimate is debited and\nrefunded on failure. Works with the panel JWT or an API key, so bots can\nretry a failed job with one call.","operationId":"repeat_job_api_v1_jobs__job_id__repeat_post","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}}],"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/jobs/{job_id}/cancel":{"post":{"tags":["jobs"],"summary":"Cancel Job","operationId":"cancel_job_api_v1_jobs__job_id__cancel_post","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/studio/tools":{"get":{"tags":["studio"],"summary":"Tools","operationId":"tools_api_v1_studio_tools_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/StudioTool"},"type":"array","title":"Response Tools Api V1 Studio Tools Get"}}}}},"security":[]}},"/api/v1/studio/run":{"post":{"tags":["studio"],"summary":"Run","operationId":"run_api_v1_studio_run_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StudioRunRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StudioRunOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/studio/batch":{"post":{"tags":["studio"],"summary":"Run Batch","operationId":"run_batch_api_v1_studio_batch_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchRunRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/studio/batches":{"get":{"tags":["studio"],"summary":"List Batches","operationId":"list_batches_api_v1_studio_batches_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BatchOut"},"title":"Response List Batches Api V1 Studio Batches Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/studio/batches/{batch_id}":{"get":{"tags":["studio"],"summary":"Get Batch","operationId":"get_batch_api_v1_studio_batches__batch_id__get","parameters":[{"name":"batch_id","in":"path","required":true,"schema":{"type":"string","title":"Batch Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/studio/batches/{batch_id}/cancel":{"post":{"tags":["studio"],"summary":"Cancel Batch","operationId":"cancel_batch_api_v1_studio_batches__batch_id__cancel_post","parameters":[{"name":"batch_id","in":"path","required":true,"schema":{"type":"string","title":"Batch Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/studio/batches/{batch_id}/repeat":{"post":{"tags":["studio"],"summary":"Repeat Batch","description":"Re-run a previous batch on the same source files + operation.","operationId":"repeat_batch_api_v1_studio_batches__batch_id__repeat_post","parameters":[{"name":"batch_id","in":"path","required":true,"schema":{"type":"string","title":"Batch Id"}}],"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/public/pricing":{"get":{"tags":["public"],"summary":"Public Pricing","description":"The price list, readable without an account.\n\nTwo jobs, and the second one is the reason it exists at all:\n\n1. A visitor (and a payment provider reviewing us) can see what things cost\n   before signing up. A storefront that hides its prices behind a login is a\n   verification failure, and a fair one.\n2. It is read from the SAME rows the checkout charges from —\n   ``credit_packages`` and ``plans`` — so the number on the page and the\n   number on the card cannot drift. Changing a price in the admin panel\n   moves both at once, by construction rather than by discipline. Never\n   cache this: a stale price here is a compliance problem, not a slow page.\n\nDeliberately NOT gated by \"are payments live\" or by the per-account payments\nfeature. Those decide who may BUY; what we charge is public either way. An\nexisting customer may pay less than the list price (grandfathering) — that\nis shown to them on /pricing once signed in, and it can only ever be lower.","operationId":"public_pricing_api_v1_public_pricing_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicPricing"}}}}},"security":[]}},"/api/v1/public/config":{"get":{"tags":["public"],"summary":"Public Config","description":"What anonymous web visitors are currently allowed to do, whether we're in\na maintenance window, and how to reach support. Public so the SPA can adapt\nbefore (or without) sign-in.","operationId":"public_config_api_v1_public_config_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicConfig"}}}}},"security":[]}},"/api/v1/uploads":{"post":{"tags":["uploads"],"summary":"Upload","operationId":"upload_api_v1_uploads_post","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_api_v1_uploads_post"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Upload Api V1 Uploads Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/uploads/presign":{"post":{"tags":["uploads"],"summary":"Presign","description":"Presigned PUT for a DIRECT browser→R2 upload — bypasses the app + the\nCloudflare ~100 MB proxy body limit so multi-GB videos upload fine. The browser\nPUTs the file to `put_url` with the given Content-Type, then passes `url` to the\nstudio as the file. Local-dev storage can't presign → the client falls back to\nthe multipart POST above.","operationId":"presign_api_v1_uploads_presign_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PresignRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Presign Api V1 Uploads Presign Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/uploads/multipart/create":{"post":{"tags":["uploads"],"summary":"Multipart Create","description":"Start a direct browser→R2 multipart upload. Same guards as /presign;\nthis is the ONLY multipart endpoint that consumes the anon upload quota.","operationId":"multipart_create_api_v1_uploads_multipart_create_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MultipartCreateRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Multipart Create Api V1 Uploads Multipart Create Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/uploads/multipart/sign-part":{"post":{"tags":["uploads"],"summary":"Multipart Sign Part","description":"Presigned URL for ONE part. Called ~50×/file — no upload quota, but\nbounded: per-IP rpm guard + only uploads we minted (Redis record from\ncreate) + only parts within the budget the CLAIMED size implies.","operationId":"multipart_sign_part_api_v1_uploads_multipart_sign_part_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MultipartSignPartRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Multipart Sign Part Api V1 Uploads Multipart Sign Part Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/uploads/multipart/complete":{"post":{"tags":["uploads"],"summary":"Multipart Complete","description":"Stitch the uploaded parts; returns the same shape as /presign so the\nclient can hand the file straight to the studio.","operationId":"multipart_complete_api_v1_uploads_multipart_complete_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MultipartCompleteRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Multipart Complete Api V1 Uploads Multipart Complete Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/uploads/multipart/abort":{"post":{"tags":["uploads"],"summary":"Multipart Abort","description":"Best-effort cleanup of an abandoned multipart upload (frees R2 storage).","operationId":"multipart_abort_api_v1_uploads_multipart_abort_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MultipartAbortRequest"}}}},"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/tg/deliver":{"post":{"tags":["telegram"],"summary":"Deliver","description":"Create a single-use Telegram delivery link for a finished note video.","operationId":"deliver_api_v1_tg_deliver_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeliverRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeliverResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/upload-sessions":{"get":{"tags":["upload-bridge"],"summary":"List Upload Sessions","description":"The owner's recent sessions, newest first — powers the web \"Upload\nlinks\" page. Lazily expires overdue rows and syncs the first few\nprocessing ones so the listing reflects live state.","operationId":"list_upload_sessions_api_v1_upload_sessions_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UploadSessionOut"},"title":"Response List Upload Sessions Api V1 Upload Sessions Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/upload-sessions/api":{"post":{"tags":["upload-bridge"],"summary":"Create Upload Session Api","operationId":"create_upload_session_api_api_v1_upload_sessions_api_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadSessionCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadSessionCreated"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/upload-sessions/{session_id}":{"get":{"tags":["upload-bridge"],"summary":"Get Upload Session","description":"Status poll for the session owner (panel JWT or API key). Syncs the\nlinked job from the upstream on read — same on-demand refresh model as\nGET /jobs/{id}.","operationId":"get_upload_session_api_v1_upload_sessions__session_id__get","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadSessionOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]},"delete":{"tags":["upload-bridge"],"summary":"Delete Upload Session","description":"Delete one of YOUR links — active or spent. Its files are deleted with\nit (in-flight upload aborted, stored source removed from the bucket) and\nstill-running linked jobs are canceled + refunded. The link's token stops\nworking immediately.","operationId":"delete_upload_session_api_v1_upload_sessions__session_id__delete","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/upload-sessions/{session_id}/archive":{"get":{"tags":["upload-bridge"],"summary":"Download Archive","description":"All the link's uploaded files as ONE .zip, streamed — files come\nstraight from storage through this response (store-only zip, zip64, no\ndisk buffering). Files that vanished from storage are skipped.","operationId":"download_archive_api_v1_upload_sessions__session_id__archive_get","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/health":{"get":{"tags":["health"],"summary":"Health","description":"Liveness — process is up. No dependency checks (those belong in /ready).","operationId":"health_api_v1_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Health Api V1 Health Get"}}}}},"security":[]}}},"components":{"schemas":{"BatchOut":{"properties":{"id":{"type":"string","title":"Id"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"status":{"$ref":"#/components/schemas/BatchStatus"},"total":{"type":"integer","title":"Total"},"done":{"type":"integer","title":"Done"},"failed":{"type":"integer","title":"Failed"},"estimated_cost":{"type":"integer","title":"Estimated Cost"},"final_cost":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Final Cost"},"result_zip_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Result Zip Url"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"finished_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Finished At"},"operation_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operation Key"},"params":{"additionalProperties":true,"type":"object","title":"Params"},"sources":{"items":{"type":"string"},"type":"array","title":"Sources","default":[]}},"type":"object","required":["id","title","status","total","done","failed","estimated_cost","result_zip_url","error","created_at","finished_at","operation_key","params"],"title":"BatchOut"},"BatchRunRequest":{"properties":{"operation_id":{"type":"integer","title":"Operation Id"},"file_urls":{"items":{"type":"string"},"type":"array","minItems":1,"title":"File Urls"},"preset_index":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Preset Index"},"naming":{"type":"string","title":"Naming","default":"keep"},"params":{"additionalProperties":true,"type":"object","title":"Params"},"filenames":{"anyOf":[{"items":{"anyOf":[{"type":"string"},{"type":"null"}]},"type":"array"},{"type":"null"}],"title":"Filenames"}},"type":"object","required":["operation_id","file_urls"],"title":"BatchRunRequest"},"BatchStatus":{"type":"string","enum":["queued","processing","done","failed","canceled"],"title":"BatchStatus"},"BillingConfig":{"properties":{"signup_bonus_credits":{"type":"integer","title":"Signup Bonus Credits"},"signup_bonus_ttl_days":{"type":"integer","title":"Signup Bonus Ttl Days"},"free_daily_credits":{"type":"integer","title":"Free Daily Credits"},"free_daily_ttl_hours":{"type":"integer","title":"Free Daily Ttl Hours"},"time_tariff_enabled":{"type":"boolean","title":"Time Tariff Enabled"},"time_tariff_base_credits":{"type":"integer","title":"Time Tariff Base Credits"},"time_tariff_per_extra_minute_credits":{"type":"integer","title":"Time Tariff Per Extra Minute Credits"},"time_tariff_max_credits":{"type":"integer","title":"Time Tariff Max Credits"},"input_limit_enabled":{"type":"boolean","title":"Input Limit Enabled"},"input_max_minutes":{"additionalProperties":{"type":"integer"},"type":"object","title":"Input Max Minutes"},"video_max_mb":{"type":"integer","title":"Video Max Mb"},"video_max_sec":{"type":"integer","title":"Video Max Sec"},"recurring_available":{"type":"boolean","title":"Recurring Available"},"packs_require_subscription":{"type":"boolean","title":"Packs Require Subscription"},"bundle_pack_discount_pct":{"type":"integer","title":"Bundle Pack Discount Pct"}},"type":"object","required":["signup_bonus_credits","signup_bonus_ttl_days","free_daily_credits","free_daily_ttl_hours","time_tariff_enabled","time_tariff_base_credits","time_tariff_per_extra_minute_credits","time_tariff_max_credits","input_limit_enabled","input_max_minutes","video_max_mb","video_max_sec","recurring_available","packs_require_subscription","bundle_pack_discount_pct"],"title":"BillingConfig","description":"Every published billing number, resolved from app_settings.\n\nAnonymous-safe by construction: these are the same figures already printed\non the pricing page, in the Terms and on the studio tiles. Nothing here is\nper-caller — `asr_max_input_minutes` carries all three tiers so the page can\nlabel the visitor's own without the server having to know who they are."},"Body_submit_job_upload_api_v1_jobs_upload_post":{"properties":{"file":{"type":"string","format":"binary","title":"File"},"service_slug":{"type":"string","title":"Service Slug"},"operation_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operation Key"},"params":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Params"},"webhook_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhook Url"},"high_priority":{"type":"boolean","title":"High Priority","default":false}},"type":"object","required":["file","service_slug"],"title":"Body_submit_job_upload_api_v1_jobs_upload_post"},"Body_upload_api_v1_uploads_post":{"properties":{"file":{"type":"string","format":"binary","title":"File"}},"type":"object","required":["file"],"title":"Body_upload_api_v1_uploads_post"},"DeliverRequest":{"properties":{"result_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Result Url"},"job_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Job Id"},"bot_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Bot Id"}},"type":"object","title":"DeliverRequest"},"DeliverResponse":{"properties":{"deep_link":{"type":"string","title":"Deep Link"},"token":{"type":"string","title":"Token"},"bot_id":{"type":"integer","title":"Bot Id"}},"type":"object","required":["deep_link","token","bot_id"],"title":"DeliverResponse"},"DeliveredOut":{"properties":{"purged":{"type":"boolean","title":"Purged"},"files_deleted":{"type":"integer","title":"Files Deleted","default":0}},"type":"object","required":["purged"],"title":"DeliveredOut","description":"Whether the visitor's copy is now the only one left."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"JobOut":{"properties":{"id":{"type":"string","title":"Id"},"status":{"$ref":"#/components/schemas/JobStatus"},"service_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Service Id"},"operation_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operation Key"},"params":{"additionalProperties":true,"type":"object","title":"Params"},"result":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Result"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"},"estimated_cost":{"type":"integer","title":"Estimated Cost"},"final_cost":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Final Cost"},"input_duration_sec":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Input Duration Sec"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"finished_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Finished At"},"queue_position":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Queue Position"}},"type":"object","required":["id","status","service_id","operation_key","params","result","error","estimated_cost","final_cost","created_at","finished_at"],"title":"JobOut"},"JobStatus":{"type":"string","enum":["queued","processing","done","failed","canceled"],"title":"JobStatus"},"JobSubmit":{"properties":{"service_slug":{"type":"string","title":"Service Slug"},"operation_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operation Key"},"params":{"additionalProperties":true,"type":"object","title":"Params"},"webhook_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhook Url"},"high_priority":{"type":"boolean","title":"High Priority","default":false}},"type":"object","required":["service_slug"],"title":"JobSubmit"},"MarketingConfig":{"properties":{"ga4_id":{"type":"string","title":"Ga4 Id"},"google_ads_id":{"type":"string","title":"Google Ads Id"},"google_ads_signup_label":{"type":"string","title":"Google Ads Signup Label"},"google_ads_purchase_label":{"type":"string","title":"Google Ads Purchase Label"},"meta_pixel_id":{"type":"string","title":"Meta Pixel Id"},"consent_required":{"type":"boolean","title":"Consent Required"}},"type":"object","required":["ga4_id","google_ads_id","google_ads_signup_label","google_ads_purchase_label","meta_pixel_id","consent_required"],"title":"MarketingConfig","description":"Ad-network counter ids the SPA loads (empty string = that network is off,\nso its script is never fetched). Public by nature — a pixel id is visible in\npage source on every site that runs one; there is no secret here.\n\nThey are served at RUNTIME rather than baked into the bundle because Vite\ninlines `import.meta.env` at build time: a marketer swapping a counter, or\nthe owner killing a pixel after a complaint, would otherwise need a rebuild\nand a redeploy."},"MultipartAbortRequest":{"properties":{"key":{"type":"string","maxLength":1024,"minLength":1,"title":"Key"},"upload_id":{"type":"string","maxLength":4096,"minLength":1,"title":"Upload Id"}},"type":"object","required":["key","upload_id"],"title":"MultipartAbortRequest"},"MultipartCompleteRequest":{"properties":{"key":{"type":"string","maxLength":1024,"minLength":1,"title":"Key"},"upload_id":{"type":"string","maxLength":4096,"minLength":1,"title":"Upload Id"},"parts":{"items":{"$ref":"#/components/schemas/MultipartPart"},"type":"array","maxItems":10000,"minItems":1,"title":"Parts"},"content_type":{"type":"string","title":"Content Type","default":"application/octet-stream"}},"type":"object","required":["key","upload_id","parts"],"title":"MultipartCompleteRequest"},"MultipartCreateRequest":{"properties":{"filename":{"type":"string","maxLength":300,"minLength":1,"title":"Filename"},"size":{"type":"integer","exclusiveMinimum":0.0,"title":"Size"},"content_type":{"type":"string","title":"Content Type","default":"application/octet-stream"}},"type":"object","required":["filename","size"],"title":"MultipartCreateRequest"},"MultipartPart":{"properties":{"part_number":{"type":"integer","maximum":10000.0,"minimum":1.0,"title":"Part Number"},"etag":{"type":"string","maxLength":256,"minLength":1,"title":"Etag"}},"type":"object","required":["part_number","etag"],"title":"MultipartPart"},"MultipartSignPartRequest":{"properties":{"key":{"type":"string","maxLength":1024,"minLength":1,"title":"Key"},"upload_id":{"type":"string","maxLength":4096,"minLength":1,"title":"Upload Id"},"part_number":{"type":"integer","maximum":10000.0,"minimum":1.0,"title":"Part Number"}},"type":"object","required":["key","upload_id","part_number"],"title":"MultipartSignPartRequest"},"PingOut":{"properties":{"ok":{"type":"boolean","title":"Ok","default":true},"token_label":{"type":"string","title":"Token Label"},"plan":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Plan"},"credits":{"type":"integer","title":"Credits"}},"type":"object","required":["token_label","plan","credits"],"title":"PingOut"},"PresignRequest":{"properties":{"filename":{"type":"string","maxLength":300,"minLength":1,"title":"Filename"},"content_type":{"type":"string","title":"Content Type","default":"application/octet-stream"}},"type":"object","required":["filename"],"title":"PresignRequest"},"PublicConfig":{"properties":{"anon_enabled":{"type":"boolean","title":"Anon Enabled"},"anon_allow_heavy":{"type":"boolean","title":"Anon Allow Heavy"},"anon_allow_batch":{"type":"boolean","title":"Anon Allow Batch"},"registration_enabled":{"type":"boolean","title":"Registration Enabled"},"google_auth_enabled":{"type":"boolean","title":"Google Auth Enabled"},"turnstile_site_key":{"type":"string","title":"Turnstile Site Key"},"email_verification_enabled":{"type":"boolean","title":"Email Verification Enabled"},"verify_bonus_credits":{"type":"integer","title":"Verify Bonus Credits"},"studio_tiles_v2":{"type":"boolean","title":"Studio Tiles V2"},"studio_api_builder":{"type":"boolean","title":"Studio Api Builder","default":true},"telegram_bots":{"items":{"$ref":"#/components/schemas/TgBotPublic"},"type":"array","title":"Telegram Bots"},"telegram_enabled":{"type":"boolean","title":"Telegram Enabled"},"maintenance":{"type":"boolean","title":"Maintenance"},"maintenance_message":{"type":"string","title":"Maintenance Message"},"support":{"$ref":"#/components/schemas/SupportConfig"},"marketing":{"$ref":"#/components/schemas/MarketingConfig"},"billing":{"$ref":"#/components/schemas/BillingConfig"},"mcp_url":{"type":"string","title":"Mcp Url"}},"type":"object","required":["anon_enabled","anon_allow_heavy","anon_allow_batch","registration_enabled","google_auth_enabled","turnstile_site_key","email_verification_enabled","verify_bonus_credits","studio_tiles_v2","telegram_bots","telegram_enabled","maintenance","maintenance_message","support","marketing","billing","mcp_url"],"title":"PublicConfig"},"PublicPackage":{"properties":{"id":{"type":"integer","title":"Id"},"name":{"type":"string","title":"Name"},"credits":{"type":"integer","title":"Credits"},"price_cents":{"type":"integer","title":"Price Cents"},"charge_cents":{"type":"integer","title":"Charge Cents"},"bundle_charge_cents":{"type":"integer","title":"Bundle Charge Cents"},"discount_pct":{"type":"number","title":"Discount Pct","default":0},"currency":{"type":"string","title":"Currency"},"badge":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Badge"},"is_popular":{"type":"boolean","title":"Is Popular","default":false},"reference_cents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Reference Cents"},"promo_ends_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Promo Ends At"}},"type":"object","required":["id","name","credits","price_cents","charge_cents","bundle_charge_cents","currency"],"title":"PublicPackage","description":"A one-off credit pack, exactly as it will be charged.\n\n``price_cents`` is the list price and ``charge_cents`` is what the card is\nactually debited — they differ only while a promo is running, and the UI\nstrikes the first through and shows the second."},"PublicPlan":{"properties":{"id":{"type":"integer","title":"Id"},"slug":{"type":"string","title":"Slug"},"name":{"type":"string","title":"Name"},"price_cents":{"type":"integer","title":"Price Cents"},"currency":{"type":"string","title":"Currency"},"period_credits":{"type":"integer","title":"Period Credits"},"period_days":{"type":"integer","title":"Period Days"},"priority":{"type":"integer","title":"Priority"},"max_concurrent":{"type":"integer","title":"Max Concurrent"},"max_batch_files":{"type":"integer","title":"Max Batch Files"},"terms":{"items":{"$ref":"#/components/schemas/PublicTermQuote"},"type":"array","title":"Terms","default":[]},"charge_cents":{"type":"integer","title":"Charge Cents","default":0},"badge":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Badge"},"is_popular":{"type":"boolean","title":"Is Popular","default":false},"reference_cents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Reference Cents"},"promo_ends_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Promo Ends At"}},"type":"object","required":["id","slug","name","price_cents","currency","period_credits","period_days","priority","max_concurrent","max_batch_files"],"title":"PublicPlan","description":"A monthly tier, at LIST price — what a new customer pays.\n\n``price_cents`` / ``period_credits`` stay MONTHLY. ``terms`` carries the\nmulti-month offers; it always holds at least the one-month entry, so a\nclient that ignores it renders the page it always did."},"PublicPricing":{"properties":{"packages":{"items":{"$ref":"#/components/schemas/PublicPackage"},"type":"array","title":"Packages"},"plans":{"items":{"$ref":"#/components/schemas/PublicPlan"},"type":"array","title":"Plans"},"tax_included":{"type":"boolean","title":"Tax Included","default":false}},"type":"object","required":["packages","plans"],"title":"PublicPricing"},"PublicTermQuote":{"properties":{"months":{"type":"integer","title":"Months"},"credits_per_month":{"type":"integer","title":"Credits Per Month"},"credits_total":{"type":"integer","title":"Credits Total"},"monthly_price_cents":{"type":"integer","title":"Monthly Price Cents"},"undiscounted_cents":{"type":"integer","title":"Undiscounted Cents"},"charge_cents":{"type":"integer","title":"Charge Cents"},"discount_pct":{"type":"integer","title":"Discount Pct"},"currency":{"type":"string","title":"Currency"}},"type":"object","required":["months","credits_per_month","credits_total","monthly_price_cents","undiscounted_cents","charge_cents","discount_pct","currency"],"title":"PublicTermQuote","description":"One purchasable term length at LIST price — see schemas/billing.TermQuoteOut.\n\nRepeated here rather than imported so the public contract stays readable in\none file; both are filled from the same ``pricing.term_quote`` call, so they\ncannot disagree about a number."},"StudioPreset":{"properties":{"index":{"type":"integer","title":"Index"},"label":{"anyOf":[{"type":"string"},{"additionalProperties":{"type":"string"},"type":"object"}],"title":"Label"}},"type":"object","required":["index","label"],"title":"StudioPreset"},"StudioRunOut":{"properties":{"id":{"type":"string","title":"Id"},"status":{"$ref":"#/components/schemas/JobStatus"},"service_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Service Id"},"operation_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operation Key"},"params":{"additionalProperties":true,"type":"object","title":"Params"},"result":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Result"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"},"estimated_cost":{"type":"integer","title":"Estimated Cost"},"final_cost":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Final Cost"},"input_duration_sec":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Input Duration Sec"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"finished_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Finished At"},"queue_position":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Queue Position"},"complexity_score":{"type":"integer","title":"Complexity Score","default":0},"complexity_tier":{"type":"string","title":"Complexity Tier","default":"light"},"queued":{"type":"boolean","title":"Queued","default":false}},"type":"object","required":["id","status","service_id","operation_key","params","result","error","estimated_cost","final_cost","created_at","finished_at"],"title":"StudioRunOut","description":"Job + a complexity hint so the browser knows how to present it:\n`queued`=true → big job, tell the user to check history; else inline result."},"StudioRunRequest":{"properties":{"operation_id":{"type":"integer","title":"Operation Id"},"file_url":{"anyOf":[{"type":"string","maxLength":1000,"minLength":8},{"type":"null"}],"title":"File Url"},"source_url":{"anyOf":[{"type":"string","maxLength":2000,"minLength":8},{"type":"null"}],"title":"Source Url"},"preset_index":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Preset Index"},"params":{"additionalProperties":true,"type":"object","title":"Params"},"filename":{"anyOf":[{"type":"string","maxLength":300},{"type":"null"}],"title":"Filename"}},"type":"object","required":["operation_id"],"title":"StudioRunRequest"},"StudioTool":{"properties":{"operation_id":{"type":"integer","title":"Operation Id"},"service_id":{"type":"integer","title":"Service Id"},"service_slug":{"type":"string","title":"Service Slug"},"operation_key":{"type":"string","title":"Operation Key"},"label":{"anyOf":[{"type":"string"},{"additionalProperties":{"type":"string"},"type":"object"}],"title":"Label"},"group":{"anyOf":[{"type":"string"},{"additionalProperties":{"type":"string"},"type":"object"}],"title":"Group"},"accepts":{"items":{"type":"string"},"type":"array","title":"Accepts"},"presets":{"items":{"$ref":"#/components/schemas/StudioPreset"},"type":"array","title":"Presets"},"credits_per_call":{"type":"integer","title":"Credits Per Call"},"config":{"additionalProperties":true,"type":"object","title":"Config","default":{}}},"type":"object","required":["operation_id","service_id","service_slug","operation_key","label","group","accepts","presets","credits_per_call"],"title":"StudioTool"},"SupportConfig":{"properties":{"email":{"type":"string","title":"Email"},"phone":{"type":"string","title":"Phone"},"telegram":{"type":"string","title":"Telegram"},"site":{"type":"string","title":"Site"},"legal_name":{"type":"string","title":"Legal Name","default":""},"registration_no":{"type":"string","title":"Registration No","default":""},"address":{"type":"string","title":"Address","default":""},"popup_on_error":{"type":"boolean","title":"Popup On Error"},"feedback_enabled":{"type":"boolean","title":"Feedback Enabled"}},"type":"object","required":["email","phone","telegram","site","popup_on_error","feedback_enabled"],"title":"SupportConfig","description":"Where a stuck client should turn. Everything here is admin-editable in\nSettings → Support & feedback; empty fields are simply not rendered."},"TgBotPublic":{"properties":{"id":{"type":"integer","title":"Id"},"name":{"type":"string","title":"Name"},"username":{"type":"string","title":"Username"}},"type":"object","required":["id","name","username"],"title":"TgBotPublic","description":"A delivery bot the SPA may offer — public identity only (no secrets)."},"UploadSessionCreate":{"properties":{"service_slug":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Service Slug"},"operation_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operation Key"},"params":{"additionalProperties":true,"type":"object","title":"Params"},"operations":{"anyOf":[{"items":{"$ref":"#/components/schemas/UploadSessionOperation"},"type":"array","maxItems":10},{"type":"null"}],"title":"Operations"},"max_files":{"type":"integer","maximum":20.0,"minimum":1.0,"title":"Max Files","default":1},"bundle_zip":{"type":"boolean","title":"Bundle Zip","default":false},"expires_in_seconds":{"anyOf":[{"type":"integer","maximum":604800.0,"minimum":60.0},{"type":"null"}],"title":"Expires In Seconds"},"max_file_size_bytes":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Max File Size Bytes"},"allowed_mime_types":{"anyOf":[{"items":{"type":"string"},"type":"array","maxItems":50},{"type":"null"}],"title":"Allowed Mime Types"},"callback_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Callback Url"},"callback_secret":{"anyOf":[{"type":"string","maxLength":128,"minLength":16},{"type":"null"}],"title":"Callback Secret"},"delete_after_processing":{"type":"boolean","title":"Delete After Processing","default":false},"metadata":{"additionalProperties":true,"type":"object","title":"Metadata"}},"type":"object","title":"UploadSessionCreate","description":"Create body — operations use the exact same names and semantics as\nPOST /jobs/api. Either the single service_slug/operation_key/params triple\nOR the multi-op ``operations`` list (one job per entry on the same file)."},"UploadSessionCreated":{"properties":{"id":{"type":"string","title":"Id"},"upload_url":{"type":"string","title":"Upload Url"},"expires_at":{"type":"string","format":"date-time","title":"Expires At"},"status":{"$ref":"#/components/schemas/UploadSessionStatus"},"estimated_cost":{"type":"integer","title":"Estimated Cost"},"callback_secret":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Callback Secret"}},"type":"object","required":["id","upload_url","expires_at","status","estimated_cost"],"title":"UploadSessionCreated"},"UploadSessionFileEntry":{"properties":{"filename":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Filename"},"size_bytes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Size Bytes"},"mime_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mime Type"},"uploaded_ip":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Uploaded Ip"},"uploaded_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Uploaded At"},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url"},"job_ids":{"items":{"type":"string"},"type":"array","title":"Job Ids","default":[]},"skipped":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Skipped","default":[]}},"type":"object","required":["filename","size_bytes","mime_type","uploaded_ip","uploaded_at","url"],"title":"UploadSessionFileEntry","description":"One completed upload within a (possibly multi-file) session."},"UploadSessionFileOut":{"properties":{"filename":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Filename"},"size_bytes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Size Bytes"},"mime_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mime Type"},"checksum":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Checksum"},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url"}},"type":"object","required":["filename","size_bytes","mime_type","checksum","url"],"title":"UploadSessionFileOut"},"UploadSessionOperation":{"properties":{"service_slug":{"type":"string","title":"Service Slug"},"operation_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operation Key"},"params":{"additionalProperties":true,"type":"object","title":"Params"}},"type":"object","required":["service_slug"],"title":"UploadSessionOperation","description":"One processing step — same triple POST /jobs/api takes."},"UploadSessionOut":{"properties":{"id":{"type":"string","title":"Id"},"status":{"$ref":"#/components/schemas/UploadSessionStatus"},"expires_at":{"type":"string","format":"date-time","title":"Expires At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"service_slug":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Service Slug"},"operation_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Operation Key"},"operations":{"items":{"$ref":"#/components/schemas/UploadSessionOperation"},"type":"array","title":"Operations"},"estimated_cost":{"type":"integer","title":"Estimated Cost"},"max_files":{"type":"integer","title":"Max Files"},"bundle_zip":{"type":"boolean","title":"Bundle Zip"},"files":{"items":{"$ref":"#/components/schemas/UploadSessionFileEntry"},"type":"array","title":"Files"},"file":{"$ref":"#/components/schemas/UploadSessionFileOut"},"uploaded_ip":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Uploaded Ip"},"job":{"anyOf":[{"$ref":"#/components/schemas/JobOut"},{"type":"null"}]},"jobs":{"items":{"$ref":"#/components/schemas/JobOut"},"type":"array","title":"Jobs"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"}},"type":"object","required":["id","status","expires_at","created_at","service_slug","operation_key","operations","estimated_cost","max_files","bundle_zip","files","file","uploaded_ip","job","jobs","error"],"title":"UploadSessionOut"},"UploadSessionStatus":{"type":"string","enum":["created","uploading","uploaded","processing","done","failed","expired"],"title":"UploadSessionStatus"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}},"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-Api-Key","description":"API key from https://metaplatho.com/docs/api (format `ca_live_...`)."}}},"servers":[{"url":"https://metaplatho.com"}],"security":[{"ApiKeyAuth":[]}]}