Enlarge photos from code

Three ways in, one contract. The REST API runs Pro. The enlarge CLI and its local MCP server run Free on your machine with no key, and Pro with an API key.

Get an API key

Free needs no key in the CLI or MCP server. Pro needs an account with credits and an API key:

  1. Sign in with your email. There is no password; we send you a link.
  2. Buy a credit pack on your account page (see pricing).
  3. On the same page, create an API key under API keys. It starts with enl_ and is shown once, so store it somewhere safe.

Send it as Authorization: Bearer enl_…. You can have up to 10 keys and revoke any of them at any time. Keys spend the credits of the account that made them.

REST API

Base URL https://enlarge.photos/api/v1. Requests and responses are JSON, except the upload (multipart) and the download (the image). Enlarging is asynchronous: create a job, poll it, then download the result.

  • Credits are taken when the job is created: one per 24 MP of output, up to 5. If the job fails, they are refunded automatically.
  • Results are kept for 24 hours, then deleted. We delete the upload when the job ends.
  • Rate limits: 30 per minute new jobs and 60 per minute deletes per account, and 20 per minute failed key checks per IP address.

POST/api/v1/upscale

Creates a Pro job. Send multipart/form-data; the answer is 202 with the job.

POST /api/v1/upscale fields
FieldValuesDefault
imageJPEG, PNG or WebP file, up to 50 MBRequired
scale2, 4The largest that keeps the output within 100 MP
modestandard, high_fidelity, low_resstandard
face_enhancetrue, falsetrue
formatauto, jpeg, png, webpauto (same as the input)
curl
curl https://enlarge.photos/api/v1/upscale \
  -H "Authorization: Bearer enl_…" \
  -F [email protected] \
  -F scale=4 \
  -F mode=standard

GET/api/v1/jobs/:id

Returns the job. status moves from queued to running to succeeded or failed, and a succeeded job becomes expired after 24 hours. Poll every 2 seconds. Only the account that created a job can see it.

curl
curl https://enlarge.photos/api/v1/jobs/job_7Hk2mQ9xLp3vR8sT \
  -H "Authorization: Bearer enl_…"
200 OK
{
  "job": {
    "id": "job_7Hk2mQ9xLp3vR8sT",
    "status": "succeeded",
    "engine": "pro",
    "provider": "fal",
    "mode": "standard",
    "scale": 4,
    "face_enhance": true,
    "format": "auto",
    "filename": "[email protected]",
    "input": {
      "width": 1200,
      "height": 800
    },
    "output": {
      "width": 4800,
      "height": 3200
    },
    "credits": 1,
    "output_bytes": 4182733,
    "error": null,
    "created_at": "2026-10-09T17:02:11.000Z",
    "started_at": "2026-10-09T17:02:11.412Z",
    "finished_at": "2026-10-09T17:02:24.903Z",
    "expires_at": "2026-10-10T17:02:24.903Z",
    "download_url": "https://enlarge.photos/api/v1/jobs/job_7Hk2mQ9xLp3vR8sT/download",
    "thumbnail_url": "https://enlarge.photos/api/v1/jobs/job_7Hk2mQ9xLp3vR8sT/thumbnail"
  }
}

GET/api/v1/jobs/:id/download

Returns the enlarged image. Before the job succeeds the answer is 409 not_ready; after 24 hours it is 410 expired.

curl
curl https://enlarge.photos/api/v1/jobs/job_7Hk2mQ9xLp3vR8sT/download \
  -H "Authorization: Bearer enl_…" \
  -o [email protected]

GET/api/v1/jobs/:id/thumbnail

Returns a small preview of the result: a WebP image whose longest side is 384 pixels. A succeeded job links to it as thumbnail_url. Like the download, it answers 409 not_ready until the job succeeds and 410 expired once the result is deleted.

curl
curl https://enlarge.photos/api/v1/jobs/job_7Hk2mQ9xLp3vR8sT/thumbnail \
  -H "Authorization: Bearer enl_…" \
  -o preview.webp

DELETE/api/v1/jobs/:id

Deletes the job and its files now, instead of after 24 hours. Credits are not refunded. While the job is queued or running the answer is 409 not_ready; wait for it to finish. A job that is already gone, or not yours, is 404 not_found.

curl
curl -X DELETE https://enlarge.photos/api/v1/jobs/job_7Hk2mQ9xLp3vR8sT \
  -H "Authorization: Bearer enl_…"
200 OK
{
  "deleted": true
}

GET/api/v1/jobs?limit=20

Your most recent jobs, newest first, as { "jobs": [...] }. limit is 1 to 100.

curl
curl "https://enlarge.photos/api/v1/jobs?limit=20" \
  -H "Authorization: Bearer enl_…"

GET/api/v1/me

The account the key belongs to and its credit balance.

curl
curl https://enlarge.photos/api/v1/me \
  -H "Authorization: Bearer enl_…"
200 OK
{
  "email": "[email protected]",
  "credits": 59
}

A full round trip

