{
  "openapi": "3.1.0",
  "info": {
    "title": "AdScaled BG Remover API",
    "version": "1.0.0",
    "description": "Server-side versions of the AdScaled BG Remover tools: background removal, metadata\nstripping, PDF clean-up and text clean-up. The algorithms are the same classic\n(non-AI) algorithms the website runs in the browser.\n\nSend the raw file as the request body and receive the processed file. Files are\nprocessed in memory and never stored; the output never carries metadata.\n\n**Plans.** The API is part of **Pro**. Every call that succeeds counts as one\n**operation**. Pro includes 2,000 operations per calendar month (UTC). After that,\neach operation uses one prepaid **credit** (packs of 1,000 or 10,000 operations on\nthe pricing page; referral bonuses are credits too). Credits never expire. When both\nthe monthly quota and the credits are used up, the API answers `402 quota_exceeded`.\nFailed calls are not counted.\n\n**Limits (Pro).** File 15 MB, image 16 megapixels, text 2 MB, 30 requests per minute.\nJobs run one after another on the server; a job that takes longer than 45 seconds is\nstopped (`504 timeout`), a full queue answers `503 busy` with `Retry-After`.\n\n**Rate limit headers.** Responses carry the IETF `RateLimit-Policy` and `RateLimit` headers\n(draft-ietf-httpapi-ratelimit-headers): `flood` = 300 requests per 60 s per client IP for every `/api` path,\n`api` = 30 requests per 60 s per account for authenticated calls, `api-bad-key` = 20 invalid keys per 600 s per IP.\nA `429` adds `Retry-After` in seconds; wait that long instead of retrying in a loop.\n\n**Versioning and deprecation.** The version is part of the path (`/api/v1/`). Within v1 changes are only additive: new operations, new optional parameters, new response fields or headers; `info.version` follows semantic versioning. A breaking change gets a new path version (`/api/v2/`) and v1 keeps working alongside it. Before an operation or a version is retired, it is marked `deprecated: true` in this document, the notice is published on the developer page, and its responses carry a `Deprecation` header (RFC 9745), a `Sunset` header with the shutdown date (RFC 8594) and a `Link` header with `rel=\"deprecation\"` pointing to the notice. A deprecated operation stays available for at least 90 days after the deprecation is announced. No operation is deprecated at the moment.\n",
    "summary": "Server-side background removal, metadata stripping, PDF and text clean-up without AI (Pro plan, API key).",
    "contact": {
      "name": "AdScaled",
      "email": "contact@adscaled.media",
      "url": "https://www.adscaled.media/en/contact"
    },
    "termsOfService": "https://bgremover.adscaled.media/terms"
  },
  "security": [
    {
      "apiKey": []
    }
  ],
  "tags": [
    {
      "name": "Background"
    },
    {
      "name": "Metadata"
    },
    {
      "name": "PDF"
    },
    {
      "name": "Text"
    },
    {
      "name": "Account"
    }
  ],
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key from the account page (asc_…). Keys can be limited to scopes (`convert` = processing endpoints, `usage` = GET /api/v1/usage), IP addresses and a lifetime."
      }
    },
    "schemas": {
      "Error": {
        "title": "Error",
        "description": "The body of every error response (every 4xx and 5xx status). `code` is stable and machine-readable; `message` is for people and may change.",
        "type": "object",
        "required": [
          "error"
        ],
        "additionalProperties": false,
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "additionalProperties": false,
            "properties": {
              "code": {
                "type": "string",
                "description": "Stable error code, e.g. `invalid_api_key`, `quota_exceeded`, `rate_limited`, `invalid_parameter`, `fileTooBig`, `unsupported`, `busy`, `timeout`, `server_error`.",
                "example": "quota_exceeded"
              },
              "message": {
                "type": "string",
                "description": "Human-readable explanation in English."
              }
            }
          }
        },
        "example": {
          "error": {
            "code": "quota_exceeded",
            "message": "Monthly operation quota and credits exhausted. Buy credits or wait for the next month."
          }
        }
      },
      "MetadataField": {
        "type": "object",
        "required": [
          "group",
          "field",
          "value"
        ],
        "properties": {
          "group": {
            "type": "string",
            "example": "EXIF"
          },
          "field": {
            "type": "string",
            "example": "GPSLatitude"
          },
          "value": {
            "type": "string",
            "example": "50.0875"
          },
          "sensitive": {
            "type": "boolean",
            "description": "Location, serial numbers, author names and similar personal data"
          },
          "info": {
            "type": "boolean",
            "description": "A fact about the file, not removable metadata (PDF page count, encryption, attachments present, Office page/word counts)"
          }
        }
      },
      "Usage": {
        "type": "object",
        "properties": {
          "plan": {
            "type": "string",
            "enum": [
              "pro",
              "free"
            ]
          },
          "month": {
            "type": "string",
            "example": "2026-09"
          },
          "used": {
            "type": "integer",
            "description": "Operations used this month from the monthly quota"
          },
          "limit": {
            "type": "integer",
            "description": "Monthly operations included in the plan",
            "example": 2000
          },
          "remaining": {
            "type": "integer",
            "description": "Operations left this month (without credits)"
          },
          "credits": {
            "type": "integer",
            "description": "Prepaid credits left; used after the monthly quota runs out"
          },
          "maxFileBytes": {
            "type": "integer",
            "example": 15728640
          },
          "maxImagePixels": {
            "type": "integer",
            "example": 16000000
          },
          "maxTextBytes": {
            "type": "integer",
            "example": 2097152
          },
          "perMinute": {
            "type": "integer",
            "example": 30
          }
        }
      },
      "ToolList": {
        "title": "ToolList",
        "description": "Machine-readable list of the API operations and the Pro limits.",
        "type": "object",
        "properties": {
          "operations": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "example": "remove-background"
                },
                "method": {
                  "type": "string",
                  "example": "POST"
                },
                "path": {
                  "type": "string",
                  "example": "/api/v1/remove-background"
                },
                "inputs": {
                  "type": "array",
                  "items": {
                    "type": "string",
                    "enum": [
                      "image",
                      "pdf",
                      "office",
                      "text"
                    ]
                  }
                },
                "output": {
                  "type": "string"
                },
                "parameters": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "type": {
                        "type": "string"
                      },
                      "values": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      },
                      "min": {
                        "type": "number"
                      },
                      "max": {
                        "type": "number"
                      },
                      "default": {},
                      "description": {
                        "type": "string"
                      }
                    }
                  }
                },
                "tools": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "Website tools this endpoint covers"
                }
              }
            }
          },
          "limits": {
            "type": "object",
            "description": "Limits of the Pro plan API",
            "properties": {
              "plan": {
                "type": "string",
                "example": "pro"
              },
              "monthlyOperations": {
                "type": "integer",
                "example": 2000
              },
              "maxFileBytes": {
                "type": "integer",
                "example": 15728640
              },
              "maxImagePixels": {
                "type": "integer",
                "example": 16000000
              },
              "maxTextBytes": {
                "type": "integer",
                "example": 2097152
              },
              "perMinute": {
                "type": "integer",
                "example": 30
              }
            }
          },
          "auth": {
            "type": "string"
          },
          "docs": {
            "type": "string"
          }
        }
      },
      "MetadataReport": {
        "title": "MetadataReport",
        "description": "Metadata fields found in the file.",
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "example": "jpeg"
          },
          "count": {
            "type": "integer",
            "description": "Number of metadata fields (without info fields)"
          },
          "sensitive": {
            "type": "integer",
            "description": "Number of sensitive fields"
          },
          "fields": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MetadataField"
            }
          }
        }
      }
    },
    "parameters": {
      "Filename": {
        "name": "X-Filename",
        "in": "header",
        "required": false,
        "schema": {
          "type": "string",
          "maxLength": 200
        },
        "description": "Original file name (used for the output name in Content-Disposition). `?filename=` works too."
      }
    },
    "headers": {
      "X-Usage-Used": {
        "schema": {
          "type": "integer"
        },
        "description": "Operations used this month (from the monthly quota)"
      },
      "X-Usage-Limit": {
        "schema": {
          "type": "integer"
        },
        "description": "Monthly operations of the plan"
      },
      "X-Usage-Remaining": {
        "schema": {
          "type": "integer"
        },
        "description": "Operations left this month (without credits)"
      },
      "X-Credits-Remaining": {
        "schema": {
          "type": "integer"
        },
        "description": "Prepaid credits left"
      },
      "X-RateLimit-Limit": {
        "schema": {
          "type": "integer"
        },
        "description": "Requests allowed per minute"
      },
      "X-RateLimit-Remaining": {
        "schema": {
          "type": "integer"
        },
        "description": "Requests left in the current minute"
      },
      "RateLimit-Policy": {
        "schema": {
          "type": "string"
        },
        "description": "Quota policies that apply to this request (draft-ietf-httpapi-ratelimit-headers), e.g. `\"flood\";q=300;w=60, \"api\";q=30;w=60`"
      },
      "RateLimit": {
        "schema": {
          "type": "string"
        },
        "description": "Remaining quota per policy, e.g. `\"flood\";r=297;t=41, \"api\";r=29;t=60` (r = requests left, t = seconds until the window resets)"
      },
      "Retry-After": {
        "schema": {
          "type": "integer",
          "minimum": 1
        },
        "description": "Seconds to wait before the next request"
      },
      "Content-Disposition": {
        "schema": {
          "type": "string"
        },
        "description": "`attachment; filename=\"<name>\"; filename*=UTF-8''<name>`: suggested name of the result file"
      }
    },
    "responses": {
      "BadRequest": {
        "description": "`invalid_parameter`: a query parameter is missing or out of range, or does not fit the file (e.g. a page that does not exist); the message says which",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "`invalid_api_key` (missing, wrong or revoked key) or `key_expired`",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "QuotaExceeded": {
        "description": "`quota_exceeded`: monthly quota and credits are both used up",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Forbidden": {
        "description": "`plan_required` (the plan has no API), `scope_denied` (key without the scope), `ip_denied` (address not in the key's allowlist)",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "TooLarge": {
        "description": "`fileTooBig`, `textTooBig`, `tooManyPixels`: over the plan limit (checked from Content-Length and the image header before decoding)",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unsupported": {
        "description": "`unsupported`, `svg`, `video`, `audio`, `mismatch` (extension does not match the content), `binary`",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unprocessable": {
        "description": "`empty`, `unreadableSize`, `decode`, `corrupt`, `encrypted` (password-protected PDF/Office), `failed` (e.g. every page of the PDF is blank)",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "RateLimited": {
        "description": "`rate_limited`: too many requests per minute (per account, or 300 per IP for all of /api), or too many invalid keys from one address. Wait for Retry-After seconds.",
        "headers": {
          "Retry-After": {
            "$ref": "#/components/headers/Retry-After"
          },
          "RateLimit-Policy": {
            "$ref": "#/components/headers/RateLimit-Policy"
          },
          "RateLimit": {
            "$ref": "#/components/headers/RateLimit"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Busy": {
        "description": "`busy`: the processing queue is full. Retry after the number of seconds in Retry-After.",
        "headers": {
          "Retry-After": {
            "$ref": "#/components/headers/Retry-After"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Timeout": {
        "description": "`timeout`: the job took longer than 45 seconds and was stopped. Not counted.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "ServerError": {
        "description": "`server_error`: unexpected server error. Not counted; safe to retry later.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "UnexpectedError": {
        "description": "Any other error status (for example `404 not_found` for a mistyped path); always the same JSON error body.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "requestBodies": {
      "Image": {
        "required": true,
        "description": "Raw image bytes: JPEG, PNG, WebP, AVIF or GIF (first frame). SVG and BMP are refused (415).",
        "content": {
          "image/*": {
            "schema": {
              "type": "string",
              "format": "binary"
            }
          },
          "application/octet-stream": {
            "schema": {
              "type": "string",
              "format": "binary"
            }
          }
        }
      },
      "Pdf": {
        "required": true,
        "description": "Raw PDF bytes (not password-protected).",
        "content": {
          "application/pdf": {
            "schema": {
              "type": "string",
              "format": "binary"
            }
          }
        }
      },
      "AnyFile": {
        "required": true,
        "description": "JPEG, PNG or WebP image, PDF, or Office / OpenDocument file (DOCX, XLSX, PPTX, ODT, ODS, ODP). Password-protected files are refused (`422 encrypted`).",
        "content": {
          "application/octet-stream": {
            "schema": {
              "type": "string",
              "format": "binary"
            }
          }
        }
      }
    }
  },
  "paths": {
    "/api/v1/tools": {
      "get": {
        "operationId": "listApiOperations",
        "tags": [
          "Account"
        ],
        "summary": "List of operations, accepted inputs, parameters and limits",
        "security": [],
        "responses": {
          "200": {
            "description": "Machine-readable description of every endpoint (no API key needed)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolList"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "default": {
            "$ref": "#/components/responses/UnexpectedError"
          }
        },
        "description": "Public, no API key needed. Lists every endpoint with its accepted inputs, parameters (names, types, allowed values, defaults) and the Pro limits. Not counted as an operation."
      }
    },
    "/api/v1/usage": {
      "get": {
        "operationId": "getApiUsage",
        "tags": [
          "Account"
        ],
        "summary": "Quota, credits and limits of the key's account",
        "description": "Needs the `usage` scope. Does not count as an operation.",
        "responses": {
          "200": {
            "description": "Usage",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Usage"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "default": {
            "$ref": "#/components/responses/UnexpectedError"
          }
        }
      }
    },
    "/api/v1/remove-background": {
      "post": {
        "operationId": "removeBackground",
        "tags": [
          "Background"
        ],
        "summary": "Remove (or replace) the background of an image",
        "description": "Classic segmentation without AI. Works best on solid or contrasting backgrounds,\nproduct photos, logos and green/blue screens. Hair or fur on a busy background and\ncomplex scenes are not separated well; use `mode=rect` with a tight rectangle.\nThe image is decoded with EXIF orientation applied; the output carries no metadata.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/Filename"
          },
          {
            "name": "mode",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "auto",
                "solid",
                "chroma",
                "rect"
              ],
              "default": "auto"
            },
            "description": "auto = background touching the border (photos, products); solid = one flat colour (`color`, detected when missing); chroma = green/blue screen (`key` or custom `color`); rect = GrabCut inside `rect`"
          },
          {
            "name": "color",
            "in": "query",
            "schema": {
              "type": "string",
              "pattern": "^#?[0-9a-fA-F]{6}$"
            },
            "description": "solid: background colour; chroma: custom key colour (#rrggbb, URL-encode # as %23)"
          },
          {
            "name": "key",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "green",
                "blue"
              ],
              "default": "green"
            },
            "description": "chroma screen colour"
          },
          {
            "name": "tolerance",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 100
            },
            "description": "How different from the background a pixel may be and still be removed. Defaults: auto 18, solid 12, chroma 40."
          },
          {
            "name": "softness",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 100,
              "default": 20
            },
            "description": "chroma only: width of the soft transition"
          },
          {
            "name": "contiguous",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": true
            },
            "description": "solid only: remove only background connected to the border (false = the colour everywhere)"
          },
          {
            "name": "rect",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "40,30,600,800"
            },
            "description": "rect mode (required): x,y,width,height of the object in pixels of the oriented image"
          },
          {
            "name": "grow",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": -50,
              "maximum": 50,
              "default": 0
            },
            "description": "Grow (+) or shrink (-) the kept area in pixels"
          },
          {
            "name": "feather",
            "in": "query",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 50,
              "default": 0
            },
            "description": "Soften the edge (px)"
          },
          {
            "name": "fillHoles",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "Fill background holes fully enclosed by the object"
          },
          {
            "name": "removeIslands",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 1000000,
              "default": 0
            },
            "description": "Drop kept specks smaller than this many pixels"
          },
          {
            "name": "bg",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "transparent",
              "example": "#ffffff"
            },
            "description": "transparent, a colour #rrggbb, or blur (blurred original background)"
          },
          {
            "name": "blur",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 12
            },
            "description": "Blur radius for bg=blur"
          },
          {
            "name": "decontaminate",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": true
            },
            "description": "Remove background colour bleeding into semi-transparent edges"
          },
          {
            "name": "trim",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "Crop to the object (not with bg=blur)"
          },
          {
            "name": "padding",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 1000,
              "default": 0
            },
            "description": "Margin around the object after trim (px)"
          },
          {
            "name": "format",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "png",
                "webp",
                "jpg"
              ],
              "default": "png"
            },
            "description": "jpg needs an opaque background (bg=#rrggbb or blur)"
          },
          {
            "name": "quality",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 90
            },
            "description": "webp/jpg quality"
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/Image"
        },
        "responses": {
          "200": {
            "description": "The processed image (`<name>-no-bg.png` etc.)",
            "headers": {
              "Content-Disposition": {
                "$ref": "#/components/headers/Content-Disposition"
              },
              "X-Usage-Used": {
                "$ref": "#/components/headers/X-Usage-Used"
              },
              "X-Usage-Limit": {
                "$ref": "#/components/headers/X-Usage-Limit"
              },
              "X-Usage-Remaining": {
                "$ref": "#/components/headers/X-Usage-Remaining"
              },
              "X-Credits-Remaining": {
                "$ref": "#/components/headers/X-Credits-Remaining"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              }
            },
            "content": {
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary",
                  "contentMediaType": "image/png",
                  "description": "Raw image/png bytes"
                }
              },
              "image/webp": {
                "schema": {
                  "type": "string",
                  "format": "binary",
                  "contentMediaType": "image/webp",
                  "description": "Raw image/webp bytes"
                }
              },
              "image/jpeg": {
                "schema": {
                  "type": "string",
                  "format": "binary",
                  "contentMediaType": "image/jpeg",
                  "description": "Raw image/jpeg bytes"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/QuotaExceeded"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "415": {
            "$ref": "#/components/responses/Unsupported"
          },
          "422": {
            "$ref": "#/components/responses/Unprocessable"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/Busy"
          },
          "504": {
            "$ref": "#/components/responses/Timeout"
          },
          "default": {
            "$ref": "#/components/responses/UnexpectedError"
          }
        }
      }
    },
    "/api/v1/strip-metadata": {
      "post": {
        "operationId": "stripMetadata",
        "tags": [
          "Metadata"
        ],
        "summary": "Remove metadata (EXIF, GPS, XMP, IPTC, document properties) from an image, PDF or Office file",
        "description": "JPEG, PNG and WebP are cleaned without re-encoding (pixels untouched; the orientation\nflag and colour profile are kept by default). PDFs lose the document information\ndictionary, XMP, page thumbnails and the file ID; Office (DOCX, XLSX, PPTX) and\nOpenDocument files lose core/app/custom properties (author, company, last editor…),\nthumbnails and comment author names. GIF, BMP and AVIF are refused (`415 unsupported`).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/Filename"
          },
          {
            "name": "keepOrientation",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": true
            },
            "description": "Keep the EXIF orientation flag so photos stay upright"
          },
          {
            "name": "keepColorProfile",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": true
            },
            "description": "Keep the ICC colour profile"
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/AnyFile"
        },
        "responses": {
          "200": {
            "description": "The cleaned file in the same format as the input (`Content-Type` = the detected input type)",
            "headers": {
              "Content-Disposition": {
                "$ref": "#/components/headers/Content-Disposition"
              },
              "X-Usage-Used": {
                "$ref": "#/components/headers/X-Usage-Used"
              },
              "X-Credits-Remaining": {
                "$ref": "#/components/headers/X-Credits-Remaining"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              }
            },
            "content": {
              "image/jpeg": {
                "schema": {
                  "type": "string",
                  "format": "binary",
                  "contentMediaType": "image/jpeg",
                  "description": "Raw image/jpeg bytes"
                }
              },
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary",
                  "contentMediaType": "image/png",
                  "description": "Raw image/png bytes"
                }
              },
              "image/webp": {
                "schema": {
                  "type": "string",
                  "format": "binary",
                  "contentMediaType": "image/webp",
                  "description": "Raw image/webp bytes"
                }
              },
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary",
                  "contentMediaType": "application/pdf",
                  "description": "Raw application/pdf bytes"
                }
              },
              "application/vnd.openxmlformats-officedocument.wordprocessingml.document": {
                "schema": {
                  "type": "string",
                  "format": "binary",
                  "contentMediaType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
                  "description": "Raw application/vnd.openxmlformats-officedocument.wordprocessingml.document bytes"
                }
              },
              "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": {
                "schema": {
                  "type": "string",
                  "format": "binary",
                  "contentMediaType": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
                  "description": "Raw application/vnd.openxmlformats-officedocument.spreadsheetml.sheet bytes"
                }
              },
              "application/vnd.openxmlformats-officedocument.presentationml.presentation": {
                "schema": {
                  "type": "string",
                  "format": "binary",
                  "contentMediaType": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
                  "description": "Raw application/vnd.openxmlformats-officedocument.presentationml.presentation bytes"
                }
              },
              "application/vnd.oasis.opendocument.text": {
                "schema": {
                  "type": "string",
                  "format": "binary",
                  "contentMediaType": "application/vnd.oasis.opendocument.text",
                  "description": "Raw application/vnd.oasis.opendocument.text bytes"
                }
              },
              "application/vnd.oasis.opendocument.spreadsheet": {
                "schema": {
                  "type": "string",
                  "format": "binary",
                  "contentMediaType": "application/vnd.oasis.opendocument.spreadsheet",
                  "description": "Raw application/vnd.oasis.opendocument.spreadsheet bytes"
                }
              },
              "application/vnd.oasis.opendocument.presentation": {
                "schema": {
                  "type": "string",
                  "format": "binary",
                  "contentMediaType": "application/vnd.oasis.opendocument.presentation",
                  "description": "Raw application/vnd.oasis.opendocument.presentation bytes"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/QuotaExceeded"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "415": {
            "$ref": "#/components/responses/Unsupported"
          },
          "422": {
            "$ref": "#/components/responses/Unprocessable"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/Busy"
          },
          "504": {
            "$ref": "#/components/responses/Timeout"
          },
          "default": {
            "$ref": "#/components/responses/UnexpectedError"
          }
        }
      }
    },
    "/api/v1/inspect-metadata": {
      "post": {
        "operationId": "inspectMetadata",
        "tags": [
          "Metadata"
        ],
        "summary": "List the metadata found in an image, PDF or Office file",
        "parameters": [
          {
            "$ref": "#/components/parameters/Filename"
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/AnyFile"
        },
        "responses": {
          "200": {
            "description": "Found fields (values shortened to 500 characters)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MetadataReport"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/QuotaExceeded"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "415": {
            "$ref": "#/components/responses/Unsupported"
          },
          "422": {
            "$ref": "#/components/responses/Unprocessable"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/Busy"
          },
          "504": {
            "$ref": "#/components/responses/Timeout"
          },
          "default": {
            "$ref": "#/components/responses/UnexpectedError"
          }
        },
        "description": "Read-only: lists the metadata fields (EXIF, GPS, XMP, IPTC, PDF info, Office properties) and flags sensitive ones. Counts as one operation."
      }
    },
    "/api/v1/pdf/remove-pages": {
      "post": {
        "operationId": "removePdfPages",
        "tags": [
          "PDF"
        ],
        "summary": "Delete pages from a PDF",
        "parameters": [
          {
            "$ref": "#/components/parameters/Filename"
          },
          {
            "name": "pages",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1,3-5"
            },
            "description": "1-based page numbers and ranges to delete; at least one page must remain"
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/Pdf"
        },
        "responses": {
          "200": {
            "description": "The PDF without the pages",
            "headers": {
              "Content-Disposition": {
                "$ref": "#/components/headers/Content-Disposition"
              },
              "X-Page-Count": {
                "schema": {
                  "type": "integer"
                },
                "description": "Pages left in the output"
              },
              "X-Removed-Count": {
                "schema": {
                  "type": "integer"
                },
                "description": "Pages deleted"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              }
            },
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary",
                  "contentMediaType": "application/pdf",
                  "description": "Raw application/pdf bytes"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/QuotaExceeded"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "415": {
            "$ref": "#/components/responses/Unsupported"
          },
          "422": {
            "$ref": "#/components/responses/Unprocessable"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/Busy"
          },
          "504": {
            "$ref": "#/components/responses/Timeout"
          },
          "default": {
            "$ref": "#/components/responses/UnexpectedError"
          }
        },
        "description": "Deletes the given 1-based pages and ranges; at least one page must remain."
      }
    },
    "/api/v1/pdf/remove-blank-pages": {
      "post": {
        "operationId": "removeBlankPdfPages",
        "tags": [
          "PDF"
        ],
        "summary": "Delete blank pages from a PDF",
        "description": "A page is blank when it draws nothing visible (no text, images or filled shapes; space-only text counts as blank). Scanned pages count as blank when they carry almost no ink (the `normal` level, the browser default). At least one page must remain.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Filename"
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/Pdf"
        },
        "responses": {
          "200": {
            "description": "The PDF without blank pages",
            "headers": {
              "Content-Disposition": {
                "$ref": "#/components/headers/Content-Disposition"
              },
              "X-Removed-Pages": {
                "schema": {
                  "type": "string",
                  "example": "2,7"
                },
                "description": "1-based numbers of the deleted pages (empty when none)"
              },
              "X-Removed-Count": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Page-Count": {
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              }
            },
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary",
                  "contentMediaType": "application/pdf",
                  "description": "Raw application/pdf bytes"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/QuotaExceeded"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "415": {
            "$ref": "#/components/responses/Unsupported"
          },
          "422": {
            "$ref": "#/components/responses/Unprocessable"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/Busy"
          },
          "504": {
            "$ref": "#/components/responses/Timeout"
          },
          "default": {
            "$ref": "#/components/responses/UnexpectedError"
          }
        }
      }
    },
    "/api/v1/pdf/clean": {
      "post": {
        "operationId": "cleanPdf",
        "tags": [
          "PDF"
        ],
        "summary": "Remove annotations, links, forms, attachments, JavaScript, bookmarks, metadata or thumbnails from a PDF",
        "parameters": [
          {
            "$ref": "#/components/parameters/Filename"
          },
          {
            "name": "parts",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "annotations,links,forms,attachments,javascript,metadata"
            },
            "description": "Comma list of: annotations, links, forms, attachments, javascript, bookmarks, metadata, thumbnails"
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/Pdf"
        },
        "responses": {
          "200": {
            "description": "The cleaned PDF",
            "headers": {
              "Content-Disposition": {
                "$ref": "#/components/headers/Content-Disposition"
              },
              "X-Page-Count": {
                "schema": {
                  "type": "integer"
                }
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              }
            },
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary",
                  "contentMediaType": "application/pdf",
                  "description": "Raw application/pdf bytes"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/QuotaExceeded"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "415": {
            "$ref": "#/components/responses/Unsupported"
          },
          "422": {
            "$ref": "#/components/responses/Unprocessable"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/Busy"
          },
          "504": {
            "$ref": "#/components/responses/Timeout"
          },
          "default": {
            "$ref": "#/components/responses/UnexpectedError"
          }
        },
        "description": "Removes the chosen interactive or hidden parts from a PDF; the visible page content stays."
      }
    },
    "/api/v1/text": {
      "post": {
        "operationId": "cleanText",
        "tags": [
          "Text"
        ],
        "summary": "Clean up text (duplicate lines, empty lines, spaces, accents, emojis, HTML tags…)",
        "parameters": [
          {
            "name": "ops",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "duplicate-lines,extra-spaces"
            },
            "description": "Comma list applied in order: duplicate-lines, empty-lines, line-breaks, extra-spaces, leading-trailing-spaces, accents, emojis, html-tags, punctuation, numbers, urls, emails, phones, non-ascii"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "text/plain": {
              "schema": {
                "type": "string"
              },
              "example": "b\na\nb\n"
            }
          },
          "description": "UTF-8 text (a BOM is dropped) or UTF-16 with a BOM."
        },
        "responses": {
          "200": {
            "description": "The cleaned text (UTF-8)",
            "headers": {
              "X-Removed-Count": {
                "schema": {
                  "type": "integer"
                },
                "description": "Items removed by all operations together"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              }
            },
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string",
                  "contentMediaType": "text/plain; charset=utf-8",
                  "description": "UTF-8 text"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/QuotaExceeded"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "415": {
            "$ref": "#/components/responses/Unsupported"
          },
          "422": {
            "$ref": "#/components/responses/Unprocessable"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/Busy"
          },
          "504": {
            "$ref": "#/components/responses/Timeout"
          },
          "default": {
            "$ref": "#/components/responses/UnexpectedError"
          }
        },
        "description": "Applies the text operations in the given order with their default options and returns UTF-8 text."
      }
    }
  },
  "externalDocs": {
    "description": "Developer page with examples",
    "url": "https://bgremover.adscaled.media/developers"
  },
  "servers": [
    {
      "url": "https://bgremover.adscaled.media"
    }
  ]
}