{"openapi":"3.1.0","info":{"title":"KısaLinkAtla API","description":"Resolve ad-gated and shortened links (ouo, aylink, cuty.io, shorte.st, cpmlink, trlink …) to their final destination URL.\n\nAuthenticate every request with the `X-API-Key` header. Create keys and see plans at https://www.kisalinkatla.com/developers. Machine-readable limits and the supported-domain list are available at `GET /api-info`.\n\nTwo ways to resolve:\n- `POST /resolve` — synchronous; waits up to ~10s and returns the result, or `202` with a `job_id` to poll.\n- `POST /bypass` — asynchronous; returns a `job_id`, then poll `GET /job/{job_id}` until `status` is `success` or `dead`.\n- `POST /batch/bypass` — queue up to 50 links at once, then poll `GET /batch/{batch_id}`.\n\n`safety_status` (VirusTotal scan) is not performed for API-key requests and is `null` in API responses.\n\nErrors use a standard envelope: `{\"error\": {\"code\", \"message\", \"retryable\"}, \"detail\"}`. Quota headers: `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`.","version":"1.0.0"},"paths":{"/bypass":{"post":{"summary":"Queue a link for resolution","operationId":"bypass_url_bypass_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"started","job_id":"3f2a…","lane":"heavy","message":"Job queued."}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"invalid_api_key","message":"Invalid API key.","retryable":false},"detail":"Invalid API key."}}}},"429":{"description":"Rate limit or daily quota exceeded"}},"description":"Queues the short link and returns a `job_id` immediately (or the cached result if the link was resolved before). Poll `GET /job/{job_id}` for the result. Costs 1 quota unit; refunded if the link is detected as dead before processing.","tags":["public"]}},"/job/{job_id}":{"get":{"summary":"Get job status","operationId":"job_status_job__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":{},"example":{"job_id":"3f2a…","status":"success","lane":"heavy","attempt":1,"max_attempts":2,"result_url":"https://example.com/file","engine_used":"dom_bypass","safety_status":null,"created_at":"2026-10-05T12:00:00","completed_at":"2026-10-05T12:00:07"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"invalid_api_key","message":"Invalid API key.","retryable":false},"detail":"Invalid API key."}}}},"429":{"description":"Rate limit or daily quota exceeded"}},"description":"Returns the state of a job created by `POST /bypass` or `POST /resolve`. `status` is one of `pending`, `processing`, `retrying`, `success`, `dead`. Only the key that created the job can read it (others get 404). Polling does not consume quota. `safety_status` is `null` for API-key requests.","tags":["public"]}},"/status/{id}":{"get":{"summary":"Get job status (alias)","description":"Backwards-compatible alias of `GET /job/{job_id}`.","operationId":"get_status_status__id__get","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"invalid_api_key","message":"Invalid API key.","retryable":false},"detail":"Invalid API key."}}}},"429":{"description":"Rate limit or daily quota exceeded"}},"tags":["public"]}},"/resolve":{"post":{"summary":"Resolve a link synchronously","description":"Resolves the short link and returns the destination in one call. Shares auth, quota, cache and queue with `POST /bypass`. If the job is not finished within ~10 seconds, responds `202` with a `job_id`; poll `GET /job/{job_id}`. Costs 1 quota unit.","operationId":"resolve_url_resolve_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","url":"https://ouo.io/abc123","result_url":"https://example.com/file","engine":"dom_bypass","lane":"heavy","safety_status":null,"cached":false,"elapsed_ms":7400,"job_id":"3f2a…"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"invalid_api_key","message":"Invalid API key.","retryable":false},"detail":"Invalid API key."}}}},"429":{"description":"Rate limit or daily quota exceeded"},"202":{"description":"Still processing — poll GET /job/{job_id}","content":{"application/json":{"example":{"status":"pending","job_id":"3f2a…","lane":"heavy","message":"Still processing; poll GET /job/{job_id} for the result."}}}}},"tags":["public"]}},"/batch/bypass":{"post":{"summary":"Queue a batch of links","description":"Queues up to 50 distinct short links in one request and returns a `batch_id` plus one `job_id` per URL. Each URL costs 1 quota unit; the full amount is reserved up front, and if the remaining quota is not enough the whole batch is rejected with `429` (nothing is charged). If any URL is from an unsupported domain the batch is rejected and the quota refunded. Poll `GET /batch/{batch_id}` (or each `GET /job/{job_id}`). More than 50 URLs, an empty list or duplicate URLs are rejected: request validation answers `422`, and the handler additionally guards the size with `400` `batch_too_large` (`max_urls: 50`).","operationId":"batch_bypass_batch_bypass_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchLinkRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"batch_id":"9c1e…","count":2,"jobs":[{"url":"https://ouo.io/abc123","job_id":"3f2a…","lane":"heavy","status":"pending"},{"url":"https://cuty.io/xyz789","job_id":"7b4d…","lane":"fast","status":"pending"}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"invalid_api_key","message":"Invalid API key.","retryable":false},"detail":"Invalid API key."}}}},"429":{"description":"Rate limit or daily quota exceeded"},"400":{"description":"Batch too large (max 50 URLs)","content":{"application/json":{"example":{"detail":{"code":"batch_too_large","message":"A batch may contain at most 50 URLs.","max_urls":50}}}}}},"tags":["public"]}},"/batch/{batch_id}":{"get":{"summary":"Get batch status","description":"Returns every job of a batch created with the same API key (other keys get 404). Aggregate `status` is `processing` while any job is `pending`/`processing`/`retrying`, `complete` when all succeeded, otherwise `partial`. Does not consume quota. `safety_status` is `null` for API-key requests.","operationId":"batch_status_batch__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":{},"example":{"batch_id":"9c1e…","status":"partial","total":2,"done":2,"successful":1,"failed":1,"jobs":[{"job_id":"3f2a…","url":"https://ouo.io/abc123","status":"success","lane":"heavy","result_url":"https://example.com/file","engine_used":"dom_bypass","safety_status":null,"completed_at":"2026-10-05T12:00:07"},{"job_id":"7b4d…","url":"https://cuty.io/xyz789","status":"dead","lane":"fast","result_url":null,"engine_used":null,"safety_status":null,"completed_at":"2026-10-05T12:00:20","last_error":{"error_type":"BypassTimeoutError","message":"Bypass timed out.","url":"https://cuty.io/xyz789","engine":"cutyio","retry_policy":"retry","original":null}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"invalid_api_key","message":"Invalid API key.","retryable":false},"detail":"Invalid API key."}}}},"429":{"description":"Rate limit or daily quota exceeded"}},"tags":["public"]}},"/history":{"get":{"summary":"Recent jobs of this API key","description":"Lists the most recent finished jobs (`success` and `dead`, newest first) created with this API key; `limit` is 1–20 (default 20). API-key only. Does not consume quota. `safety_status` is `null` for API-key requests.","operationId":"get_history_history_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":20,"minimum":1,"default":20,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":[{"url":"https://ouo.io/abc123","result_url":"https://example.com/file","lane":"heavy","engine":"dom_bypass","status":"success","safety_status":null,"elapsed_ms":7400,"ts":"2026-10-05T12:00:00"}]}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"example":{"error":{"code":"invalid_api_key","message":"Invalid API key.","retryable":false},"detail":"Invalid API key."}}}},"429":{"description":"Rate limit or daily quota exceeded"}},"tags":["public"]}},"/api-info":{"get":{"summary":"API contract summary","description":"Machine-readable summary of plans, daily limits, rate limits, error codes and supported shortener domains. No authentication.","operationId":"api_info_api_info_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"tags":["public"],"security":[]}},"/health":{"get":{"summary":"Liveness probe","description":"Public liveness check. No authentication.","operationId":"health_check_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"ok","uptime_s":3600}}}}},"tags":["public"],"security":[]}}},"components":{"schemas":{"BatchLinkRequest":{"properties":{"urls":{"items":{"type":"string"},"type":"array","title":"Urls","description":"1–50 distinct short links, each starting with https://.","maxItems":50,"minItems":1,"example":["https://ouo.io/abc123","https://cuty.io/xyz789"]}},"type":"object","required":["urls"],"title":"BatchLinkRequest"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"LinkRequest":{"properties":{"url":{"type":"string","title":"Url","description":"Short link to resolve (must start with https://).","example":"https://ouo.io/abc123"}},"type":"object","required":["url"],"title":"LinkRequest"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}},"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key"}}},"security":[{"ApiKeyAuth":[]}],"servers":[{"url":"https://api.kisalinkatla.com"}]}