---
title: "Poll a job's status and result"
method: GET
path: "/api/v1/jobs/{jobId}"
tags: ["Jobs"]
---

# Poll a job's status and result

`GET /api/v1/jobs/{jobId}`

## Request

- Base URL: `https://beyourcover.com`
- URL: `https://beyourcover.com/api/v1/jobs/{jobId}`
- Auth: HTTP bearer

Returns the job envelope. For `completed` jobs, all `covers[].signedUrl` values in `result` are freshly re-signed on every poll (1-hour expiry) and internal storage paths are stripped. Jobs belonging to a different API key/subscription return `404 job_not_found` (not 403). A job with `source: "web"` ran in the web app: it returns its status and credits, and `result` is always null.

## Path parameters

- `jobId` string, uuid, required

## Response `200`

Current job state.

- Job
  - `jobId` string, uuid, required
  - `status` 'queued' | 'processing' | 'completed' | 'failed', required
  - `operation` 'generate' | 'variation' | 'edit_image' | 'upscale' | 'audiobook_cover' | 'remove_text' | 'generate_reference' | 'wrap' | 'wrap_extend_front' | 'generate_single' | 'edit_font' | 'convert_style' | 'layerize_text' | 'remove_text_variants' | 'audiobook_generate' | 'marketing_resource' | 'kit_regeneration' | 'brand_kit_extract' | 'series_next_book' | 'wrap_cover_generate' | 'wrap_cover_regenerate' | 'audiobook_upscale' | 'refine_cover' | 'wrap_back_cover_generate' | 'wrap_cover_export', required
  - `source` 'api' | 'web', required: `api`: started through this API or the MCP server. `web`: recorded by the web app when a workspace member spent credits there; its output stays in the app.
  - `external_ref` string, nullable, required
  - `credits_used` integer, nullable, required: Credits actually consumed (set on completion; partial failures reduce it and refund the difference).
  - `created_at` string, date-time, required
  - `started_at` string, date-time, nullable, required
  - `completed_at` string, date-time, nullable, required
  - `result` union, required: Null until the job completes. Shape depends on `operation`: `generate`/`generate_reference` -> GenerateJobResult; `variation`/`edit_image` -> CoverOperationJobResult; `upscale`/`audiobook_cover`/`remove_text` -> AssetJobResult; `wrap`/`wrap_extend_front` -> WrapJobResult. On each poll of a completed job, signed URLs and their `expiresAt` are refreshed. Always null for a `web` job.
    - GenerateJobResult: Result payload for `generate` jobs. Only successfully generated covers are included; `credits_used` reflects the successful count.
      - `bookId` string, uuid, required
      - `covers` GeneratedCover[], required
        - `coverId` string, uuid, required: Public id of the cover. Use with the /api/v1/covers/{coverId} endpoints.
        - `signedUrl` string, uri, required: Time-limited signed URL for the preview image (1 hour).
        - `expiresAt` string, date-time, required
        - `coverStyle` string: Template/style id used to render the cover (e.g. a V2 template id).
        - `prompt` string: The generation prompt stored for this cover.
    - CoverOperationJobResult: Result payload for `variation` and `edit_image` jobs. Each entry is a NEW child cover.
      - `sourceCoverId` string, uuid, required: Public id of the cover the operation was applied to.
      - `covers` GeneratedCover[], required
        - `coverId` string, uuid, required: Public id of the cover. Use with the /api/v1/covers/{coverId} endpoints.
        - `signedUrl` string, uri, required: Time-limited signed URL for the preview image (1 hour).
        - `expiresAt` string, date-time, required
        - `coverStyle` string: Template/style id used to render the cover (e.g. a V2 template id).
        - `prompt` string: The generation prompt stored for this cover.
    - AssetJobResult: Result payload for `upscale` and `audiobook_cover` jobs. The new asset is attached to the SAME cover (coverId is the source cover's public id).
      - `covers` CoverAssetResult[], required
        - `coverId` string, uuid, required: Public id of the (source) cover the asset belongs to.
        - `asset` 'full' | 'audiobook_preview' | 'audiobook_full' | 'no_text' | 'no_text_full', required: Which asset was produced: `full` (upscale of preview), `audiobook_full` (upscale of audiobook_preview), `audiobook_preview` (audiobook_cover jobs), `no_text` (remove_text jobs), or `no_text_full` (upscale of no_text).
        - `signedUrl` string, uri, required
        - `expiresAt` string, date-time, required
    - WrapJobResult: Result payload for a `wrap` or `wrap_extend_front` job. Unlike cover operations this carries an `assets` map, not a `covers` array — a wrap is several renditions of ONE design. For `wrap_extend_front`, `designStyle` and `preset` are omitted (the wrap's stored layout is reused).
      - `wrapId` string, uuid, required: Pass to GET /api/v1/wraps/{wrapId} and the render endpoint.
      - `bookId` string, uuid
      - `coverId` string, uuid: Public id of the cover used as the front panel.
      - `designStyle` 'solid' | 'textured' | 'continuation' | 'complementary'
      - `preset` 'standard' | 'blurb-only' | 'minimal'
      - `dims` WrapDimensions: Print geometry at 300 DPI. All inch values are the finished canvas including bleed.
        - `spineWidth` number: Spine width in inches: derived from pageCount and paperType on a KDP wrap, entered by hand on a Barnes & Noble design from the editor.
        - `fullWidth` number: Full wrap width in inches (back + spine + front + bleed).
        - `fullHeight` number: Full wrap height in inches (trim height + bleed).
        - `pixelWidth` integer: fullWidth x dpi, rounded.
        - `pixelHeight` integer: fullHeight x dpi, rounded.
        - `dpi` integer: Always 300.
        - `bleed` number: Bleed in inches per edge (0 for hardcover printed case).
        - `safeTextMargin` number: Minimum inches between text and the trim edge.
        - `minFontSize` number: Smallest point size the layout engine will emit.
        - `canHaveSpineText` boolean: False when the spine is too thin for lettering (under 79 pages on KDP); spine text is dropped with a warning.
        - `barcodeZone` object: Rectangle in inches, relative to the BACK COVER origin, that the printer covers with the barcode. The layout engine keeps text out of it.
          - `x` number
          - `y` number
          - `width` number
          - `height` number
        - `sections` object: Panel boundaries in inches from the left edge of the full wrap.
        - `bindingType` 'paperback' | 'hardcover' | 'dust-jacket': `dust-jacket` (with flaps) appears only on Barnes & Noble designs made in the browser editor.
      - `layout_report` WrapLayoutReport: What the compositor actually drew, after auto-fit and guardrails.
        - `width` integer
        - `height` integer
        - `dpi` integer
        - `blocks` object[]
          - `id` string
          - `fontSize` number: Point size after auto-fit, which may be smaller than requested.
          - `heightPx` integer
          - `overflowsPanel` boolean
        - `warnings` WrapWarning[]
          - `code` 'text_too_long_for_band' | 'text_too_long_for_block' | 'preset_not_applied' | 'text_overflows_panel' | 'clamped_to_safe_area' | 'moved_clear_of_barcode' | 'barcode_zone_unavoidable' | 'font_size_raised_to_minimum' | 'spine_too_thin_for_text' | 'italic_not_available' | 'bold_not_available' | 'image_block_not_rendered' | 'spine_image_not_allowed' | 'front_outpaint_trimmed' | 'front_outpaint_incomplete', required
          - `blockId` string: The text or image block the warning applies to, when it is block-specific.
          - `message` string, required
      - `warnings` WrapWarning[]
        - `code` 'text_too_long_for_band' | 'text_too_long_for_block' | 'preset_not_applied' | 'text_overflows_panel' | 'clamped_to_safe_area' | 'moved_clear_of_barcode' | 'barcode_zone_unavoidable' | 'font_size_raised_to_minimum' | 'spine_too_thin_for_text' | 'italic_not_available' | 'bold_not_available' | 'image_block_not_rendered' | 'spine_image_not_allowed' | 'front_outpaint_trimmed' | 'front_outpaint_incomplete', required
        - `blockId` string: The text or image block the warning applies to, when it is block-specific.
        - `message` string, required
      - `assets` WrapAssets, required: Renditions of one wrap design. Re-signed on every poll/read.
        - `wrap_preview` WrapAsset
          - `signedUrl` string, uri, required
          - `expiresAt` string, date-time, required
        - `wrap_flat` WrapAsset
          - `signedUrl` string, uri, required
          - `expiresAt` string, date-time, required
        - `wrap_pdf` WrapAsset
          - `signedUrl` string, uri, required
          - `expiresAt` string, date-time, required
        - `back_art` WrapAsset
          - `signedUrl` string, uri, required
          - `expiresAt` string, date-time, required
  - `error` string, nullable, required: Failure message when status is `failed` (raw error_message string, not an error envelope).

## Other responses

- `400`: `code`: `missing_job_id` (defensive; the path parameter is normally always present).
- `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`: Job not found, or found but owned by a different API key/subscription. `code`: `job_not_found`.
- `500`: Unexpected server error. `code`: `internal_error`.
- `503`: `code`: `temporarily_unavailable` — the workspace's plan could not be checked. Retry.

---

[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)
