AdScaled Converter API
Convert images, data and text files over HTTP with an API key.
Converts images (JPG, PNG, WebP, GIF, AVIF, BMP, SVG), data (CSV, JSON, YAML, XML) and text (Markdown, plain text, Base64) to another format. Send the raw file as the request body, receive the converted file. Files are processed in memory and never stored.
Authentication. POST /api/v1/convert and GET /api/v1/usage need an API key
(Authorization: Bearer asc_…). Keys are created on the account page of a verified Free or Pro
account (https://converter.adscaled.media/ucet#api-klice); a key can be limited to scopes
(convert, usage), IP addresses and an expiry. GET /api/v1/formats is public.
Quota and credits. Every plan has a monthly number of API conversions
(Free 50, Pro 5,000, Business by agreement). When the monthly quota runs out,
each further conversion uses one prepaid credit (packs of 1,000 or 10,000
conversions on the pricing page; referral bonuses are credits too). Credits never
expire. When both the quota and the credits are used up, the API answers
402 quota_exceeded. A failed conversion is not counted.
Rate limits. Responses carry the IETF RateLimit-Policy and RateLimit headers
(draft-ietf-httpapi-ratelimit-headers). Policies: flood = 300 requests per 60 s per client IP
for every /api path; api = requests per 60 s per account (Free 10, Pro 60, all keys of the
account together); api-key-failures = 20 invalid keys per 600 s per IP. A 429 response always
has Retry-After in seconds: wait that long before retrying.
Errors are always JSON { "error": { "code", "message" } }.
Versioning and deprecation. The version is part of the URL (/api/v1/). Within v1 only
backward-compatible changes are made (new optional parameters, new response fields, new formats);
ignore fields you do not know. A breaking change ships as a new version (/api/v2/) while v1 keeps
working. Before an operation or a version is removed it is marked deprecated: true here and its
responses carry Deprecation (RFC 9745) and Sunset (RFC 8594) headers plus
Link: <https://converter.adscaled.media/api/docs>; rel="deprecation", and it stays available for at
least 90 days after the deprecation is announced. info.version is the version of this description (semantic versioning). No operation
is deprecated at the moment.
- OpenAPI 3.1 specification: https://converter.adscaled.media/api/openapi.json
- API catalog (RFC 9727): https://converter.adscaled.media/.well-known/api-catalog
- Base URL: https://converter.adscaled.media
- Developer guide with code samples: https://converter.adscaled.media/en/developers
- Site guide for AI agents: https://converter.adscaled.media/llms.txt
Endpoints
POST /api/v1/convert (convertFile)
Convert one file. Send the raw file bytes as the body and the target format in to; the response body is the
converted file. The input type is detected from the bytes (not only the extension); video,
audio and unsupported or mismatched files are refused. Image targets accept the transform
parameters below (resize, crop, rotate, background, watermark, target size). Each successful
conversion uses one conversion from the monthly quota, then one credit. Needs the convert scope.
Authentication: API key (Authorization: Bearer asc_…).
| Parameter | In | Type | Description |
|---|---|---|---|
to (required) |
query | string, one of png, jpg, webp, bmp, ico, favicon-pack, pdf, json, csv, tsv, yaml, xml, xlsx, json-pretty, json-min, html, base64, unbase64 |
|
quality |
query | integer, min 1, max 100, default 85 |
|
width |
query | integer, min 1, max 10000 | |
height |
query | integer, min 1, max 10000 | |
scale |
query | integer, min 1, max 200 | Percent; ignored when width/height is set |
fit |
query | string, one of inside, contain, cover, exact, default inside |
How the image fits width × height: inside = keep ratio within the box; contain = whole image on a background; cover = fill and crop; exact = stretch. Other than inside needs both width and height. |
aspect |
query | string, one of 1:1, 4:5, 4:3, 3:2, 16:9, 9:16 |
Crop to an aspect ratio (around the focus point) |
focusX |
query | number, min 0, max 1, default 0.5 |
Horizontal focus point for cover/aspect crops (0 = left |
focusY |
query | number, min 0, max 1, default 0.5 |
Vertical focus point for cover/aspect crops (0 = top |
background |
query | string | Background colour (hex, # optional) for contain, padding, rounded corners and formats without transparency |
padding |
query | integer, min 0, max 1000 | Padding around the image in px |
radius |
query | integer, min 1, max 50 | Rounded corners in % of the shorter side |
grayscale |
query | boolean | |
brightness |
query | integer, min -100, max 100 | |
contrast |
query | integer, min -100, max 100 | |
rotate |
query | integer, one of 0, 90, 180, 270 |
|
flipH |
query | boolean | |
flipV |
query | boolean | |
targetKb |
query | integer, min 1 | Target size for JPG/WebP |
watermark |
query | string, max length 80 | |
watermarkPosition |
query | string, one of tl, tr, bl, br, c, default br |
|
watermarkOpacity |
query | number, min 0.1, max 1, default 0.5 |
|
watermarkSize |
query | number, min 1, max 20, default 5 |
|
filename |
query | string, max length 200 | Original file name (alternative to the X-Filename header) |
X-Filename |
header | string, max length 200 | Original file name (used for the output name and text formats) |
Request body: application/octet-stream. The file to convert (raw bytes, at most maxFileBytes of the plan)
Example:
curl -X POST 'https://converter.adscaled.media/api/v1/convert?to=webp&width=1200' \
-H 'Authorization: Bearer asc_…' \
-H 'X-Filename: photo.jpg' \
--data-binary @photo.jpg -o photo.webp
Responses:
200: Converted file (to=favicon-packreturns a ZIP with favicon.ico, PNG icons, site.webmanifest and an HTML snippet)400: invalid_parameter: unknowntoor an invalid parameter; unsupportedTarget: the file cannot be converted toto401: invalid_api_key, key_expired: missing, unknown, revoked or expired API key402: quota_exceeded: the monthly quota and all prepaid credits are used up. Buy a credit pack or upgrade the plan.403: scope_denied: the key does not allow this endpoint; ip_denied: the request comes from an IP address the key does not allow; plan_required: the plan has no API access413: fileTooBig, textTooBig, tooManyPixels: the file or image exceeds the plan limit415: video, audio, unsupported, mismatch, binary: the file type is not accepted422: empty, unreadableSize, decode, parse: the file is empty or broken429: rate_limited: too many requests (flood limit, per-account limit or invalid keys). WaitRetry-Afterseconds.503: busy: the conversion queue is full; retry afterRetry-Afterseconds504: timeout: the conversion took too long and was stopped
GET /api/v1/usage (getUsage)
Usage this month and plan limits. Returns the plan, the monthly quota, what is left of it, prepaid credits and the file limits of the account that owns the key. Needs the usage scope (403 scope_denied otherwise). Takes no parameters.
Authentication: API key (Authorization: Bearer asc_…).
Example:
curl -H 'Authorization: Bearer asc_…' https://converter.adscaled.media/api/v1/usage
Responses:
200: Usage of the key owner401: invalid_api_key, key_expired403: scope_denied, ip_denied, plan_required429: rate_limited: too many requests (flood limit, per-account limit or invalid keys). WaitRetry-Afterseconds.
GET /api/v1/formats (listFormats)
Supported conversions. Public list of every target format, which targets each input kind can be converted to, which targets accept image transforms and the names of the transform parameters. Optional from limits conversions to one input kind. No key needed.
Authentication: none.
| Parameter | In | Type | Description |
|---|---|---|---|
from |
query | string, one of jpg, png, webp, bmp, gif, avif, svg, csv, json, yaml, xml, md, txt |
Only list the targets of this input kind |
Example:
curl https://converter.adscaled.media/api/v1/formats
Responses:
200: Conversion matrix400: invalid_parameter: unknownfrom429: rate_limited: too many requests (flood limit, per-account limit or invalid keys). WaitRetry-Afterseconds.
GET /api/health (getHealth)
Service status. Liveness check of the service (also the deploy healthcheck). ok is true when the server runs; queue shows running and waiting API conversions. No key needed. Takes no parameters.
Authentication: none.
Example:
curl https://converter.adscaled.media/api/health
Responses:
200: The service is running429: rate_limited: too many requests (flood limit, per-account limit or invalid keys). WaitRetry-Afterseconds.
Versioning and deprecation
The API is versioned in the URL path: every public operation lives under /api/v1/ (only the status check /api/health is unversioned).
- Compatible changes stay in v1: new optional parameters, new response fields, new formats and new error codes. Clients must ignore fields they do not know.
- Breaking changes get a new version: removing or renaming a field, parameter or endpoint, or changing a type or meaning ships as
/api/v2/. The previous version keeps working next to it. - Deprecation: before an operation or a version is removed, it is marked
deprecated: truein the OpenAPI description and its responses carry aDeprecationheader (RFC 9745), aSunsetheader (RFC 8594) with the date after which it stops working, andLink: <https://converter.adscaled.media/api/docs>; rel="deprecation". - Notice: a deprecated operation stays available for at least 90 days after the deprecation is announced (the
Sunsetdate is at least 90 days after theDeprecationdate). The change is also announced on this page. - Description version:
info.versionin the OpenAPI description follows semantic versioning (minor = new compatible features, major = a new API version).
No operation is deprecated at the moment.
Rate limits
Every /api response carries RateLimit-Policy and RateLimit headers (IETF draft-ietf-httpapi-ratelimit-headers), one list entry per policy:
flood: 300 requests per 60 s per client IP, shared by all/apipaths.api: requests per 60 s per account for the API v1 endpoints with a key (Free 10, Pro 60; all keys of one account count together).api-key-failures: 20 requests with an invalid key per 600 s per IP; then every key request from that IP gets429until the window frees up.
Example: RateLimit-Policy: "flood";q=300;w=60, "api";q=10;w=60 and RateLimit: "flood";r=297;t=58, "api";r=9;t=60 (q quota, w window in seconds, r remaining, t seconds until reset).
A 429 rate_limited response always has Retry-After (seconds). Wait that long; do not retry in a loop. A full conversion queue answers 503 busy with Retry-After: 5.
Errors
Errors are JSON { "error": { "code": "…", "message": "…" } }; branch on code, show message to a person.