Image DPI 1 API: Pricing, Documentation

by Pixazo

Prepare an image for print. Send image_url with a dpi between 72 and 1200 (300 by default) and the file is re-tagged at its own pixel size, keeping the source format for PNG and JPEG — PNG is re-tagged by copying the metadata chunk, so the pixels are never decoded and never re-compressed. Add a size preset (4x6, 5x7, 8x10, 11x14, 12x18, 18x24, 24x36, a5, a4, a3, a2, letter, tabloid) or width_in / height_in to target a physical size instead, and allow_upsample to permit enlarging. Anything other than the native re-tag comes back as TIFF unless you pass format. An image with too few pixels for the size you asked for is rejected rather than silently stretched.

Get API Key
Image DPI API

Models Version

WELCOME BONUS

Get $5 Free Credit on First Payment

No strings attached — add funds and get $5 bonus instantly

Claim Your $5 →

Image DPI 1.0 API Documentation

https://gateway.pixazo.ai/media-tools/v1/image-dpi

Authentication

All requests require an API key passed via header.

Pricing: Billed at $0.002 per image — a flat rate per call. The DPI you ask for, the print size and the pixel dimensions of the source make no difference to the price.

Retries: this is an asynchronous job on shared encoding capacity, so a request can occasionally come back processing_failed or take much longer than usual. These are transient and succeed on a retry, and a failed job is never charged — the wallet hold is released. If you chain these tools, retry a failed step rather than failing the whole pipeline.

HeaderTypeRequiredDescription
Ocp-Apim-Subscription-KeystringYesYour API subscription key

Image DPI & Print Prep generate request

Request Code

POST https://gateway.pixazo.ai/media-tools/v1/image-dpi
Content-Type: application/json
Cache-Control: no-cache
Ocp-Apim-Subscription-Key: YOUR_API_KEY

{
  "image_url": "https://api-assets.pixazo.ai/media-api-test/sample.png",
  "dpi": 300,
  "size": "8x10",
  "format": "tiff"
}
import requests

url = "https://gateway.pixazo.ai/media-tools/v1/image-dpi"
headers = {
    "Content-Type": "application/json",
    "Cache-Control": "no-cache",
    "Ocp-Apim-Subscription-Key": "YOUR_API_KEY"
}
data = {
  "image_url": "https://api-assets.pixazo.ai/media-api-test/sample.png",
  "dpi": 300,
  "size": "8x10",
  "format": "tiff"
}

response = requests.post(url, json=data, headers=headers)
print(response.json())
const url = "https://gateway.pixazo.ai/media-tools/v1/image-dpi";
const headers = {
  "Content-Type": "application/json",
  "Cache-Control": "no-cache",
  "Ocp-Apim-Subscription-Key": "YOUR_API_KEY"
};
const data = {
  "image_url": "https://api-assets.pixazo.ai/media-api-test/sample.png",
  "dpi": 300,
  "size": "8x10",
  "format": "tiff"
};

fetch(url, {
  method: "POST",
  headers: headers,
  body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => console.log(data));
curl -X POST "https://gateway.pixazo.ai/media-tools/v1/image-dpi" \
  -H "Content-Type: application/json" \
  -H "Cache-Control: no-cache" \
  -H "Ocp-Apim-Subscription-Key: YOUR_API_KEY" \
  --data-raw '{
    "image_url": "https://api-assets.pixazo.ai/media-api-test/sample.png",
    "dpi": 300,
    "size": "8x10",
    "format": "tiff"
  }'

Output

