BeYourCover Jobs API
The Jobs API from BeYourCover — 2 operation(s) for jobs.
The Jobs API from BeYourCover — 2 operation(s) for jobs.
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
find_apisBrowse and filter every API in the catalog.get_api_artifactsOne API's artifacts, grouped by type.get_openapiThe primary OpenAPI for this API.find_similar_apisAPIs that look like this one.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.curl "https://apis.io/api/v1/apis/beyourcover-com:beyourcover-com-jobs-api"
curl "https://apis.io/api/v1/apis?limit=25"
Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: BeYourCover Partner Jobs API
version: 1.1.0
description: 'Enterprise/partner REST API for AI-powered book cover generation: covers from book details or from reference images, variations, edits, replacing a person with a photo, text removal, upscales, audiobook covers, and full print wraps for Amazon KDP with a print-ready PDF. Every endpoint except `GET /api/v1/health` requires a partner API key (`Authorization: Bearer byc_sk_...`). Long-running operations (generation, reference-image generation, variations, edits, replacing a person, text removal, upscales, audiobook covers, print wraps and a wrap''s front-panel re-extension) return `202 Accepted` with a job envelope; poll `GET /api/v1/jobs/{jobId}` or receive a webhook. Re-typesetting a wrap (`POST /api/v1/wraps/{wrapId}/render`) runs no model, so it answers `200` directly. All error responses use a uniform envelope: `{ "error": { "code": string, "message": string } }`.'
servers:
- url: https://beyourcover.com
description: Production. All paths below are relative to the site origin.
security:
- ApiKeyBearer: []
tags:
- name: Jobs
paths:
/api/v1/jobs/{jobId}:
get:
tags:
- Jobs
operationId: getJob
summary: Poll a job's status and result
description: '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.'
parameters:
- name: jobId
in: path
required: true
schema:
type: string
format: uuid
description: Job id returned by a job-creating endpoint (also embedded in `poll_url`).
responses:
'200':
description: Current job state.
content:
application/json:
schema:
$ref: '#/components/schemas/Job'
'400':
description: '`code`: `missing_job_id` (defensive; the path parameter is normally always present).'
x-error-codes:
- missing_job_id
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'404':
description: 'Job not found, or found but owned by a different API key/subscription. `code`: `job_not_found`.'
x-error-codes:
- job_not_found
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
'500':
$ref: '#/components/responses/InternalError'
'503':
description: '`code`: `temporarily_unavailable` — the workspace''s plan could not be checked. Retry.'
x-error-codes:
- temporarily_unavailable
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
/api/v1/jobs:
get:
tags:
- Jobs
operationId: listJobs
summary: List jobs
description: 'Lists the subscription''s jobs, newest first, with optional status/operation/source filters and keyset cursor pagination. The list also holds the jobs the web app records when a workspace member spends credits there (`source: "web"`, for example `edit_font`, `marketing_resource` or `wrap_cover_generate`): they draw on the same credit balance. Result payloads are omitted — poll `GET /api/v1/jobs/{jobId}` for signed cover URLs.'
parameters:
- name: status
in: query
required: false
schema:
type: string
enum:
- queued
- processing
- completed
- failed
description: Filter by job status.
- name: operation
in: query
required: false
schema:
type: string
enum:
- generate
- variation
- edit_image
- upscale
- audiobook_cover
- remove_text
- generate_reference
- replace_person
- wrap
- wrap_extend_front
- import_cover
- 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
description: 'Filter by operation. Accepts every operation a listed job can carry: the API''s, the web app''s, and older web operations that nothing writes now (`audiobook_upscale`, `refine_cover`, `wrap_back_cover_generate`, `wrap_cover_export`).'
- name: source
in: query
required: false
schema:
type: string
enum:
- api
- web
description: 'Filter by where the job ran: `api` (this API or the MCP server) or `web` (the web app).'
- $ref: '#/components/parameters/PageLimit'
- $ref: '#/components/parameters/PageCursor'
responses:
'200':
description: One page of jobs.
content:
application/json:
schema:
$ref: '#/components/schemas/JobList'
'400':
description: '`code` is one of: `invalid_status_filter`, `invalid_operation_filter`, `invalid_source_filter`, `invalid_limit`, `invalid_cursor`.'
x-error-codes:
- invalid_status_filter
- invalid_operation_filter
- invalid_source_filter
- invalid_limit
- invalid_cursor
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'500':
description: Server error. `code` is `fetch_failed` or `internal_error`.
x-error-codes:
- fetch_failed
- internal_error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
components:
responses:
Forbidden:
description: 'The API key is valid but its owner has no active enterprise subscription (`forbidden`); or the acting member''s role does not allow the call: a reviewer cannot spend credits or change books (`forbidden_role`), and only the member who created a book may edit it or its covers (`not_book_creator`).'
x-error-codes:
- forbidden
- forbidden_role
- not_book_creator
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
Unauthorized:
description: 'Missing/malformed API key, unknown or inactive key, or inactive subscription detected during credit checks. `code`: `unauthorized`.'
x-error-codes:
- unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
InternalError:
description: 'Unexpected server error. `code`: `internal_error`.'
x-error-codes:
- internal_error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
schemas:
WrapDimensions:
type: object
description: Print geometry at 300 DPI. All inch values are the finished canvas including bleed.
properties:
spineWidth:
type: number
description: '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:
type: number
description: Full wrap width in inches (back + spine + front + bleed).
fullHeight:
type: number
description: Full wrap height in inches (trim height + bleed).
pixelWidth:
type: integer
description: fullWidth x dpi, rounded.
pixelHeight:
type: integer
description: fullHeight x dpi, rounded.
dpi:
type: integer
description: Always 300.
bleed:
type: number
description: Bleed in inches per edge (0 for hardcover printed case).
safeTextMargin:
type: number
description: Minimum inches between text and the trim edge.
minFontSize:
type: number
description: Smallest point size the layout engine will emit.
canHaveSpineText:
type: boolean
description: False when the spine is too thin for lettering (under 79 pages on KDP); spine text is dropped with a warning.
barcodeZone:
type: object
description: Rectangle in inches, relative to the BACK COVER origin, that the printer covers with the barcode. The layout engine keeps text out of it.
properties:
x:
type: number
y:
type: number
width:
type: number
height:
type: number
sections:
type: object
description: Panel boundaries in inches from the left edge of the full wrap.
additionalProperties:
type: number
bindingType:
type: string
enum:
- paperback
- hardcover
- dust-jacket
description: '`dust-jacket` (with flaps) appears only on Barnes & Noble designs made in the browser editor.'
JobSummary:
type: object
required:
- jobId
- status
- operation
- source
- created_at
- poll_url
properties:
jobId:
type: string
format: uuid
status:
type: string
enum:
- queued
- processing
- completed
- failed
operation:
type: string
enum:
- generate
- variation
- edit_image
- upscale
- audiobook_cover
- remove_text
- generate_reference
- replace_person
- wrap
- wrap_extend_front
- import_cover
- 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
source:
type: string
enum:
- api
- web
description: '`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:
type:
- string
- 'null'
credits_used:
type:
- integer
- 'null'
bookId:
type:
- string
- 'null'
format: uuid
error:
type:
- string
- 'null'
description: Failure message when status is `failed`.
created_at:
type: string
format: date-time
started_at:
type:
- string
- 'null'
format: date-time
completed_at:
type:
- string
- 'null'
format: date-time
poll_url:
type: string
description: Path of the job detail endpoint (result payloads with signed URLs live there, not in this list).
actor_user_id:
type:
- string
- 'null'
format: uuid
description: 'The workspace member the job acted as: the key owner, or the member signed in over MCP OAuth. Null on jobs created before 2026-10-20.'
WrapJobResult:
type: object
description: 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).
required:
- wrapId
- assets
properties:
wrapId:
type: string
format: uuid
description: Pass to GET /api/v1/wraps/{wrapId} and the render endpoint.
bookId:
type: string
format: uuid
coverId:
type: string
format: uuid
description: Public id of the cover used as the front panel.
designStyle:
type: string
enum:
- solid
- textured
- continuation
- complementary
preset:
type: string
enum:
- standard
- blurb-only
- minimal
dims:
$ref: '#/components/schemas/WrapDimensions'
layout_report:
$ref: '#/components/schemas/WrapLayoutReport'
warnings:
type: array
items:
$ref: '#/components/schemas/WrapWarning'
assets:
$ref: '#/components/schemas/WrapAssets'
GenerateJobResult:
type: object
required:
- bookId
- covers
properties:
bookId:
type: string
format: uuid
covers:
type: array
items:
$ref: '#/components/schemas/GeneratedCover'
description: Result payload for `generate` jobs. Only successfully generated covers are included; `credits_used` reflects the successful count.
AssetJobResult:
type: object
required:
- covers
properties:
covers:
type: array
items:
$ref: '#/components/schemas/CoverAssetResult'
description: 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).
Job:
type: object
required:
- jobId
- status
- operation
- source
- external_ref
- credits_used
- created_at
- started_at
- completed_at
- result
- error
properties:
jobId:
type: string
format: uuid
status:
type: string
enum:
- queued
- processing
- completed
- failed
operation:
type: string
enum:
- generate
- variation
- edit_image
- upscale
- audiobook_cover
- remove_text
- generate_reference
- replace_person
- wrap
- wrap_extend_front
- import_cover
- 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
source:
type: string
enum:
- api
- web
description: '`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:
type:
- string
- 'null'
credits_used:
type:
- integer
- 'null'
description: Credits actually consumed (set on completion; partial failures reduce it and refund the difference).
created_at:
type: string
format: date-time
started_at:
type:
- string
- 'null'
format: date-time
completed_at:
type:
- string
- 'null'
format: date-time
result:
oneOf:
- $ref: '#/components/schemas/GenerateJobResult'
- $ref: '#/components/schemas/CoverOperationJobResult'
- $ref: '#/components/schemas/AssetJobResult'
- $ref: '#/components/schemas/WrapJobResult'
- type: 'null'
description: '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.'
error:
type:
- string
- 'null'
description: Failure message when status is `failed` (raw error_message string, not an error envelope).
actor_user_id:
type:
- string
- 'null'
format: uuid
description: 'The workspace member the job acted as: the key owner, or the member signed in over MCP OAuth. Null on jobs created before 2026-10-20.'
CoverOperationJobResult:
type: object
required:
- sourceCoverId
- covers
properties:
sourceCoverId:
type: string
format: uuid
description: Public id of the cover the operation was applied to.
covers:
type: array
items:
$ref: '#/components/schemas/GeneratedCover'
failed_models:
type: array
items:
type: string
description: '`replace_person` only: the models of the pair that made no version. The job still succeeds, and keeps its credit, when one model made a version.'
description: Result payload for `variation`, `edit_image` and `replace_person` jobs. Each entry is a NEW child cover. A `replace_person` job returns up to two covers, one per model, and names each model in `model`.
WrapLayoutReport:
type: object
description: What the compositor actually drew, after auto-fit and guardrails.
properties:
width:
type: integer
height:
type: integer
dpi:
type: integer
blocks:
type: array
items:
type: object
properties:
id:
type: string
fontSize:
type: number
description: Point size after auto-fit, which may be smaller than requested.
heightPx:
type: integer
overflowsPanel:
type: boolean
warnings:
type: array
items:
$ref: '#/components/schemas/WrapWarning'
CoverAssetResult:
type: object
required:
- coverId
- asset
- signedUrl
- expiresAt
properties:
coverId:
type: string
format: uuid
description: Public id of the (source) cover the asset belongs to.
asset:
type: string
enum:
- full
- audiobook_preview
- audiobook_full
- no_text
- no_text_full
description: '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:
type: string
format: uri
expiresAt:
type: string
format: date-time
WrapWarning:
type: object
description: A layout adjustment the engine made, or a limitation of the finished wrap. Warnings never fail a job — they tell you what a human at the editor would have seen and fixed.
required:
- code
- message
properties:
code:
type: string
enum:
- 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
- low_text_contrast
- back_converted_to_solid
blockId:
type: string
description: The text or image block the warning applies to, when it is block-specific.
message:
type: string
WrapAssets:
type: object
description: Renditions of one wrap design. Re-signed on every poll/read.
properties:
wrap_preview:
allOf:
- $ref: '#/components/schemas/WrapAsset'
description: 1024px-wide JPEG for on-screen review.
wrap_flat:
allOf:
- $ref: '#/components/schemas/WrapAsset'
description: Full-resolution composited JPEG at 300 DPI.
wrap_pdf:
allOf:
- $ref: '#/components/schemas/WrapAsset'
description: 'Print-ready PDF sized to fullWidth x fullHeight inches — the file you upload to KDP. The link is signed with `Content-Disposition: attachment`, so a browser saves the file (named like `wrap_cover_paperback_6x9_300pp_white_3820919b_1760000000000.pdf`, as the editor''s PDF export names it) instead of opening it in a tab.'
back_art:
allOf:
- $ref: '#/components/schemas/WrapAsset'
description: The generated back-cover artwork alone, without text. Present on GET /api/v1/wraps/{wrapId}.
GeneratedCover:
type: object
required:
- coverId
- signedUrl
- expiresAt
properties:
coverId:
type: string
format: uuid
description: Public id of the cover. Use with the /api/v1/covers/{coverId} endpoints.
signedUrl:
type: string
format: uri
description: Time-limited signed URL for the preview image (1 hour).
expiresAt:
type: string
format: date-time
coverStyle:
type: string
description: Template/style id used to render the cover (e.g. a V2 template id).
prompt:
type: string
description: The generation prompt stored for this cover.
model:
type: string
description: '`replace_person` only: the image model that made this version.'
ErrorEnvelope:
type: object
required:
- error
properties:
error:
type: object
required:
- code
- message
properties:
code:
type: string
description: Machine-readable error code (snake_case).
message:
type: string
description: Human-readable explanation. For 500s this is always a generic message.
details:
type: object
description: Optional machine-readable recovery information. 402 responses carry { balance, required, billing_url }; unknown-path 404s carry absolute URLs for the OpenAPI spec, documentation, API catalog, authentication guide and health probe.
description: Uniform error envelope used by every non-2xx JSON response.
JobList:
type: object
required:
- jobs
- next_cursor
properties:
jobs:
type: array
items:
$ref: '#/components/schemas/JobSummary'
description: Newest first. Result payloads are omitted — poll `GET /api/v1/jobs/{jobId}` for signed cover URLs.
next_cursor:
type:
- string
- 'null'
description: Pass as `cursor` to fetch the next page. `null` when there are no more results.
WrapAsset:
type: object
required:
- signedUrl
- expiresAt
properties:
signedUrl:
type: string
format: uri
expiresAt:
type: string
format: date-time
parameters:
PageCursor:
name: cursor
in: query
required: false
schema:
type: string
description: Opaque cursor from a previous response's `next_cursor`. Omit for the first page.
PageLimit:
name: limit
in: query
required: false
schema:
type: integer
minimum: 1
maximum: 100
description: Page size (default 20, max 100).
securitySchemes:
ApiKeyBearer:
type: http
scheme: bearer
bearerFormat: byc_sk_{32 hex chars}
description: 'Partner API key sent as `Authorization: Bearer byc_sk_...`. The key must match `^byc_sk_[0-9a-f]{32}$`. A malformed, unknown, or inactive key yields `401 unauthorized`; a valid key whose owner has no active enterprise subscription yields `403 forbidden`.'