---
title: "Upscale a cover asset to print resolution (async)"
method: POST
path: "/api/v1/covers/{coverId}/upscale"
tags: ["Covers"]
---

# Upscale a cover asset to print resolution (async)

`POST /api/v1/covers/{coverId}/upscale`

## Request

- Base URL: `https://beyourcover.com`
- URL: `https://beyourcover.com/api/v1/covers/{coverId}/upscale`
- Auth: HTTP bearer

Upscales `preview` -> `full`, `audiobook_preview` -> `audiobook_full`, or `no_text` -> `no_text_full`. FREE for every source asset, `audiobook_preview` included: consumes no credits (only the concurrency limit applies; there is no 402 on this endpoint). The web app's high-res downloads are free on Enterprise too. Returns `409 asset_already_exists` if the target asset already exists, and `404 asset_not_available` if the source asset has not been generated.

## Path parameters

- `coverId` string, uuid, required

## Headers

- `Idempotency-Key` string

## Request body

- object
  - `sourceAsset` 'preview' | 'audiobook_preview' | 'no_text', required: Which asset to upscale. `preview` produces the `full` asset; `audiobook_preview` produces `audiobook_full`; `no_text` produces `no_text_full`.
  - `external_ref` string: Optional caller-supplied reference. (Length/type limits are not enforced on this endpoint in code.)
  - `webhookUrl` string: Optional per-job webhook URL. (Length/type limits are not enforced on this endpoint in code.)

## Response `200`

Idempotent replay of an existing job with the same `Idempotency-Key`.

- JobReplay: 200 envelope returned when an Idempotency-Key matches an existing job. Unlike the fresh 202, `status` reflects the job's current state and `operation` is always present.
  - `jobId` string, uuid, required
  - `status` 'queued' | 'processing' | 'completed' | 'failed', required: Current status of the previously created job.
  - `operation` 'generate' | 'variation' | 'edit_image' | 'upscale' | 'audiobook_cover' | 'remove_text' | 'generate_reference' | 'wrap' | 'wrap_extend_front', required
  - `credits_reserved` integer: What the ORIGINAL job reserved. Returned by the variations, edit-image, upscale, audiobook-cover, remove-text, wraps and extend-front endpoints when the job recorded it.
  - `included_format` boolean: true when the book's marketing kit paid for the ORIGINAL job instead of credits. Returned by the edit-image, upscale, audiobook-cover, remove-text, wraps and extend-front endpoints.
  - `external_ref` string, nullable, required: The external_ref stored on the ORIGINAL job.
  - `created_at` string, date-time, required
  - `poll_url` string, required

## Other responses

- `202`: Job accepted and queued. `operation` is `upscale`.
- `400`: `code`: `invalid_source_asset` (missing or not one of `preview`, `audiobook_preview`, `no_text`).
- `401`: Missing/malformed API key, unknown or inactive key, or inactive subscription detected during credit checks. `code`: `unauthorized`.
- `403`: The API key is valid but its owner has no active enterprise subscription. `code`: `forbidden`.
- `404`: `code` is one of: `asset_not_available` (source asset not generated yet), `cover_not_found` (cover missing or not owned).
- `409`: `code` is one of: `asset_already_exists` (the target asset already exists for this cover), `operation_in_progress` (an identical job for this cover is already queued or processing — poll it instead of starting another; a second run would charge again and overwrite the first result).
- `429`: The subscription's concurrent-job limit is reached (jobs with status `queued` or `processing` count). `code`: `concurrency_limit`.
- `500`: Server error. `code` is `job_creation_failed` or `internal_error`.

---

[API](https://skmtc.dev/beyourcover/apis/beyourcover-partner-api.md) · [All operations](https://skmtc.dev/beyourcover/apis/beyourcover-partner-api/llms.txt) · [OpenAPI document](https://skmtc.dev/beyourcover/apis/beyourcover-partner-api/revisions/82ad2c7c8ede?raw)