{
  "request_id": "media-image-dpi_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "status": "QUEUED",
  "polling_url": "https://gateway.pixazo.ai/v2/requests/status/media-image-dpi_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}

Webhook (Optional)

Add the X-Webhook-URL header to your generate request to receive a POST callback instead of polling.

X-Webhook-URL: https://your-server.com/webhook/callback

Request Parameters - Image DPI & Print Prep generate request

Parameter Required Type Default Allowed values / range Description
image_urlYesstringHTTP(S) URL to an imagePublicly reachable HTTP(S) URL of the image to re-tag or resample.
dpiNonumber30072 – 1200Dots per inch written into the output. 300 is the usual number for photo printing.
formatNostringtiff (native mode keeps a PNG or JPG source)tiff, tif, png, jpg, jpegOutput format. The backend default is TIFF. The one exception is native mode — no size and no width_in/height_in — where a PNG source comes back a PNG and a JPEG source a JPG. Every other case, including a native-mode WebP, TIFF or HEIC source, produces TIFF unless you pass this parameter.
sizeNostring4x6, 5x7, 8x10, 11x14, 12x18, 18x24, 24x36, a5, a4, a3, a2, letter, tabloidNamed print size. Sending it switches the call from a metadata re-tag to a resample at that exact physical size.
Every named size renders at the default dpi of 300 — the largest, 24x36, is 77.8 MP against an 80 MP output ceiling. That ceiling is what a high dpi runs into: above roughly 304 DPI for 24x36, 430 for 18x24 and 454 for a2, the job comes back FAILED naming the megapixel count.
width_inNonumber0.1 – 100Print width in inches, for a size that is not on the named list. Use together with height_in instead of size.
height_inNonumber0.1 – 100Print height in inches. Use together with width_in.
allow_upsampleNobooleanfalsetrue, falsePermit the resample to invent pixels the source does not have. Off by default, which is why an under-resolution request comes back 422 instead of a soft-looking print.

Native mode — re-tag only. Send just image_url and dpi and the image is re-tagged at its own pixel size, pixels untouched. A PNG source keeps its format through a metadata-only chunk copy that never re-encodes, so it comes back bit-for-bit identical apart from its density header; a JPEG source comes back a JPG. Every other case produces TIFF unless you pass format — a native-mode source that is neither PNG nor JPEG, and every resample-mode request. Pass format to pin the output type either way.

Resample mode. Add a size, or an explicit width_in + height_in, and the image is resampled to that exact physical size at your dpi. The fit is cover-cropped, so the print is filled edge to edge and the overhanging side is trimmed rather than letterboxed. Alpha is flattened onto white, and EXIF — including GPS coordinates — is stripped. A TIFF output keeps its ICC profile; a PNG output does not.

It will not quietly upscale for you. If the source has too few pixels for the print you asked for, the API answers 422 and tells you the numbers — the pixel size it has and the pixel size the job needs — rather than stretching a small file into a soft print. Send allow_upsample: true if you want it to go ahead anyway.

Ceilings. The output area is capped at 24 megapixels, roughly 12×18 in at 300 DPI; a request over that is refused as a 400 before any charge, so probing the limit is free. Source images above 120 megapixels are refused, and the job comes back FAILED with code invalid_input. The single exception is the zero-decode path, which is PNG only: a native-mode re-tag that keeps a PNG at its own pixel size and returns PNG is a metadata chunk copy, so it works at any source size. Anything else — a JPEG, TIFF or WebP source, or a PNG you asked to convert or resample — is handed to ImageMagick, which allocates per source pixel, and is subject to the same 120 MP limit. A second ceiling applies to what the pipeline renders: above 80 megapixels of output the job is refused as well, which in practice you only meet in native mode on a very large non-PNG source.

Example Request

{
  "image_url": "https://api-assets.pixazo.ai/media-api-test/sample.png",
  "dpi": 300,
  "size": "8x10",
  "format": "tiff"
}

Response

{
  "request_id": "media-image-dpi_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "status": "QUEUED",
  "polling_url": "https://gateway.pixazo.ai/v2/requests/status/media-image-dpi_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}

Request Headers

Header Value
Content-Typeapplication/json
Cache-Controlno-cache
Ocp-Apim-Subscription-KeyYOUR_API_KEY

Response Handling

Common status codes.

CodeMeaning
202Accepted — Request queued
Bad Request
401Unauthorized
402Insufficient Balance
403Forbidden
Unprocessable — source has too few pixels for the requested print size
Too Many Requests
500Internal Server Error

Error Responses

Queue system errors and model validation errors.

Queue System Errors

// 402 — Insufficient balance
{
  "error": "Insufficient Balance",
  "message": "Your wallet does not have enough balance."
}
// 400 — Model not found
{
  "error": "Model not found",
  "message": "Model 'media-image-dpi' not found or is disabled"
}
// 400 — a parameter is outside its allowed range.
// Settled at the gateway from your parameters alone, BEFORE any wallet hold,
// so probing the limits costs nothing.
{
  "error": "Invalid request parameters",
  "message": "'dpi' must be <= 1200 (got 5000)",
  "violations": ["'dpi' must be <= 1200 (got 5000)"]
}

Error via Status/Webhook

{
  "request_id": "media-image-dpi_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "status": "ERROR",
  "model_id": "media-image-dpi",
  "error": "Description of the error",
  "output": null
}

Print Verdicts

Three refusals are decided after the image has been fetched and its header read, so they are not submit-time errors: the submit returns 202 as usual and the verdict arrives on the polled status response as a FAILED job. The error string carries the code invalid_input followed by our sentence for that verdict, with the numbers for your image in it.

// GET /v2/requests/status/{request_id}
// Source has too few pixels for the print, and allow_upsample was not set
{
  "request_id": "media-image-dpi_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "status": "FAILED",
  "model_id": "media-image-dpi",
  "error": "invalid_input: The source is 1200x1600 px, which is only 150 DPI at 8x10 in — printing that size at 300 DPI needs 2400x3000 pixels. Upscale the image first, ask for a smaller physical size, or send allow_upsample: true to accept a softer print.",
  "output": null
}
VerdictWhen it firesThe sentence you get
Not enough pixels The source cannot cover the requested physical size at your dpi, and allow_upsample is not true. The source is 1200x1600 px, which is only 150 DPI at 8x10 in — printing that size at 300 DPI needs 2400x3000 pixels. Upscale the image first, ask for a smaller physical size, or send allow_upsample: true to accept a softer print.
Source over 120 MP Any request that has to decode the source. Checked before the output ceiling, so a very large source reports this one. This is the one verdict whose sentence comes straight from the pipeline. Image is 14000x10000 (140 MP); the print pipeline reads up to 120 MP. A PNG can be re-tagged at its own size instead.
Output over 80 MP Reached in native mode on a large non-PNG source, where the output is the source’s own pixel grid. A request that names a size or inches reaches it too — 24x36 at 400 DPI is 138 MP. That size and DPI would render 11000x9000 pixels; this endpoint renders up to 80 MP (24x36 in at 300 DPI). Ask for a smaller physical size or a lower dpi.

The numbers in each sentence are computed for your image, so treat the examples above as shapes rather than fixed strings — match on the invalid_input code, not on the wording.

Retrieving Results

Poll the universal status endpoint to check progress and retrieve results.

Endpoint

GET https://gateway.pixazo.ai/v2/requests/status/{request_id}
Ocp-Apim-Subscription-Key: YOUR_API_KEY

cURL Example

curl -H "Ocp-Apim-Subscription-Key: YOUR_API_KEY" \
  "https://gateway.pixazo.ai/v2/requests/status/media-image-dpi_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

Response (Completed)

{
  "request_id": "media-image-dpi_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "status": "COMPLETED",
  "model_id": "media-image-dpi",
  "error": null,
  "output": {
    "media_url": [
      "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/v1/media-image-dpi_019dxxxx/output.tiff"
    ],
    "media_type": "image/tiff"
  },
  "created_at": "2026-03-31T10:00:00.000Z",
  "updated_at": "2026-03-31T10:00:15.000Z",
  "completed_at": "2026-03-31T10:00:15.000Z"
}

Response Fields

FieldTypeDescription
request_idstringUnique request identifier
statusstringQUEUED, PROCESSING, COMPLETED, FAILED, or ERROR
model_idstringModel that processed the request
errorstring|nullError message if failed
output.media_urlarrayURLs to generated media (R2 CDN)
output.media_typestringMIME type of the output
created_atstringWhen request was created
completed_atstringWhen request completed
polling_urlstringStatus URL (initial response only)

Status Values

StatusDescription
QUEUEDRequest accepted, waiting to be processed
PROCESSINGBeing processed by the model
COMPLETEDDone — output contains the result
FAILEDFailed — check error field
ERRORSystem error — not charged

Status Flow

QUEUED → PROCESSING → COMPLETED
                    → FAILED
                    → ERROR

Typical Workflow

  1. Send a generate request to the API endpoint
  2. Save the request_id from the response
  3. Poll every 5-10 seconds: GET /v2/requests/status/{request_id}
  4. When status is "COMPLETED", download from output.media_url

Tip: Use X-Webhook-URL header to get a callback instead of polling.

Image DPI 1.0 API Pricing

Your request will cost $0.002 per image.
every image costs $0.002, whatever its resolution or DPI