Create, poll and download in one script (uses jq):

enlarge.sh
export ENLARGE_API_KEY=enl_…

JOB=$(curl -s https://enlarge.photos/api/v1/upscale \
  -H "Authorization: Bearer $ENLARGE_API_KEY" \
  -F [email protected] | jq -r .job.id)

# Poll every 2 seconds until the job leaves queued/running
while :; do
  STATUS=$(curl -s https://enlarge.photos/api/v1/jobs/$JOB \
    -H "Authorization: Bearer $ENLARGE_API_KEY" | jq -r .job.status)
  [ "$STATUS" = queued ] || [ "$STATUS" = running ] || break
  sleep 2
done

[ "$STATUS" = succeeded ] && curl -s https://enlarge.photos/api/v1/jobs/$JOB/download \
  -H "Authorization: Bearer $ENLARGE_API_KEY" -o photo-enlarged.jpg

Errors

Every error has the same shape and an HTTP status that matches its code:

402 Payment Required
{
  "error": {
    "code": "insufficient_credits",
    "message": "This needs 2 credits and you have 1. Buy credits at https://enlarge.photos/account#credits. Questions: [email protected]."
  }
}
Error codes
StatusCodeMeaning
401unauthorizedSign in or send a valid API key (Authorization: Bearer enl_...).
402insufficient_creditsNot enough credits. Buy credits at https://enlarge.photos/account#credits. Questions: [email protected].
403forbiddenYou do not have access to this.
404not_foundNot found.
409not_readyThe job has not finished yet.
410expiredThe result has expired. Results are kept for 24 hours.
422too_largeThe image is too large.
422invalid_inputThe request is invalid.
429rate_limitedToo many requests. Try again in a minute.
502provider_errorThe enlargement failed at our processor. Your credits were refunded.
503unavailablePro is temporarily unavailable. Try again later.

CLI

The enlarge command ships in the npm package enlarge-photos and needs Node 20 or later. Free runs the model on your machine and works offline; on a Mac it uses Core ML when it can.

Terminal
npm i -g enlarge-photos

# Free: runs on your machine, offline, no key
enlarge photo.jpg

# Pro: Topaz via your API key, asks before spending credits
export ENLARGE_API_KEY=enl_…
enlarge photo.jpg -e pro

Usage

Usage
enlarge <inputs...> [-s 2|4] [-e free|pro] [--mode standard|high_fidelity|low_res]
        [--no-face-enhance] [-f auto|jpeg|png|webp] [-o <file|dir>]
        [--force] [--yes] [--json] [--verbose]

Inputs are files or folders (JPEG, PNG and WebP; folders are not searched recursively). Results are named <name>@<scale>x.<ext> and existing files are never overwritten without --force.

CLI options
OptionWhat it does
-s 2|4Scale. Default: the largest that fits the engine's limit.
-e free|proEngine. Default free.
--modePro mode: standard, high_fidelity, low_res. Default standard.
--no-face-enhancePro: turn face enhancement off (it is on by default).
-fOutput format: auto, jpeg, png, webp. Default auto, same as the input.
-o <file|dir>Where to write the result.
--forceOverwrite existing files.
--yesSkip the Pro credit confirmation. Required when not running in a terminal.
--jsonPrint one JSON object per result on stdout.
--verboseShow more detail, such as which accelerator ran.

Commands

CLI commands
CommandWhat it does
enlarge loginSave your API key. Paste it at the hidden prompt or pipe it in; it is checked before saving.
enlarge logoutRemove the saved key.
enlarge whoamiShow the account and credit balance for the key.
enlarge mcpStart the MCP server on stdio (see below).
enlarge --helpAll options.

Configuration and exit codes

  • The key comes from ENLARGE_API_KEY, else from ~/.config/enlarge-photos/config.json (written by enlarge login, readable only by you; XDG_CONFIG_HOME is respected).
  • Pro shows the credit total and asks before it spends anything. Progress goes to stderr, results to stdout.
  • Exit codes: 0 success, 1 error, 2 usage error, 3 not enough credits.

MCP server

enlarge mcp is a local MCP server on stdio. Your agent hands it a file path; the image is enlarged on your machine (Free) or by Topaz (Pro) and saved as a new file. Without a key, only Free is available.

Terminal
npm i -g enlarge-photos
claude mcp add enlarge -e ENLARGE_API_KEY=enl_… -- enlarge mcp

# Free only, no key:
# claude mcp add enlarge -- enlarge mcp

Tools

MCP tools
ToolWhat it does
upscale_imageEnlarges the image at path (absolute). Optional: scale, engine, mode, face_enhance, format, output_path. Returns the output path, its size, the engine, credits used and credits left.
estimate_costWhat a Pro enlargement of path would cost, computed locally. Optional scale.
get_accountThe account and credit balance for the configured key.

Long jobs report progress to clients that ask for it. Try: Enlarge ~/Desktop/photo.jpg 4x or How much would a Pro enlargement of this photo cost?