{"openapi":"3.1.0","info":{"title":"PhotoRescue API","version":"1.0.0","summary":"Enhance, upscale and restore photos with the PhotoRescue models.","description":"Asynchronous image processing: create a job, then poll it or receive a webhook. The same models and credits as photo-rescue.com.\n\n**Authentication**: `Authorization: Bearer pr_live_...` (sandbox keys start with `pr_test_`). Create keys in the dashboard.\n\n**Credits**: Upscale 8x costs 2 credits per image, every other task 1. Credits are charged when a job is accepted (202) and refunded automatically when it fails or is canceled. Without enough credits a job is refused with 402; there is no overage.\n\n| Plan | Price | Credits / month | Rate limit (per key) | Concurrent jobs (per account) |\n|---|---|---|---|---|\n| API Starter | $149/month | 2,000 | 60/min | 4 |\n| API Growth | $499/month | 8,000 | 300/min | 16 |\n| API Scale | $1499/month | 30,000 | 1000/min | 48 |\n\n**Results** are deleted 24 hours after the job completes. Output URLs are signed for 1 hour; GET the job again for a fresh URL.\n\n**Batches**: `POST /batches` creates one job per item (up to 500) and processes them together, which is faster and cheaper for many images. Every job shows live `progress` while it runs.\n\n**Webhooks**: `POST` of `{\"id\", \"type\": \"job.succeeded\" | \"job.failed\" | \"batch.completed\", \"data\": <job or batch>}` to the job's (or batch's) `webhook_url`, signed with `PhotoRescue-Signature: t=<unix>,v1=<hex HMAC-SHA256 of \"t.body\">` using the account webhook secret. Up to 5 attempts with exponential backoff over about 1 hour. Any 2xx answer counts as delivered.","termsOfService":"https://photo-rescue.com/en/legal/business-terms","contact":{"name":"PhotoRescue","url":"https://photo-rescue.com/en/contact"}},"servers":[{"url":"https://photo-rescue.com/api/v1","description":"Production"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Jobs","description":"Create and follow processing jobs."},{"name":"Batches","description":"Many images of one task in one request."},{"name":"Uploads","description":"Upload input files."},{"name":"Account","description":"Models and usage."}],"paths":{"/models":{"get":{"tags":["Account"],"operationId":"listModels","summary":"List models","description":"The current models (enhance, upscale, upscale-8x) with their scale, credit cost, input cap for your plan and whether each is available right now.","responses":{"200":{"description":"Models.","headers":{"RateLimit-Limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelList"},"example":{"object":"list","data":[{"id":"enhance","object":"model","name":"enhance","scale":1,"creditCost":1,"maxInputMp":30,"legacy":false,"enabled":true},{"id":"upscale","object":"model","name":"upscale","scale":4,"creditCost":1,"maxInputMp":5,"legacy":false,"enabled":true},{"id":"upscale-8x","object":"model","name":"upscale-8x","scale":8,"creditCost":2,"maxInputMp":1.25,"legacy":false,"enabled":true}]}}}},"401":{"description":"Missing, malformed or unknown API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_api_key":{"value":{"error":{"code":"invalid_api_key","message":"The API key is missing, malformed or unknown."}}}}}}},"403":{"description":"Revoked key, or the account has no active business plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"key_revoked":{"value":{"error":{"code":"key_revoked","message":"This API key has been revoked."}}},"plan_required":{"value":{"error":{"code":"plan_required","message":"API access needs an active business plan (API Starter, Growth or Scale).","details":{"plan":"pro200"}}}}}}}},"429":{"description":"Rate limit exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"value":{"error":{"code":"rate_limited","message":"Too many requests. Slow down and retry after the Retry-After delay.","details":{"limit":60,"window_seconds":60}}}}}}},"headers":{"RateLimit-Limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait.","schema":{"type":"integer"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"value":{"error":{"code":"internal_error","message":"Something went wrong on our side. Please retry."}}}}}}},"503":{"description":"Temporarily unavailable (e.g. the rate limiter); retry after Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"service_unavailable":{"value":{"error":{"code":"service_unavailable","message":"The service is temporarily unavailable. Please retry after the Retry-After delay."}}}}}},"headers":{"Retry-After":{"description":"Seconds to wait.","schema":{"type":"integer"}}}}}}},"/uploads":{"post":{"tags":["Uploads"],"operationId":"createUpload","summary":"Create an upload URL","description":"Returns a presigned URL for one direct `PUT` of the file. `size` (bytes) is required and signed into the URL: the PUT must send exactly that many bytes (`Content-Length`), so files above your plan's cap cannot be stored. Without `content_type`, PUT with the file's own Content-Type; with it, send exactly the returned `headers`. Then create a job with `{\"input\": {\"upload_id\": ...}}`. The file is validated when the job is created, before any charge.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadRequest"},"example":{"content_type":"image/jpeg","size":482113,"filename":"photo.jpg"}}}},"responses":{"201":{"description":"Upload URL.","headers":{"RateLimit-Limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Upload"},"example":{"object":"upload","upload_id":"upl_3hT9kLmN2pQ8rS4vW6xY1zA0","url":"https://images.example-r2.com/uploads/user/u/api/upl_3hT9kLmN2pQ8rS4vW6xY1zA0?X-Amz-Signature=...","method":"PUT","headers":{"Content-Type":"image/jpeg","Content-Length":"482113"},"expires_at":"2026-10-10T12:15:00.000Z","max_bytes":20971520}}}},"400":{"description":"Invalid request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_request":{"value":{"error":{"code":"invalid_request","message":"The request is not valid."}}}}}}},"401":{"description":"Missing, malformed or unknown API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_api_key":{"value":{"error":{"code":"invalid_api_key","message":"The API key is missing, malformed or unknown."}}}}}}},"403":{"description":"Revoked key, or the account has no active business plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"key_revoked":{"value":{"error":{"code":"key_revoked","message":"This API key has been revoked."}}},"plan_required":{"value":{"error":{"code":"plan_required","message":"API access needs an active business plan (API Starter, Growth or Scale).","details":{"plan":"pro200"}}}}}}}},"413":{"description":"File larger than the plan allows.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"file_too_large":{"value":{"error":{"code":"file_too_large","message":"The file is larger than your plan allows.","details":{"max_bytes":20971520,"size":31457280}}}}}}}},"415":{"description":"Unsupported format.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unsupported_format":{"value":{"error":{"code":"unsupported_format","message":"Unsupported image format. Use JPEG, PNG or WebP.","details":{"allowed":["image/jpeg","image/png","image/webp"]}}}}}}}},"429":{"description":"Rate limit exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"value":{"error":{"code":"rate_limited","message":"Too many requests. Slow down and retry after the Retry-After delay.","details":{"limit":60,"window_seconds":60}}}}}}},"headers":{"RateLimit-Limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait.","schema":{"type":"integer"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"value":{"error":{"code":"internal_error","message":"Something went wrong on our side. Please retry."}}}}}}},"503":{"description":"Temporarily unavailable (e.g. the rate limiter); retry after Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"service_unavailable":{"value":{"error":{"code":"service_unavailable","message":"The service is temporarily unavailable. Please retry after the Retry-After delay."}}}}}},"headers":{"Retry-After":{"description":"Seconds to wait.","schema":{"type":"integer"}}}}}}},"/jobs":{"post":{"tags":["Jobs"],"operationId":"createJob","summary":"Create a job","description":"Validates the input completely (format, decode, shape, megapixels for the task) before charging. Answers 202 with the queued job; poll `GET /jobs/{id}` or wait for the webhook. The same `Idempotency-Key` with the same body within 24 hours returns the same job.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string (1-255 printable ASCII characters), e.g. a UUID.","schema":{"type":"string","maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobRequest"},"examples":{"upload":{"value":{"task":"upscale-8x","input":{"upload_id":"upl_3hT9kLmN2pQ8rS4vW6xY1zA0"},"output_format":"jpeg","metadata":{"order_id":"A-1042"}}},"url":{"value":{"task":"enhance","input":{"url":"https://example.com/photo.jpg"},"webhook_url":"https://example.com/hooks/photorescue"}}}}}},"responses":{"202":{"description":"Accepted; credits charged.","headers":{"RateLimit-Limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}},"Location":{"description":"URL of the job.","schema":{"type":"string"}},"Idempotent-Replayed":{"description":"\"true\" when this is the job of an earlier request with the same Idempotency-Key.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"},"example":{"id":"job_Q1w2E3r4T5y6U7i8O9p0A1s2","object":"job","status":"queued","task":"upscale","credits":1,"created_at":"2026-10-10T12:00:00.000Z","completed_at":null,"input":{"width":320,"height":213},"output":null,"error":null,"metadata":{},"progress":null,"batch_id":null,"batch_index":null}}}},"400":{"description":"Invalid request or task not available.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_request":{"value":{"error":{"code":"invalid_request","message":"The request is not valid.","details":{"field":"task"}}}},"task_unavailable":{"value":{"error":{"code":"task_unavailable","message":"This task is not available right now.","details":{"task":"upscale-8x"}}}}}}}},"401":{"description":"Missing, malformed or unknown API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_api_key":{"value":{"error":{"code":"invalid_api_key","message":"The API key is missing, malformed or unknown."}}}}}}},"402":{"description":"Not enough credits.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"insufficient_credits":{"value":{"error":{"code":"insufficient_credits","message":"Not enough credits left in this billing period.","details":{"needed":2,"remaining":1}}}}}}}},"403":{"description":"Revoked key, or the account has no active business plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"key_revoked":{"value":{"error":{"code":"key_revoked","message":"This API key has been revoked."}}},"plan_required":{"value":{"error":{"code":"plan_required","message":"API access needs an active business plan (API Starter, Growth or Scale).","details":{"plan":"pro200"}}}}}}}},"404":{"description":"Unknown upload_id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"upload_not_found":{"value":{"error":{"code":"upload_not_found","message":"No uploaded file was found for this upload_id. Upload the file before creating the job.","details":{"upload_id":"upl_3hT9kLmN2pQ8rS4vW6xY1zA0"}}}}}}}},"409":{"description":"Idempotency-Key conflict.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"idempotency_conflict":{"value":{"error":{"code":"idempotency_conflict","message":"This Idempotency-Key was already used with a different request body."}}},"idempotency_in_progress":{"value":{"error":{"code":"idempotency_in_progress","message":"A request with this Idempotency-Key is still being processed."}}}}}}},"413":{"description":"File or image too large.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"file_too_large":{"value":{"error":{"code":"file_too_large","message":"The file is larger than your plan allows."}}},"image_too_large_for_task":{"value":{"error":{"code":"image_too_large_for_task","message":"The image has more megapixels than this task accepts.","details":{"task":"upscale-8x","max_megapixels":1.25,"megapixels":2.07,"task_cap":1.25}}}}}}}},"415":{"description":"Unsupported format.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unsupported_format":{"value":{"error":{"code":"unsupported_format","message":"Unsupported image format. Use JPEG, PNG or WebP."}}}}}}},"422":{"description":"The image or the input URL cannot be used.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"image_damaged":{"value":{"error":{"code":"image_damaged","message":"The image could not be decoded; the file looks damaged or truncated."}}},"image_shape":{"value":{"error":{"code":"image_shape","message":"The image is too small (under 16 px a side) or too elongated (over 12:1)."}}},"input_url_rejected":{"value":{"error":{"code":"input_url_rejected","message":"The input URL is not allowed. Use a public https URL."}}},"input_url_unreachable":{"value":{"error":{"code":"input_url_unreachable","message":"The input URL could not be downloaded."}}}}}}},"429":{"description":"Rate limit or concurrent-jobs cap.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"value":{"error":{"code":"rate_limited","message":"Too many requests. Slow down and retry after the Retry-After delay."}}},"concurrency_limit":{"value":{"error":{"code":"concurrency_limit","message":"Too many jobs in progress for this account. Wait for one to finish.","details":{"max_concurrent_jobs":4}}}}}}},"headers":{"RateLimit-Limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait.","schema":{"type":"integer"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"value":{"error":{"code":"internal_error","message":"Something went wrong on our side. Please retry."}}}}}}},"503":{"description":"Credit service or rate limiter unavailable; retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"quota_unavailable":{"value":{"error":{"code":"quota_unavailable","message":"The credit service is temporarily unavailable. Please retry."}}},"service_unavailable":{"value":{"error":{"code":"service_unavailable","message":"The service is temporarily unavailable. Please retry after the Retry-After delay."}}}}}}}},"callbacks":{"jobEvent":{"{$request.body#/webhook_url}":{"post":{"summary":"Job finished","parameters":[{"name":"PhotoRescue-Signature","in":"header","required":true,"schema":{"type":"string"},"example":"t=1760097641,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"},{"name":"PhotoRescue-Event","in":"header","required":true,"schema":{"type":"string"}},{"name":"PhotoRescue-Delivery","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"},"example":{"id":"evt_0f8e1d2c3b4a59687766554433221100","type":"job.succeeded","data":{"id":"job_8fK2mQ4xZ1aB7cD9eF3gH5jK","object":"job","status":"succeeded","task":"upscale-8x","credits":2,"created_at":"2026-10-10T12:00:00.000Z","completed_at":"2026-10-10T12:00:41.000Z","input":{"width":320,"height":213},"output":{"url":"https://images.example-r2.com/enhanced/upscale-8x/job_8fK2mQ4xZ1aB7cD9eF3gH5jK/output.jpg?X-Amz-Signature=...","width":2560,"height":1704,"format":"jpeg","expires_at":"2026-10-10T13:00:41.000Z"},"error":null,"metadata":{"order_id":"A-1042"},"progress":null,"batch_id":null,"batch_index":null}}}}},"responses":{"2XX":{"description":"Delivered. Anything else is retried."}}}}}}},"get":{"tags":["Jobs"],"operationId":"listJobs","summary":"List jobs","description":"Your account's API jobs, newest first, with cursor pagination.","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"cursor","in":"query","required":false,"description":"`next_cursor` of the previous page.","schema":{"type":"string"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["queued","processing","succeeded","failed","canceled"]}}],"responses":{"200":{"description":"A page of jobs.","headers":{"RateLimit-Limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobList"},"example":{"object":"list","data":[{"id":"job_8fK2mQ4xZ1aB7cD9eF3gH5jK","object":"job","status":"succeeded","task":"upscale-8x","credits":2,"created_at":"2026-10-10T12:00:00.000Z","completed_at":"2026-10-10T12:00:41.000Z","input":{"width":320,"height":213},"output":{"url":"https://images.example-r2.com/enhanced/upscale-8x/job_8fK2mQ4xZ1aB7cD9eF3gH5jK/output.jpg?X-Amz-Signature=...","width":2560,"height":1704,"format":"jpeg","expires_at":"2026-10-10T13:00:41.000Z"},"error":null,"metadata":{"order_id":"A-1042"},"progress":null,"batch_id":null,"batch_index":null},{"id":"job_Z9x8C7v6B5n4M3l2K1j0H9g8","object":"job","status":"failed","task":"enhance","credits":0,"created_at":"2026-10-10T12:00:00.000Z","completed_at":"2026-10-10T12:00:41.000Z","input":{"width":320,"height":213},"output":null,"error":{"code":"provider_error","message":"The processing service failed on this image. Credits were refunded."},"metadata":{},"progress":null,"batch_id":null,"batch_index":null}],"has_more":true,"next_cursor":"WyIyMDI2LTEwLTEwVDEyOjAwOjAwLjAwMFoiLCJqb2JfWjl4OEM3djZCNW40TTNsMksxajBIOWc4Il0"}}}},"400":{"description":"Invalid limit, cursor or status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_request":{"value":{"error":{"code":"invalid_request","message":"The request is not valid.","details":{"field":"limit"}}}}}}}},"401":{"description":"Missing, malformed or unknown API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_api_key":{"value":{"error":{"code":"invalid_api_key","message":"The API key is missing, malformed or unknown."}}}}}}},"403":{"description":"Revoked key, or the account has no active business plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"key_revoked":{"value":{"error":{"code":"key_revoked","message":"This API key has been revoked."}}},"plan_required":{"value":{"error":{"code":"plan_required","message":"API access needs an active business plan (API Starter, Growth or Scale).","details":{"plan":"pro200"}}}}}}}},"429":{"description":"Rate limit exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"value":{"error":{"code":"rate_limited","message":"Too many requests. Slow down and retry after the Retry-After delay.","details":{"limit":60,"window_seconds":60}}}}}}},"headers":{"RateLimit-Limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait.","schema":{"type":"integer"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"value":{"error":{"code":"internal_error","message":"Something went wrong on our side. Please retry."}}}}}}},"503":{"description":"Temporarily unavailable (e.g. the rate limiter); retry after Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"service_unavailable":{"value":{"error":{"code":"service_unavailable","message":"The service is temporarily unavailable. Please retry after the Retry-After delay."}}}}}},"headers":{"Retry-After":{"description":"Seconds to wait.","schema":{"type":"integer"}}}}}}},"/jobs/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","pattern":"^job_[A-Za-z0-9]{8,64}$"}}],"get":{"tags":["Jobs"],"operationId":"getJob","summary":"Get a job","description":"Status and result. While the result exists (24 h) every call returns a fresh output URL valid for 1 hour.","responses":{"200":{"description":"The job.","headers":{"RateLimit-Limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"},"examples":{"succeeded":{"value":{"id":"job_8fK2mQ4xZ1aB7cD9eF3gH5jK","object":"job","status":"succeeded","task":"upscale-8x","credits":2,"created_at":"2026-10-10T12:00:00.000Z","completed_at":"2026-10-10T12:00:41.000Z","input":{"width":320,"height":213},"output":{"url":"https://images.example-r2.com/enhanced/upscale-8x/job_8fK2mQ4xZ1aB7cD9eF3gH5jK/output.jpg?X-Amz-Signature=...","width":2560,"height":1704,"format":"jpeg","expires_at":"2026-10-10T13:00:41.000Z"},"error":null,"metadata":{"order_id":"A-1042"},"progress":null,"batch_id":null,"batch_index":null}},"processing":{"value":{"id":"job_P1o2I3u4Y5t6R7e8W9q0L1k2","object":"job","status":"processing","task":"upscale","credits":1,"created_at":"2026-10-10T12:00:00.000Z","completed_at":null,"input":{"width":320,"height":213},"output":null,"error":null,"metadata":{},"progress":{"stage":"restore","fraction":0.42,"eta_ms":6500},"batch_id":null,"batch_index":null}},"failed":{"value":{"id":"job_Z9x8C7v6B5n4M3l2K1j0H9g8","object":"job","status":"failed","task":"enhance","credits":0,"created_at":"2026-10-10T12:00:00.000Z","completed_at":"2026-10-10T12:00:41.000Z","input":{"width":320,"height":213},"output":null,"error":{"code":"provider_error","message":"The processing service failed on this image. Credits were refunded."},"metadata":{},"progress":null,"batch_id":null,"batch_index":null}}}}}},"401":{"description":"Missing, malformed or unknown API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_api_key":{"value":{"error":{"code":"invalid_api_key","message":"The API key is missing, malformed or unknown."}}}}}}},"403":{"description":"Revoked key, or the account has no active business plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"key_revoked":{"value":{"error":{"code":"key_revoked","message":"This API key has been revoked."}}},"plan_required":{"value":{"error":{"code":"plan_required","message":"API access needs an active business plan (API Starter, Growth or Scale).","details":{"plan":"pro200"}}}}}}}},"404":{"description":"No such job for this account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"value":{"error":{"code":"not_found","message":"Not found."}}}}}}},"429":{"description":"Rate limit exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"value":{"error":{"code":"rate_limited","message":"Too many requests. Slow down and retry after the Retry-After delay.","details":{"limit":60,"window_seconds":60}}}}}}},"headers":{"RateLimit-Limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait.","schema":{"type":"integer"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"value":{"error":{"code":"internal_error","message":"Something went wrong on our side. Please retry."}}}}}}},"503":{"description":"Temporarily unavailable (e.g. the rate limiter); retry after Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"service_unavailable":{"value":{"error":{"code":"service_unavailable","message":"The service is temporarily unavailable. Please retry after the Retry-After delay."}}}}}},"headers":{"Retry-After":{"description":"Seconds to wait.","schema":{"type":"integer"}}}}}},"delete":{"tags":["Jobs"],"operationId":"cancelJob","summary":"Cancel a queued job","description":"Only queued jobs can be canceled; their credits are refunded.","responses":{"200":{"description":"The canceled job.","headers":{"RateLimit-Limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"},"example":{"id":"job_Q1w2E3r4T5y6U7i8O9p0A1s2","object":"job","status":"canceled","task":"upscale","credits":0,"created_at":"2026-10-10T12:00:00.000Z","completed_at":"2026-10-10T12:00:02.000Z","input":{"width":320,"height":213},"output":null,"error":{"code":"canceled","message":"The job was canceled. Credits were refunded."},"metadata":{},"progress":null,"batch_id":null,"batch_index":null}}}},"401":{"description":"Missing, malformed or unknown API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_api_key":{"value":{"error":{"code":"invalid_api_key","message":"The API key is missing, malformed or unknown."}}}}}}},"403":{"description":"Revoked key, or the account has no active business plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"key_revoked":{"value":{"error":{"code":"key_revoked","message":"This API key has been revoked."}}},"plan_required":{"value":{"error":{"code":"plan_required","message":"API access needs an active business plan (API Starter, Growth or Scale).","details":{"plan":"pro200"}}}}}}}},"404":{"description":"No such job for this account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"value":{"error":{"code":"not_found","message":"Not found."}}}}}}},"409":{"description":"The job already started or finished.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"job_not_cancelable":{"value":{"error":{"code":"job_not_cancelable","message":"Only queued jobs can be canceled.","details":{"status":"processing"}}}}}}}},"429":{"description":"Rate limit exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"value":{"error":{"code":"rate_limited","message":"Too many requests. Slow down and retry after the Retry-After delay.","details":{"limit":60,"window_seconds":60}}}}}}},"headers":{"RateLimit-Limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait.","schema":{"type":"integer"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"value":{"error":{"code":"internal_error","message":"Something went wrong on our side. Please retry."}}}}}}},"503":{"description":"Temporarily unavailable (e.g. the rate limiter); retry after Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"service_unavailable":{"value":{"error":{"code":"service_unavailable","message":"The service is temporarily unavailable. Please retry after the Retry-After delay."}}}}}},"headers":{"Retry-After":{"description":"Seconds to wait.","schema":{"type":"integer"}}}}}}},"/batches":{"post":{"tags":["Batches"],"operationId":"createBatch","summary":"Create a batch","description":"Creates one job per item (1 to 500 items, one task) with a shared `batch_id` and its request `batch_index`; the jobs are processed together in few GPU runs. Each item is validated and charged like `POST /jobs`; items that cannot be accepted are listed in `rejected` and cost nothing. With an `Idempotency-Key`, a retry with the same body returns the first batch (and resumes it if the first request was interrupted); the same key with a different body is `409 idempotency_conflict`. The batch `webhook_url` receives `batch.completed` once every job has finished.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string (1-255 printable ASCII characters).","schema":{"type":"string","maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchRequest"},"example":{"task":"upscale","items":[{"input":{"upload_id":"upl_3hT9kLmN2pQ8rS4vW6xY1zA0"},"metadata":{"sku":"SKU-1"}},{"input":{"url":"https://example.com/sku-2.jpg"},"metadata":{"sku":"SKU-2"}}],"webhook_url":"https://example.com/hooks/photorescue","metadata":{"shoot":"spring-catalog"}}}}},"responses":{"202":{"description":"Accepted; credits charged for the accepted items.","headers":{"RateLimit-Limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}},"Location":{"description":"URL of the batch.","schema":{"type":"string"}},"Idempotent-Replayed":{"description":"\"true\" when this is the batch of an earlier request with the same Idempotency-Key.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Batch"},"example":{"id":"batch_4Gh7Jk2Lm9Np3Qr6St8Uv1Wx","object":"batch","status":"processing","task":"upscale","created_at":"2026-10-10T12:00:00.000Z","completed_at":null,"counts":{"total":2,"queued":2,"processing":0,"succeeded":0,"failed":0,"canceled":0},"progress":0,"metadata":{"shoot":"spring-catalog"},"jobs":[{"id":"job_B1a2T3c4H5j6O7b8S9x0Y1z2","object":"job","status":"queued","task":"upscale","credits":1,"created_at":"2026-10-10T12:00:00.000Z","completed_at":null,"input":{"width":640,"height":480},"output":null,"error":null,"metadata":{"sku":"SKU-1"},"progress":{"stage":"starting","fraction":0,"eta_ms":null},"batch_id":"batch_4Gh7Jk2Lm9Np3Qr6St8Uv1Wx","batch_index":0},{"id":"job_P1o2I3u4Y5t6R7e8W9q0L1k2","object":"job","status":"queued","task":"upscale","credits":1,"created_at":"2026-10-10T12:00:00.000Z","completed_at":null,"input":{"width":320,"height":213},"output":null,"error":null,"metadata":{"sku":"SKU-2"},"progress":{"stage":"starting","fraction":0,"eta_ms":null},"batch_id":"batch_4Gh7Jk2Lm9Np3Qr6St8Uv1Wx","batch_index":1}]}}}},"400":{"description":"Invalid request or task not available.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_request":{"value":{"error":{"code":"invalid_request","message":"The request is not valid.","details":{"field":"items"}}}},"task_unavailable":{"value":{"error":{"code":"task_unavailable","message":"This task is not available right now."}}}}}}},"401":{"description":"Missing, malformed or unknown API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_api_key":{"value":{"error":{"code":"invalid_api_key","message":"The API key is missing, malformed or unknown."}}}}}}},"402":{"description":"Not enough credits for every item.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"insufficient_credits":{"value":{"error":{"code":"insufficient_credits","message":"Not enough credits left in this billing period.","details":{"needed":40,"remaining":12}}}}}}}},"403":{"description":"Revoked key, or the account has no active business plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"key_revoked":{"value":{"error":{"code":"key_revoked","message":"This API key has been revoked."}}},"plan_required":{"value":{"error":{"code":"plan_required","message":"API access needs an active business plan (API Starter, Growth or Scale).","details":{"plan":"pro200"}}}}}}}},"409":{"description":"Idempotency-Key used with another body, or the batch is still being created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"idempotency_conflict":{"value":{"error":{"code":"idempotency_conflict","message":"This Idempotency-Key was already used with a different request body."}}},"idempotency_in_progress":{"value":{"error":{"code":"idempotency_in_progress","message":"A request with this Idempotency-Key is still being processed."}}}}}}},"422":{"description":"No item could be accepted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"batch_rejected":{"value":{"error":{"code":"batch_rejected","message":"None of the batch items could be accepted; see details.rejected.","details":{"rejected":[{"index":0,"error":{"code":"image_damaged","message":"The image could not be decoded; the file looks damaged or truncated."}}]}}}}}}}},"429":{"description":"Rate limit exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"value":{"error":{"code":"rate_limited","message":"Too many requests. Slow down and retry after the Retry-After delay.","details":{"limit":60,"window_seconds":60}}}}}}},"headers":{"RateLimit-Limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait.","schema":{"type":"integer"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"value":{"error":{"code":"internal_error","message":"Something went wrong on our side. Please retry."}}}}}}},"503":{"description":"Temporarily unavailable (e.g. the rate limiter); retry after Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"service_unavailable":{"value":{"error":{"code":"service_unavailable","message":"The service is temporarily unavailable. Please retry after the Retry-After delay."}}}}}},"headers":{"Retry-After":{"description":"Seconds to wait.","schema":{"type":"integer"}}}}},"callbacks":{"batchEvent":{"{$request.body#/webhook_url}":{"post":{"summary":"Batch completed","parameters":[{"name":"PhotoRescue-Signature","in":"header","required":true,"schema":{"type":"string"},"example":"t=1760097641,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"},{"name":"PhotoRescue-Event","in":"header","required":true,"schema":{"type":"string"}},{"name":"PhotoRescue-Delivery","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"},"example":{"id":"evt_1a2b3c4d5e6f708192a3b4c5d6e7f809","type":"batch.completed","data":{"id":"batch_4Gh7Jk2Lm9Np3Qr6St8Uv1Wx","object":"batch","status":"completed","task":"upscale","created_at":"2026-10-10T12:00:00.000Z","completed_at":"2026-10-10T12:01:10.000Z","counts":{"total":2,"queued":0,"processing":0,"succeeded":2,"failed":0,"canceled":0},"progress":1,"metadata":{"shoot":"spring-catalog"},"jobs":[{"id":"job_B1a2T3c4H5j6O7b8S9x0Y1z2","object":"job","status":"succeeded","task":"upscale","credits":1,"created_at":"2026-10-10T12:00:00.000Z","completed_at":"2026-10-10T12:00:41.000Z","input":{"width":640,"height":480},"output":{"url":"https://images.example-r2.com/enhanced/upscale-8x/job_8fK2mQ4xZ1aB7cD9eF3gH5jK/output.jpg?X-Amz-Signature=...","width":2560,"height":1920,"format":"jpeg","expires_at":"2026-10-10T13:00:41.000Z"},"error":null,"metadata":{"sku":"SKU-1"},"progress":null,"batch_id":"batch_4Gh7Jk2Lm9Np3Qr6St8Uv1Wx","batch_index":0},{"id":"job_C1d2E3f4G5h6I7j8K9l0M1n2","object":"job","status":"succeeded","task":"upscale","credits":1,"created_at":"2026-10-10T12:00:00.000Z","completed_at":"2026-10-10T12:00:41.000Z","input":{"width":640,"height":480},"output":{"url":"https://images.example-r2.com/enhanced/upscale-8x/job_8fK2mQ4xZ1aB7cD9eF3gH5jK/output.jpg?X-Amz-Signature=...","width":2560,"height":1920,"format":"jpeg","expires_at":"2026-10-10T13:00:41.000Z"},"error":null,"metadata":{"sku":"SKU-2"},"progress":null,"batch_id":"batch_4Gh7Jk2Lm9Np3Qr6St8Uv1Wx","batch_index":1}]}}}}},"responses":{"2XX":{"description":"Delivered. Anything else is retried."}}}}}}}},"/batches/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","pattern":"^batch_[A-Za-z0-9]{8,64}$"}}],"get":{"tags":["Batches"],"operationId":"getBatch","summary":"Get a batch","description":"Counts, overall progress and every job of the batch (with fresh output URLs).","responses":{"200":{"description":"The batch.","headers":{"RateLimit-Limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Batch"},"example":{"id":"batch_4Gh7Jk2Lm9Np3Qr6St8Uv1Wx","object":"batch","status":"processing","task":"upscale","created_at":"2026-10-10T12:00:00.000Z","completed_at":null,"counts":{"total":2,"queued":0,"processing":1,"succeeded":1,"failed":0,"canceled":0},"progress":0.71,"metadata":{"shoot":"spring-catalog"},"jobs":[{"id":"job_B1a2T3c4H5j6O7b8S9x0Y1z2","object":"job","status":"succeeded","task":"upscale","credits":1,"created_at":"2026-10-10T12:00:00.000Z","completed_at":"2026-10-10T12:00:41.000Z","input":{"width":640,"height":480},"output":{"url":"https://images.example-r2.com/enhanced/upscale-8x/job_8fK2mQ4xZ1aB7cD9eF3gH5jK/output.jpg?X-Amz-Signature=...","width":2560,"height":1920,"format":"jpeg","expires_at":"2026-10-10T13:00:41.000Z"},"error":null,"metadata":{"sku":"SKU-1"},"progress":null,"batch_id":"batch_4Gh7Jk2Lm9Np3Qr6St8Uv1Wx","batch_index":0},{"id":"job_P1o2I3u4Y5t6R7e8W9q0L1k2","object":"job","status":"processing","task":"upscale","credits":1,"created_at":"2026-10-10T12:00:00.000Z","completed_at":null,"input":{"width":320,"height":213},"output":null,"error":null,"metadata":{"sku":"SKU-2"},"progress":{"stage":"restore","fraction":0.42,"eta_ms":6500},"batch_id":"batch_4Gh7Jk2Lm9Np3Qr6St8Uv1Wx","batch_index":1}]}}}},"401":{"description":"Missing, malformed or unknown API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_api_key":{"value":{"error":{"code":"invalid_api_key","message":"The API key is missing, malformed or unknown."}}}}}}},"403":{"description":"Revoked key, or the account has no active business plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"key_revoked":{"value":{"error":{"code":"key_revoked","message":"This API key has been revoked."}}},"plan_required":{"value":{"error":{"code":"plan_required","message":"API access needs an active business plan (API Starter, Growth or Scale).","details":{"plan":"pro200"}}}}}}}},"404":{"description":"No such batch for this account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"value":{"error":{"code":"not_found","message":"Not found."}}}}}}},"429":{"description":"Rate limit exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"value":{"error":{"code":"rate_limited","message":"Too many requests. Slow down and retry after the Retry-After delay.","details":{"limit":60,"window_seconds":60}}}}}}},"headers":{"RateLimit-Limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait.","schema":{"type":"integer"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"value":{"error":{"code":"internal_error","message":"Something went wrong on our side. Please retry."}}}}}}},"503":{"description":"Temporarily unavailable (e.g. the rate limiter); retry after Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"service_unavailable":{"value":{"error":{"code":"service_unavailable","message":"The service is temporarily unavailable. Please retry after the Retry-After delay."}}}}}},"headers":{"Retry-After":{"description":"Seconds to wait.","schema":{"type":"integer"}}}}}}},"/usage":{"get":{"tags":["Account"],"operationId":"getUsage","summary":"Get usage","description":"Plan, current period and credits. Credits are shared between the API and the website.","responses":{"200":{"description":"Usage.","headers":{"RateLimit-Limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Usage"},"example":{"object":"usage","plan":"api_starter","api_access":true,"period_start":"2026-10-01","period_end":"2026-11-01","credits_included":2000,"credits_used":312,"credits_remaining":1688,"overage_credits":0}}}},"401":{"description":"Missing, malformed or unknown API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_api_key":{"value":{"error":{"code":"invalid_api_key","message":"The API key is missing, malformed or unknown."}}}}}}},"403":{"description":"Revoked key, or the account has no active business plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"key_revoked":{"value":{"error":{"code":"key_revoked","message":"This API key has been revoked."}}},"plan_required":{"value":{"error":{"code":"plan_required","message":"API access needs an active business plan (API Starter, Growth or Scale).","details":{"plan":"pro200"}}}}}}}},"429":{"description":"Rate limit exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"value":{"error":{"code":"rate_limited","message":"Too many requests. Slow down and retry after the Retry-After delay.","details":{"limit":60,"window_seconds":60}}}}}}},"headers":{"RateLimit-Limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait.","schema":{"type":"integer"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"internal_error":{"value":{"error":{"code":"internal_error","message":"Something went wrong on our side. Please retry."}}}}}}},"503":{"description":"Temporarily unavailable (e.g. the rate limiter); retry after Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"service_unavailable":{"value":{"error":{"code":"service_unavailable","message":"The service is temporarily unavailable. Please retry after the Retry-After delay."}}}}}},"headers":{"Retry-After":{"description":"Seconds to wait.","schema":{"type":"integer"}}}}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API key: `pr_live_...` (production) or `pr_test_...` (sandbox)."}},"schemas":{"Error":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"object","required":["code","message"],"additionalProperties":false,"properties":{"code":{"type":"string","enum":["invalid_api_key","key_revoked","plan_required","invalid_request","task_unavailable","not_found","upload_not_found","method_not_allowed","idempotency_conflict","idempotency_in_progress","job_not_cancelable","insufficient_credits","file_too_large","image_too_large_for_task","unsupported_format","image_damaged","batch_rejected","image_shape","input_url_rejected","input_url_unreachable","rate_limited","concurrency_limit","quota_unavailable","service_unavailable","internal_error"]},"message":{"type":"string"},"details":{"type":"object"}}}}},"Model":{"type":"object","required":["id","object","name","scale","creditCost","maxInputMp","legacy","enabled"],"additionalProperties":false,"properties":{"id":{"type":"string","enum":["enhance","upscale","upscale-8x"]},"object":{"type":"string","enum":["model"]},"name":{"type":"string"},"scale":{"type":"integer"},"creditCost":{"type":"integer"},"maxInputMp":{"type":"number","description":"Largest input in megapixels on your plan."},"legacy":{"type":"boolean"},"enabled":{"type":"boolean"}}},"ModelList":{"type":"object","required":["object","data"],"additionalProperties":false,"properties":{"object":{"type":"string","enum":["list"]},"data":{"type":"array","items":{"$ref":"#/components/schemas/Model"}}}},"UploadRequest":{"type":"object","required":["size"],"additionalProperties":false,"properties":{"content_type":{"type":"string","enum":["image/jpeg","image/png","image/webp"],"description":"Signed into the URL; send the same Content-Type."},"size":{"type":"integer","minimum":1,"description":"Exact file size in bytes (signed into the URL; at most the plan cap)."},"filename":{"type":"string","maxLength":255}}},"Upload":{"type":"object","required":["object","upload_id","url","method","headers","expires_at","max_bytes"],"additionalProperties":false,"properties":{"object":{"type":"string","enum":["upload"]},"upload_id":{"type":"string","pattern":"^upl_[A-Za-z0-9]{24}$"},"url":{"type":"string","format":"uri"},"method":{"type":"string","enum":["PUT"]},"headers":{"type":"object","additionalProperties":{"type":"string"}},"expires_at":{"type":"string","format":"date-time"},"max_bytes":{"type":"integer"}}},"JobRequest":{"type":"object","required":["task","input"],"additionalProperties":false,"properties":{"task":{"type":"string","enum":["enhance","upscale","upscale-8x"]},"input":{"oneOf":[{"type":"object","required":["upload_id"],"additionalProperties":false,"properties":{"upload_id":{"type":"string","pattern":"^upl_[A-Za-z0-9]{24}$"}}},{"type":"object","required":["url"],"additionalProperties":false,"properties":{"url":{"type":"string","format":"uri","description":"Public https URL (no private addresses), JPEG/PNG/WebP."}}}]},"output_format":{"type":"string","enum":["auto","png","jpeg","webp"],"default":"auto"},"webhook_url":{"type":"string","format":"uri","description":"Public https URL that receives job.succeeded / job.failed."},"metadata":{"type":"object","maxProperties":20,"additionalProperties":{"type":"string","maxLength":500},"propertyNames":{"maxLength":40}}}},"Job":{"type":"object","required":["id","object","status","task","credits","created_at","completed_at","input","output","error","metadata","progress","batch_id","batch_index"],"additionalProperties":false,"properties":{"id":{"type":"string"},"object":{"type":"string","enum":["job"]},"status":{"type":"string","enum":["queued","processing","succeeded","failed","canceled"]},"task":{"type":"string","description":"Model id of the job: enhance, upscale or upscale-8x."},"credits":{"type":"integer","description":"Credits currently charged for this job (0 after a refund)."},"created_at":{"type":"string","format":"date-time"},"completed_at":{"type":["string","null"],"format":"date-time"},"input":{"type":"object","required":["width","height"],"additionalProperties":false,"properties":{"width":{"type":["integer","null"]},"height":{"type":["integer","null"]}}},"output":{"oneOf":[{"type":"null"},{"type":"object","required":["url","width","height","format","expires_at"],"additionalProperties":false,"properties":{"url":{"type":"string","format":"uri"},"width":{"type":["integer","null"]},"height":{"type":["integer","null"]},"format":{"type":"string","enum":["jpeg","png","webp"]},"expires_at":{"type":"string","format":"date-time"}}}]},"error":{"oneOf":[{"type":"null"},{"type":"object","required":["code","message"],"additionalProperties":false,"properties":{"code":{"type":"string"},"message":{"type":"string"}}}]},"metadata":{"type":"object","additionalProperties":{"type":"string"}},"progress":{"description":"Live progress while queued or processing (null when finished). `starting`: waiting for a GPU; `queued`: the GPU is up and this image waits for its turn; then the processing stages. `eta_ms` is measured from the processing rate (null until known).","oneOf":[{"type":"null"},{"type":"object","required":["stage","fraction","eta_ms"],"additionalProperties":false,"properties":{"stage":{"type":"string","enum":["starting","queued","download","restore","refine","encode","upload","saving"]},"fraction":{"type":"number","minimum":0,"maximum":1},"eta_ms":{"type":["integer","null"]}}}]},"batch_id":{"type":["string","null"],"description":"The batch this job belongs to (POST /batches)."},"batch_index":{"type":["integer","null"],"description":"Index of the item in the POST /batches request (0-based); batch jobs are listed in this order."}}},"BatchRequest":{"type":"object","required":["task","items"],"additionalProperties":false,"properties":{"task":{"type":"string","enum":["enhance","upscale","upscale-8x"]},"items":{"type":"array","minItems":1,"maxItems":500,"items":{"type":"object","required":["input"],"additionalProperties":false,"properties":{"input":{"oneOf":[{"type":"object","required":["upload_id"],"additionalProperties":false,"properties":{"upload_id":{"type":"string","pattern":"^upl_[A-Za-z0-9]{24}$"}}},{"type":"object","required":["url"],"additionalProperties":false,"properties":{"url":{"type":"string","format":"uri"}}}]},"metadata":{"type":"object","maxProperties":20,"additionalProperties":{"type":"string","maxLength":500}}}}},"output_format":{"type":"string","enum":["auto","png","jpeg","webp"],"default":"auto"},"webhook_url":{"type":"string","format":"uri","description":"Public https URL that receives batch.completed."},"metadata":{"type":"object","maxProperties":20,"additionalProperties":{"type":"string","maxLength":500}}}},"Batch":{"type":"object","required":["id","object","status","task","created_at","completed_at","counts","progress","metadata","jobs"],"additionalProperties":false,"properties":{"id":{"type":"string"},"object":{"type":"string","enum":["batch"]},"status":{"type":"string","enum":["processing","completed"]},"task":{"type":"string","description":"Model id of the batch: enhance, upscale or upscale-8x."},"created_at":{"type":"string","format":"date-time"},"completed_at":{"type":["string","null"],"format":"date-time"},"counts":{"type":"object","required":["total","queued","processing","succeeded","failed","canceled"],"additionalProperties":false,"properties":{"total":{"type":"integer"},"queued":{"type":"integer"},"processing":{"type":"integer"},"succeeded":{"type":"integer"},"failed":{"type":"integer"},"canceled":{"type":"integer"}}},"progress":{"type":"number","minimum":0,"maximum":1,"description":"Overall progress; finished jobs count as 1."},"metadata":{"type":"object","additionalProperties":{"type":"string"}},"jobs":{"type":"array","items":{"$ref":"#/components/schemas/Job"}},"rejected":{"type":"array","description":"Only in the POST response: items that were not accepted (no job, no charge).","items":{"type":"object","required":["index","error"],"additionalProperties":false,"properties":{"index":{"type":"integer"},"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"object"}}}}}}}},"JobList":{"type":"object","required":["object","data","has_more","next_cursor"],"additionalProperties":false,"properties":{"object":{"type":"string","enum":["list"]},"data":{"type":"array","items":{"$ref":"#/components/schemas/Job"}},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"]}}},"Usage":{"type":"object","required":["object","plan","api_access","period_start","period_end","credits_included","credits_used","credits_remaining","overage_credits"],"additionalProperties":false,"properties":{"object":{"type":"string","enum":["usage"]},"plan":{"type":"string"},"api_access":{"type":"boolean"},"period_start":{"type":"string","format":"date"},"period_end":{"type":"string","format":"date"},"credits_included":{"type":"integer"},"credits_used":{"type":"integer"},"credits_remaining":{"type":"integer"},"overage_credits":{"type":"integer"}}},"WebhookEvent":{"type":"object","required":["id","type","data"],"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"type":"string","enum":["job.succeeded","job.failed","batch.completed","webhook.test"]},"data":{"anyOf":[{"$ref":"#/components/schemas/Job"},{"$ref":"#/components/schemas/Batch"},{"type":"object","description":"webhook.test: {message, test_id}"}]}}}}}}