BeYourCover Book Cover Generation API

Generate, edit, and download professional AI book covers programmatically. Built for publishers, self-publishing platforms, and developer teams who need automated book cover design at scale.

REST APIMCP Server23 EndpointsWebhook SupportHMAC-SHA256 Signed

Who Uses the Book Cover API?

Self-Publishing Platforms

Offer built-in cover generation to your authors. Integrate with a few API calls and let users create covers without leaving your platform.

Publishing Houses & Agencies

Generate hundreds of cover variations for your catalog. Use bulk generation to A/B test covers and find what converts best.

Author Tools & SaaS Products

Add professional cover design to your writing, formatting, or marketing tool. White-label ready with full control over the generation pipeline.

How It Works

1

Create a Book

Send title, author, genre, and a summary to POST /books. The summary helps the AI generate relevant imagery.

2

Generate Covers

Call POST /generate with your book ID. Get up to 5 AI-generated covers per request, delivered via polling or webhooks.

3

Edit, Upscale & Download

Refine covers with AI edits, create variations, generate audiobook versions, and upscale to high resolution — all through the API.

API Documentation

Generate book covers programmatically with the BeYourCover REST API.

Quick Start

Generate your first cover with 4 API calls and the bare minimum data. Grab your API key from the Authentication section, then run the commands below.

  1. Create a book — only title, author, and genre are required.
  2. Generate a cover — pass the bookId. Returns a job ID.
  3. Poll the job until status is completed.
  4. Download the cover from the asset download endpoint.
End-to-end minimum (curl)
# 1. Create a book (only title, author, genre required)
curl -X POST https://beyourcover.com/api/v1/books \
  -H "Authorization: Bearer byc_sk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"title":"My Novel","author":"Jane Doe","genre":"fantasy"}'
# -> { "bookId": "uuid", ... }

# 2. Generate a cover (only bookId required)
curl -X POST https://beyourcover.com/api/v1/covers/generate \
  -H "Authorization: Bearer byc_sk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"bookId":"<bookId>"}'
# -> { "jobId": "uuid", "poll_url": "/api/v1/jobs/uuid", ... }

# 3. Poll until status === "completed"
curl https://beyourcover.com/api/v1/jobs/<jobId> \
  -H "Authorization: Bearer byc_sk_your_key"
# -> { "status": "completed", "result": { "covers": [{ "coverId": "uuid", ... }] } }

# 4. Download the cover
curl -L https://beyourcover.com/api/v1/covers/<coverId>/assets/preview/download \
  -H "Authorization: Bearer byc_sk_your_key" \
  -o cover.png

Tip: Adding a summary to the book dramatically improves cover quality — the AI uses it to pick imagery and color. See the full endpoint reference for count, templates, mood, webhooks, and more.

Authentication

All API requests require a Bearer token in the Authorization header. Get your API key from the Account Dashboard. Don't have an account yet? Choose an API plan to get started.

Header
Authorization: Bearer byc_sk_your_api_key_here

Rate Limits

PlanCredits/moConcurrent Jobs
Starter1505
Growth50010
Scale1,50020

See full plan details and pricing on the Enterprise Plans page.

MCP Server (for AI agents)

BeYourCover ships a remote Model Context Protocol server, so AI agents (Claude, and any MCP-capable client) can generate covers through the same partner pipeline as the REST API — spending the same credits. It's served over Streamable HTTP at https://beyourcover.com/api/mcp/mcp and supports two ways to authenticate. It serves the stateless 2026-07-28 MCP specification natively, and still answers 2025-era Streamable HTTP clients from the same endpoint — so no existing connector needs changing.

Finished covers come back as inline image content — a downscaled JPEG preview — alongside a 1-hour signed URL that serves the full-resolution original. Whether the preview is displayed is up to the client: Claude Code renders it, while Claude Desktop and claude.ai currently do not surface tool-result images, so on those the reader gets the link. The link is always present, so nothing depends on the image being rendered. Pass include_images: false (or include_image: false on download_cover) to skip the images on programmatic runs. Print-resolution assets (full, audiobook_full) are always URL-only — they are far too large to inline.

Option A — API key (Claude Code, scripts, bridges)

Fastest for developers. Uses the same byc_sk_ key as the REST API in an Authorization: Bearer header.

Claude Code (one line)
claude mcp add --transport http beyourcover \
  https://beyourcover.com/api/mcp/mcp \
  --header "Authorization: Bearer byc_sk_your_api_key_here"

For a client that only accepts a URL (e.g. Claude Desktop's config file), bridge to it with mcp-remote, passing the key as a header:

claude_desktop_config.json (mcp-remote bridge)
{
  "mcpServers": {
    "beyourcover": {
      "command": "npx",
      "args": [
        "-y", "mcp-remote",
        "https://beyourcover.com/api/mcp/mcp",
        "--header", "Authorization:${BYC_AUTH}"
      ],
      "env": { "BYC_AUTH": "Bearer byc_sk_your_api_key_here" }
    }
  }
}

Option B — OAuth (Claude Desktop & claude.ai connectors)

For a one-click “Add custom connector” experience with no config files or keys to paste. Add the server URL in your client's connector settings and it walks you through the standard OAuth sign-in:

Add custom connector
Connector URL:  https://beyourcover.com/api/mcp/mcp

The client discovers our authorization server (via /.well-known/oauth-protected-resource), registers itself, and sends you to a BeYourCover sign-in + approval screen. On approval it receives a scoped token tied to your subscription — no byc_sk_ key required. Authorization uses the OAuth 2.1 authorization-code flow with PKCE; you can revoke a connected client anytime from your dashboard.

The server exposes 19 task-shaped tools (not a 1:1 REST mirror): create_book_and_generate_covers, generate_covers_for_book, get_generation_status, list_templates_for_genre, get_credit_balance, list_books, list_covers_for_book (free), download_cover, upscale_cover (free), edit_cover, remove_cover_text, upload_reference_image (free — takes an image_url the server fetches, or base64 for small images), generate_cover_from_reference, create_audiobook_cover, get_wrap (free), create_full_wrap (a complete print wrap — back artwork, typeset back cover, spine and extended front — returning a KDP-ready PDF), update_wrap_text (re-typeset a wrap, free and immediate), extend_wrap_front (re-run just the front extension, free) and calculate_kdp_wrap (the wrap calculator is free and uses no credits). Covers come back as short-lived signed URLs plus inline MCP image content in clients that render it; print-resolution assets stay URL-only. Wrap jobs return the wrapId with its preview, full-resolution flat and print PDF, plus any layout warnings.

Generation is asynchronous: the create tool returns a jobId that agents poll with get_generation_status. Genre coverage matches the REST API — see Genres & Subgenres or call GET /api/v1/capabilities.

Discovery & health

Every API on this site is indexed in an RFC 9727 API catalog, so an agent can find the REST API and the MCP server — and their specs, docs and health endpoint — from one well-known URL, with no scraping:

Fetch the API catalog
curl https://beyourcover.com/.well-known/api-catalog

# Content-Type: application/linkset+json;
#   profile="https://www.rfc-editor.org/info/rfc9727"

The response is a linkset whose entries anchor on each API endpoint and carry service-desc (the OpenAPI 3.1 spec for REST, the MCP manifest for MCP), service-doc (this page and /api-docs.md), status (the health probe below) and service-meta (the auth.md guide, plus the OAuth metadata for MCP). Every page on the site also advertises it in a Link: </.well-known/api-catalog>; rel="api-catalog" response header.

/auth.md

The auth.md convention: one markdown document telling an agent how to get a credential and where it works — OAuth 2.1 (MCP endpoint only, fully self-service including client registration) versus a partner API key (REST and MCP, provisioned by a human in the dashboard). It pairs with /.well-known/oauth-protected-resource, which carries the machine-readable half: the authorization server, the scopes to request, and bearer_methods_supported. Worth reading before your first authenticated call — a valid OAuth token still returns 401 unless the account behind it has an active API plan.

Read the agent auth guide
curl https://beyourcover.com/auth.md
curl https://beyourcover.com/.well-known/oauth-protected-resource

Markdown for agents (Accept: text/markdown)

Every public page on this site does content negotiation. Send Accept: text/markdown and you get the page as clean Markdown with YAML frontmatter (title, description, canonical url) instead of HTML, so there is no layout to strip. Covered: the home page, the marketing pages, every blog article and listing, the product guides, the free tools, the genre pages and the premade marketplace. Signed-in app surfaces and the legal pages stay HTML-only.

Responses carry Vary: Accept and x-markdown-tokens, an estimated token count you can use to budget context before reading the body. HTML stays the default for browsers — a wildcard Accept never returns Markdown. The user guides also keep permanent .md URLs that need no header.

Fetch any page as Markdown
curl -H "Accept: text/markdown" https://beyourcover.com/
curl -H "Accept: text/markdown" https://beyourcover.com/blog/amazon-book-cover-dimensions

# Content-Type: text/markdown; charset=utf-8
# Vary: Accept
# x-markdown-tokens: 3403

# Permanent .md URLs, no Accept header needed:
curl https://beyourcover.com/docs/full-wrap-covers.md

GET /api/v1/health

The one endpoint that needs no API key. It reports that the API is serving requests — it does not check the database, payment or image providers, so a 200 here is not a promise that a generation will succeed. For per-operation availability use GET /api/v1/capabilities. Responses are never cached.

Liveness probe
curl https://beyourcover.com/api/v1/health

{
  "status": "ok",
  "service": "BeYourCover Partner API",
  "version": "1.0.0"
}

Endpoints

POST/api/v1/books

Create a book record. Required before generating covers.

FieldRequiredMaxDescription
titlerequired100Book title
authorrequired*100Author name. *Optional when genre is planner-journal — planner covers typically lead with a brand wordmark and omit the author.
genrerequiredGenre slug — see Genres section
subtitleoptional300Book subtitle
subgenreoptional100Subgenre (kebab-case — see Genres section). For genres that use subgenres, omitting this auto-detects one from your title and summary; an explicit value always wins.
summaryrecommended1000Book synopsis — strongly recommended, used by the AI to create relevant imagery
target_audienceoptionalRestricted values: children, middle-grade, young-adult, new-adult, adult
external_refoptional200Your internal ID — echoed back in responses
planner_yearoptionalFree-form year label rendered prominently on the cover (typically foil-stamped). Only relevant when genre is planner-journal. Any string is accepted — e.g. 2026, 2026-2027, FY26.

Tip: Always provide a summary. The AI uses it to select visual metaphors, color palettes, and imagery that match your book. Without it, the cover will be based on title and genre alone, which produces more generic results.

Note: Title, author, and subtitle do not support Arabic or Hindi (Devanagari) scripts. Most other scripts including Latin, CJK, Cyrillic, and accented characters are supported.

Planner & Journal covers: When genre is planner-journal, the author field becomes optional (most planners lead with a brand wordmark and have no author). Use title for the brand/wordmark, subtitle for the tagline, and planner_year for a prominent foil-stamped year on the cover.

Subgenre auto-detection: For genres that use subgenres (Romance, Fantasy, Thriller, Mystery, Science Fiction, Horror, Contemporary Fiction, Biography & Memoir, Planner & Journal, Children's), omitting subgenre auto-detects one from your title and summary; the resolved value is returned as subgenre in the response. A few genres (Self-Help, Business, Religion, Health & Fitness, Historical Fiction) need no subgenre at all. An explicit subgenre always takes precedence.

Example Request
{
  "title": "Scale Without Limits",
  "author": "Alex Carter",
  "genre": "business-economics",
  "subtitle": "Systems and Strategies for Explosive Business Growth",
  "summary": "A practical guide for entrepreneurs and executives on building scalable systems, creating predictable growth, and leading high-performing organizations in competitive markets.",
  "target_audience": "adult",
  "external_ref": "book-123"
}
Example Request — Planner & Journal (no author)
{
  "title": "The Daily Momentum Planner",
  "subtitle": "Master Your Work Hours and Reclaim Your Time",
  "genre": "planner-journal",
  "subgenre": "productivity",
  "planner_year": "2026",
  "summary": "A weekly planner for entrepreneurs focused on quarterly goal tracking, time blocking, and reflection prompts.",
  "external_ref": "planner-001"
}
Headers (optional)
Idempotency-Key: unique-request-id
Response 201 (or 200 if idempotent duplicate)
{
  "bookId": "uuid",
  "subgenre": null,
  "external_ref": "book-123",
  "created_at": "2025-01-15T10:30:00Z"
}

POST/api/v1/covers/generate

Start an async cover generation job. Returns 202 immediately.

FieldRequiredMaxDescription
bookIdrequiredUUID of the book created via POST /api/v1/books
countoptionalNumber of covers to generate. Integer 1–5, default 1. Each cover costs 1 credit.
templateIdoptionalTemplate ID from GET /templates. If omitted, the best template is auto-selected for the book's genre & subgenre. An unrecognized id returns 400 invalid_template_id.
promptoptional1500Free-text prompt or instructions for the cover. Short text is treated as visual elements and enhanced by our AI.
moodoptionalRestricted values: intense, mysterious, romantic, intellectual, uplifting, epic, melancholic
colorPaletteoptionalRestricted values: monochrome, pastel, earth, muted, dark, bold, warm, cool, metallic, duotone
external_refoptional200Your internal ID — echoed back in responses and webhooks
webhookUrloptional500Per-job webhook override. Falls back to the URL configured in your dashboard.

Supported genres & credit safety: Generation requires the book's genre/subgenre to be supported. If it isn't — e.g. a genre that uses subgenres with none set — the request returns 422 unsupported_genre and no credits are charged. Letting POST /books auto-detect the subgenre avoids this. All synchronous rejections (404, 422, 400) happen before credits are reserved.

Example Request
{
  "bookId": "550e8400-e29b-41d4-a716-446655440000",
  "count": 3,
  "mood": "intellectual",
  "colorPalette": "muted"
}
Headers (optional)
Idempotency-Key: unique-request-id
Response 202
{
  "jobId": "uuid",
  "status": "queued",
  "operation": "generate",
  "external_ref": "gen-001",
  "created_at": "2025-01-15T10:30:00Z",
  "poll_url": "/api/v1/jobs/uuid"
}

GET/api/v1/jobs/:jobId

Poll job status. Each call returns freshly signed URLs valid for 1 hour. The result shape varies by operation — see each endpoint for details.

Response 200 (completed — generate/variation)
{
  "jobId": "uuid",
  "status": "completed",
  "operation": "generate",
  "external_ref": "gen-001",
  "credits_used": 2,
  "created_at": "...",
  "started_at": "...",
  "completed_at": "...",
  "result": {
    "bookId": "uuid",
    "covers": [
      {
        "coverId": "uuid",
        "signedUrl": "https://...",
        "expiresAt": "2025-01-15T11:30:00.000Z",
        "coverStyle": "template-name",
        "prompt": "A dark, moody book cover featuring..."
      }
    ]
  },
  "error": null
}

Important: Signed URLs expire after 1 hour. Download or serve images on your infrastructure before the expiresAt timestamp. You can re-poll the job at any time to get fresh URLs.

GET/api/v1/templates

List available cover templates. Authentication required. No credits are consumed. Use the same genre values from the Genres & Subgenres section to filter.

Query Parameters
?genre=fantasy                          // optional, any genre slug
?genre=science-fiction
?genre=thriller&subgenre=cozy           // optional; subgenre requires genre
?genre=romance&subgenre=dark-romance
?genre=fantasy&subgenre=romantasy

subgenre uses the kebab-case values from the Genres & Subgenres table (e.g. cozy, dark-romance, epic-fantasy). With genre and subgenre, the response includes that subgenre's templates plus broader genre-level templates, each tagged with a subgenreMatch boolean so you can distinguish bespoke-subgenre templates from generic ones. With genre alone, it returns every template available across that genre's subgenres.

Errors: 400 invalid_genre, 400 invalid_subgenre (lists valid values), 400 missing_genre_for_subgenre (subgenre sent without genre).

Response 200
{
  "templates": [
    {
      "id": "v2-thriller-bigtype-house",
      "name": "Big Type Over House",
      "family": "thriller-bigtype-house",
      "templateType": "photographic",
      "genreBuckets": ["Thriller & Mystery:domestic", "Thriller & Mystery:psychological", "Thriller & Mystery:rural"],
      "previewImage": "https://images.beyourcover.com/style-previews/v2/thriller-bigtype-house.png",
      "subgenreMatch": true    // only present when subgenre is in the query
    }
  ],
  "total": 135
}

GET/api/v1/covers/:coverId

Get cover metadata and asset availability. Returns fresh signed URLs for any available assets as a convenience. For stable retrieval, use GET /.../download. No credit charge.

ParamInDescription
coverIdpathUUID of the cover (from generate or variation results)
Response 200
{
  "coverId": "uuid",
  "bookId": "uuid",
  "coverStyle": "cinematic-drama",
  "assets": {
    "preview": {
      "available": true,
      "signedUrl": "https://...",
      "expiresAt": "2025-01-15T11:30:00.000Z"
    },
    "full": {
      "available": false
    },
    "audiobook_preview": {
      "available": false
    },
    "audiobook_full": {
      "available": false
    }
  }
}

Tip: Use this endpoint to inspect which assets exist on a cover and retrieve fresh temporary URLs. For a stable retrieval path, use the asset download endpoint.

Asset types: preview is the standard cover image, full is the upscaled version, audiobook_preview is the square audiobook cover, audiobook_full is the upscaled audiobook cover, no_text is the text-free artwork, and no_text_full is its upscaled version.

GET/api/v1/covers/:coverId/assets/:assetType/download

Download a cover asset. Returns a 302 redirect to a signed URL valid for 1 hour. No credit charge.

ParamInDescription
coverIdpathUUID of the cover
assetTypepathOne of: preview, full, audiobook_preview, audiobook_full
Example
curl -L https://beyourcover.com/api/v1/covers/<coverId>/assets/preview/download \
  -H "Authorization: Bearer byc_sk_your_key" \
  -o cover.png

POST/api/v1/covers/:coverId/variations

Generate new cover variations using the same prompt and style as the source cover. Async job — returns 202.

FieldRequiredDescription
coverIdpathUUID of the source cover
countoptionalNumber of variations (1–5, default 1). Each costs 1 credit.
external_refoptionalYour internal ID
webhookUrloptionalPer-job webhook override
Example Request
curl -X POST https://beyourcover.com/api/v1/covers/<coverId>/variations \
  -H "Authorization: Bearer byc_sk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"count": 3}'
Headers (optional)
Idempotency-Key: unique-request-id
Response 202
{
  "jobId": "uuid",
  "status": "queued",
  "operation": "variation",
  "external_ref": null,
  "created_at": "2025-01-15T10:30:00Z",
  "poll_url": "/api/v1/jobs/uuid"
}
Job Result (when completed)
{
  "sourceCoverId": "uuid",
  "covers": [
    {
      "coverId": "uuid",
      "signedUrl": "https://...",
      "expiresAt": "2025-01-15T11:30:00.000Z",
      "coverStyle": "cinematic-drama"
    }
  ]
}

POST/api/v1/covers/:coverId/edit-image

Edit a cover image using a text prompt. Creates a modified version of the existing cover. Async job — returns 202. Costs 1 credit.

FieldRequiredMaxDescription
coverIdpathUUID of the cover to edit
promptrequired1000Description of the changes to make (e.g. "make the sky more dramatic")
external_refoptionalYour internal ID
webhookUrloptionalPer-job webhook override
Example Request
curl -X POST https://beyourcover.com/api/v1/covers/<coverId>/edit-image \
  -H "Authorization: Bearer byc_sk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"prompt": "Make the background darker and add more stars"}'
Headers (optional)
Idempotency-Key: unique-request-id
Response 202
{
  "jobId": "uuid",
  "status": "queued",
  "operation": "edit_image",
  "external_ref": null,
  "created_at": "2025-01-15T10:30:00Z",
  "poll_url": "/api/v1/jobs/uuid"
}
Job Result (when completed)
{
  "sourceCoverId": "uuid",
  "covers": [
    {
      "coverId": "uuid",
      "signedUrl": "https://...",
      "expiresAt": "2025-01-15T11:30:00.000Z",
      "coverStyle": "cinematic-drama"
    }
  ]
}

POST/api/v1/covers/:coverId/upscale

Upscale a cover asset to high resolution. Async job — returns 202. Free — consumes no credits. Returns 409 if the upscaled version already exists.

FieldRequiredDescription
coverIdpathUUID of the cover
sourceAssetrequiredWhich asset to upscale: preview full, audiobook_preview audiobook_full, or no_text no_text_full
external_refoptionalYour internal ID
webhookUrloptionalPer-job webhook override
Example Request
curl -X POST https://beyourcover.com/api/v1/covers/<coverId>/upscale \
  -H "Authorization: Bearer byc_sk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"sourceAsset": "preview"}'
Headers (optional)
Idempotency-Key: unique-request-id
Response 202
{
  "jobId": "uuid",
  "status": "queued",
  "operation": "upscale",
  "external_ref": null,
  "created_at": "2025-01-15T10:30:00Z",
  "poll_url": "/api/v1/jobs/uuid"
}
Job Result (when completed)
{
  "covers": [
    {
      "coverId": "uuid",
      "asset": "full",
      "signedUrl": "https://...",
      "expiresAt": "2025-01-15T11:30:00.000Z"
    }
  ]
}

POST/api/v1/covers/:coverId/audiobook-cover

Generate a square (1:1) audiobook version of a cover. Async job — returns 202. Costs 1 credit. Requires the cover to have a preview image.

FieldRequiredDescription
coverIdpathUUID of the cover
external_refoptionalYour internal ID
webhookUrloptionalPer-job webhook override
Example Request
curl -X POST https://beyourcover.com/api/v1/covers/<coverId>/audiobook-cover \
  -H "Authorization: Bearer byc_sk_your_key" \
  -H "Content-Type: application/json" \
  -d '{}'
Headers (optional)
Idempotency-Key: unique-request-id
Response 202
{
  "jobId": "uuid",
  "status": "queued",
  "operation": "audiobook_cover",
  "external_ref": null,
  "created_at": "2025-01-15T10:30:00Z",
  "poll_url": "/api/v1/jobs/uuid"
}
Job Result (when completed)
{
  "covers": [
    {
      "coverId": "uuid",
      "asset": "audiobook_preview",
      "signedUrl": "https://...",
      "expiresAt": "2025-01-15T11:30:00.000Z"
    }
  ]
}

POST/api/v1/covers/:coverId/remove-text

Remove all rendered text from a cover — title, author, and every other word — producing the text-free no_text asset on the same cover. The original preview is left untouched. Async job — returns 202. Costs 1 credit. Returns 409 asset_already_exists if the no_text asset already exists, or 409 operation_in_progress if a job for this cover is still running — poll that job rather than starting a second one, which would charge again and overwrite the first result. Upscale the result via the upscale endpoint with sourceAsset: "no_text".

FieldRequiredDescription
coverIdpathUUID of the cover
external_refoptionalYour internal ID
webhookUrloptionalPer-job webhook override
Example Request
curl -X POST https://beyourcover.com/api/v1/covers/<coverId>/remove-text \
  -H "Authorization: Bearer byc_sk_your_key" \
  -H "Content-Type: application/json" \
  -d '{}'
Headers (optional)
Idempotency-Key: unique-request-id
Response 202
{
  "jobId": "uuid",
  "status": "queued",
  "operation": "remove_text",
  "external_ref": null,
  "created_at": "2025-01-15T10:30:00Z",
  "poll_url": "/api/v1/jobs/uuid"
}
Job Result (when completed)
{
  "covers": [
    {
      "coverId": "uuid",
      "asset": "no_text",
      "signedUrl": "https://...",
      "expiresAt": "2025-01-15T11:30:00.000Z"
    }
  ]
}

POST/api/v1/uploads

Presign a reference-image upload. Free — uses no credits. Returns an upload_id and a 5-minute upload_url; PUT the bytes to that URL with the same Content-Type, then pass the upload_id to generate-reference. The storage key is server-generated, and size, dimension, and content-policy checks all run when the upload is consumed — before any credit is reserved.

FieldRequiredDescription
content_typerequiredimage/jpeg, image/png, or image/webp
size_bytesoptionalDeclared size; rejected early when over the limit
Example Request
curl -X POST https://beyourcover.com/api/v1/uploads \
  -H "Authorization: Bearer byc_sk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"content_type": "image/jpeg"}'

# then upload the bytes to the returned URL
curl -X PUT "<upload_url>" \
  -H "Content-Type: image/jpeg" \
  --data-binary @reference.jpg
Response 200
{
  "upload_id": "<user-id>/api-uploads/ref-<uuid>.jpg",
  "upload_url": "https://...",
  "expires_at": "2025-01-15T10:35:00.000Z",
  "max_bytes": 5242880,
  "allowed_types": ["image/jpeg", "image/png", "image/webp"]
}

POST/api/v1/covers/generate-reference

Generate a NEW cover from 1–4 reference images plus art direction. Async job — returns 202. Costs 1 credit. A vision model reads the references and writes a self-contained prompt which the text-to-image chain renders — the image model never receives the reference images, so the result is an original cover in the referenced style. Covers made this way have a null coverStyle (they sit outside the template system).

FieldRequiredDescription
bookIdrequiredThe book the new cover belongs to
instructionsrequiredArt direction (max 1000 chars): what to take from the references, what to change
reference_upload_idsoptionalupload_ids from /api/v1/uploads (1–4 refs total)
reference_cover_idsoptionalcoverIds of existing covers to use as references
external_refoptionalYour internal ID
webhookUrloptionalPer-job webhook override
Example Request
curl -X POST https://beyourcover.com/api/v1/covers/generate-reference \
  -H "Authorization: Bearer byc_sk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "bookId": "<bookId>",
    "instructions": "This palette and the hand-lettered title, but a winter scene",
    "reference_upload_ids": ["<upload_id>"]
  }'
Headers (optional)
Idempotency-Key: unique-request-id
Response 202
{
  "jobId": "uuid",
  "status": "queued",
  "operation": "generate_reference",
  "external_ref": null,
  "created_at": "2025-01-15T10:30:00Z",
  "poll_url": "/api/v1/jobs/uuid"
}
Job Result (when completed)
{
  "bookId": "uuid",
  "covers": [
    {
      "coverId": "uuid",
      "coverStyle": null,
      "prompt": "...",
      "signedUrl": "https://...",
      "expiresAt": "2025-01-15T11:30:00.000Z"
    }
  ]
}

GET/api/v1/wraps/calculate

Print geometry for an Amazon KDP wrap: spine width, the full canvas in inches and pixels at 300 DPI, safe margins, the barcode zone, and whether the spine is thick enough for text. Free, no credits, no side effects — call it before creating a wrap so you know the numbers KDP will check on upload.

Query paramRequiredDescription
trimWidth, trimHeightrequiredTrim size in inches, e.g. 6 × 9
pageCountrequiredInterior pages — this drives spine width
paperTyperequiredwhite | cream | premium_color | standard_color
bindingTypeoptionalpaperback (default) | hardcover
Example Request
curl "https://beyourcover.com/api/v1/wraps/calculate?trimWidth=6&trimHeight=9&pageCount=300&paperType=white" \
  -H "Authorization: Bearer byc_sk_your_key"
Response 200
{
  "spineWidth": 0.6756,
  "fullWidth": 12.9256,
  "fullHeight": 9.25,
  "pixelWidth": 3878,
  "pixelHeight": 2775,
  "dpi": 300,
  "bleed": 0.125,
  "safeTextMargin": 0.125,
  "minFontSize": 7,
  "canHaveSpineText": true,
  "barcodeZone": { "x": 3.75, "y": 7.55, "width": 2, "height": 1.2 }
}

POST/api/v1/wraps

Create a full print wrap (back + spine + front) from an existing cover. Generates back-cover artwork, extends your cover art out to the full front print panel, lays your back-cover copy out on the back, and returns a composited flat, a preview, and a print-ready PDF. Async job — returns 202. Costs 2 credits for a solid back and 4 for the AI art styles. If the job fails before the wrap is created, the full amount is refunded. If it fails after — the wrap is already in your account, listable and free to re-render — the credits stand. Amazon KDP only.

You supply text, not coordinates: a preset places the blocks, auto-fit sizes them to the space available, and the result is checked against the safe margin and the barcode zone. Anything the layout engine had to change comes back in warnings. The layout is saved in the same schema the browser wrap editor uses, so the design opens there for hand adjustment afterwards.

FieldRequiredDescription
coverIdrequiredThe cover to use as the front panel
trimWidth, trimHeight, pageCount, paperTyperequiredSame values as /wraps/calculate — validated identically
designStyleoptionalsolid (2 credits, flat colour, no AI) | textured | continuation (panoramic wrap-around) | complementary (default)
presetoptionalstandard (default: tagline + blurb + bio) | blurb-only | minimal
tagline, blurb, authorBiooptionalBack-cover copy (200 / 2000 / 600 chars). Blocks with no text are omitted.
spineTitle, spineAuthoroptionalSpine lettering. Dropped with a warning when the page count makes the spine too thin.
solidColor, spineColoroptionalHex colours. Omitted, both are sampled from the artwork.
customInstructionsoptionalExtra art direction for the back cover (max 500 chars). Ignored for solid.
bindingTypeoptionalpaperback (default) | hardcover
Example Request
curl -X POST https://beyourcover.com/api/v1/wraps \
  -H "Authorization: Bearer byc_sk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "coverId": "<coverId>",
    "trimWidth": 6,
    "trimHeight": 9,
    "pageCount": 300,
    "paperType": "white",
    "designStyle": "complementary",
    "preset": "standard",
    "tagline": "One town. One lie.",
    "blurb": "When the river froze in November...",
    "spineTitle": "THE THAW",
    "spineAuthor": "M. R. VALE"
  }'
Response 202
{
  "jobId": "uuid",
  "status": "queued",
  "operation": "wrap",
  "credits_reserved": 4,
  "external_ref": null,
  "created_at": "2025-01-15T10:30:00Z",
  "poll_url": "/api/v1/jobs/uuid"
}
Job Result (when completed)
{
  "wrapId": "uuid",
  "bookId": "uuid",
  "coverId": "uuid",
  "designStyle": "complementary",
  "preset": "standard",
  "dims": { "spineWidth": 0.6756, "fullWidth": 12.9256, "fullHeight": 9.25, "...": "..." },
  "layout_report": {
    "blocks": [
      { "id": "tagline", "fontSize": 18, "heightPx": 113, "overflowsPanel": false }
    ],
    "warnings": []
  },
  "warnings": [],
  "assets": {
    "wrap_preview": { "signedUrl": "https://...", "expiresAt": "..." },
    "wrap_flat":    { "signedUrl": "https://...", "expiresAt": "..." },
    "wrap_pdf":     { "signedUrl": "https://...", "expiresAt": "..." }
  }
}

GET/api/v1/wraps/{wrapId}

Fetch a wrap with fresh one-hour signed URLs on every asset, plus its layout_state. Wraps created in the browser wrap editor are readable here too — there is one wrap per design, whichever surface made it.

Response 200
{
  "wrapId": "uuid",
  "bookId": "uuid",
  "designName": "API",
  "designStyle": "complementary",
  "trimWidth": 6,
  "trimHeight": 9,
  "pageCount": 300,
  "spineWidth": 0.6756,
  "layout_state": { "textBlocks": [ ... ], "spineRotation": 90, "...": "..." },
  "assets": {
    "wrap_preview": { "signedUrl": "https://...", "expiresAt": "..." },
    "wrap_flat":    { "signedUrl": "https://...", "expiresAt": "..." },
    "wrap_pdf":     { "signedUrl": "https://...", "expiresAt": "..." },
    "back_art":     { "signedUrl": "https://...", "expiresAt": "..." }
  }
}

POST/api/v1/wraps/{wrapId}/render

Re-typeset an existing wrap on the artwork it already has. Free and synchronous — no model runs, so it returns 200 with the new assets instead of a job to poll. Fixing a typo in a blurb should not cost a second wrap.

Send the text fields to re-run a preset, or send a complete layoutState (as returned by GET /wraps/{wrapId}) to render a layout you positioned yourself.

Example Request
curl -X POST https://beyourcover.com/api/v1/wraps/<wrapId>/render \
  -H "Authorization: Bearer byc_sk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "preset": "blurb-only",
    "blurb": "A tighter, shorter blurb.",
    "spineTitle": "THE THAW"
  }'
Response 200
{
  "wrapId": "uuid",
  "bookId": "uuid",
  "dims": { "...": "..." },
  "layout_report": { "blocks": [ ... ], "warnings": [] },
  "warnings": [],
  "assets": {
    "wrap_preview": { "signedUrl": "https://...", "expiresAt": "..." },
    "wrap_flat":    { "signedUrl": "https://...", "expiresAt": "..." },
    "wrap_pdf":     { "signedUrl": "https://...", "expiresAt": "..." }
  }
}

POST/api/v1/wraps/{wrapId}/extend-front

Re-run the AI extension of the front panel and recompose the wrap with its existing back artwork and layout. Free — the wrap was already paid for — but it runs an AI chain, so it returns 202 with a job to poll. Use it when the extended front came back with a visible seam, a framed-picture look, or an unfilled band (the wrap job reports the last of those as a front_outpaint_incomplete warning). Each run is a fresh roll of the model, exactly like the wrap editor's "re-extend front".

Example Request
curl -X POST https://beyourcover.com/api/v1/wraps/<wrapId>/extend-front \
  -H "Authorization: Bearer byc_sk_your_key"
Response 202
{
  "jobId": "uuid",
  "status": "queued",
  "operation": "wrap_extend_front",
  "credits_reserved": 0,
  "poll_url": "/api/v1/jobs/uuid"
}

Agent endpoints (account & discovery)

Read-only helpers so agents and integrations can inspect account state without side effects. All require authentication, consume no credits, and use the standard error envelope. List endpoints return newest-first with opaque cursor pagination: pass the returned next_cursor back as ?cursor= to fetch the next page (null means no more results).

GET/api/v1/credits

Current credit balance, plan tier, and concurrency limit for the authenticated subscription. Check this before large batches. Insufficient-credit errors on generation also carry error.details (balance, required, billing_url).

Response 200
{
  "tier": "growth",
  "credits_remaining": 120,   // unused monthly credits
  "credits_monthly": 500,     // monthly allowance at renewal
  "overage_credits": 30,      // purchased overage
  "total_available": 150,     // credits_remaining + overage_credits
  "concurrent_limit": 10,     // max queued/processing jobs at once
  "is_active": true,
  "billing_url": "https://beyourcover.com/enterprise-dashboard"
}

GET/api/v1/capabilities

Machine-readable generation coverage and pricing. The genres array reports, per genre and subgenre, exactly what the generator will accept — a request for an unsupported pair returns 422 unsupported_genre. The coverage is derived from the same routing logic the generate endpoint uses, so it never over-promises.

Response 200 (abridged)
{
  "api_version": "v1",
  "generation_engine": "v2",
  "genres": [
    {
      "genre": "Romance",
      "slug": "romance",
      "supported": true,
      "subgenre_auto_detected": true,   // detected from title/summary if omitted
      "subgenres": [
        { "value": "contemporary", "label": "Contemporary Romance", "supported": true },
        { "value": "romantasy",    "label": "Romantasy",            "supported": true }
      ]
    },
    { "genre": "Poetry", "slug": "poetry", "supported": false, "subgenre_auto_detected": false, "subgenres": [] }
  ],
  "operations": {
    "generate":        { "credits_per_image": 1, "description": "..." },
    "variation":       { "credits_per_image": 1, "description": "..." },
    "edit_image":      { "credits_per_image": 1, "description": "..." },
    "audiobook_cover": { "credits_per_image": 1, "description": "..." },
    "upscale":         { "credits_per_image": 0, "description": "Free." }
  },
  "limits": { "max_covers_per_generate": 5 },
  "coverage_note": "..."
}

GET/api/v1/jobs

List your jobs, newest first. Result payloads are omitted here — poll GET /api/v1/jobs/:jobId for signed cover URLs. Optional status and operation filters.

Query Parameters
?status=queued|processing|completed|failed   // optional
?operation=generate|variation|edit_image|upscale|audiobook_cover  // optional
?limit=20      // optional, 1–100 (default 20)
?cursor=<opaque>   // optional, from a previous next_cursor
Response 200
{
  "jobs": [
    {
      "jobId": "uuid",
      "status": "completed",
      "operation": "generate",
      "external_ref": "gen-001",
      "credits_used": 2,
      "bookId": "uuid",
      "error": null,
      "created_at": "...",
      "started_at": "...",
      "completed_at": "...",
      "poll_url": "/api/v1/jobs/uuid"
    }
  ],
  "next_cursor": "eyJjIjoi…"   // null on the last page
}

Errors: 400 invalid_status_filter, 400 invalid_operation_filter, 400 invalid_limit, 400 invalid_cursor.

GET/api/v1/books

List books owned by your account, newest first — so an agent can resume work on an existing book without recreating it. (The POST on this path creates a book.)

Query Parameters
?limit=20          // optional, 1–100 (default 20)
?cursor=<opaque>   // optional, from a previous next_cursor
Response 200
{
  "books": [
    {
      "bookId": "uuid",
      "title": "My Novel",
      "author": "Jane Doe",
      "subtitle": null,
      "genre": "Contemporary Fiction",   // canonical value
      "subgenre": "book-club",
      "summary": "...",
      "target_audience": null,
      "created_at": "..."
    }
  ],
  "next_cursor": null
}

GET/api/v1/books/:bookId/covers

List every cover generated for a book (newest first). Each entry exposes its public coverId plus per-asset availability flags. No signed URLs here — fetch those from GET /api/v1/covers/:coverId or the download endpoint.

Query Parameters
?limit=100   // optional, 1–200 (default 100)
Response 200
{
  "bookId": "uuid",
  "covers": [
    {
      "coverId": "uuid",                  // cover's public_id
      "coverStyle": "v2-thriller-house-bigtype",
      "created_at": "...",
      "assets": {
        "preview":           { "available": true },
        "full":              { "available": true },   // present after upscale
        "audiobook_preview": { "available": false },
        "audiobook_full":    { "available": false }
      }
    }
  ],
  "total": 1
}

Errors: 404 book_not_found (missing or not owned by your key), 400 invalid_limit.

Genres & Subgenres

Use these values for the genre and subgenre fields when creating a book. Genre is required; subgenre is optional — if you omit it for a genre that uses subgenres, one is auto-detected from your title and summary when the book is created (see POST /books). All genre and subgenre values are case-sensitive and must be sent exactly as shown.

Available Genres

Value (slug)Description
business-economicsBusiness & Economics
religion-spiritualityReligion & Spirituality
non-fictionNon-Fiction
fantasyFantasy
romanceRomance
thrillerThriller
mysteryMystery
science-fictionScience Fiction
horrorHorror
historical-fictionHistorical Fiction
health-fitnessHealth & Fitness
contemporary-fictionContemporary Fiction
young-adultYoung Adult
childrensChildren's
self-helpSelf-Help & Personal Development
biography-memoirBiography & Memoir
poetryPoetry
planner-journalPlanner & Journal

romance Subgenres

ValueLabel
contemporaryContemporary Romance
romantasyRomantasy
new-adultNew Adult Romance
dark-romanceDark Romance
sportsSports Romance
romantic-suspenseRomantic Suspense
eroticErotic Romance
paranormal-monsterParanormal & Monster Romance
historical-romanceHistorical Romance
small-townSmall Town Romance
clean-sweetClean & Sweet Romance
romcomRomantic Comedy

fantasy Subgenres

ValueLabel
romantasyRomantasy
epic-fantasyEpic & High Fantasy
dystopianDystopian
dark-fantasyDark Fantasy & Horror
cozy-fantasyCozy Fantasy
grimdarkGrimdark
litrpgLitRPG & Progression
dark-academiaDark Academia Fantasy
myth-folkloreMyth & Folklore Retellings
contemporary-urbanContemporary & Urban Fantasy
grounded-lowGrounded & Low Fantasy

children's Subgenres

ValueLabel
picture-bookPicture Book
early-readerEarly Reader
chapter-bookChapter Book
middle-gradeMiddle Grade
otherOther

thriller Subgenres

ValueLabel
cozyCozy Mystery
domesticDomestic Thriller
psychologicalPsychological Thriller
legalLegal Thriller
politicalPolitical Thriller
proceduralPolice Procedural
dark-academiaDark Academia Thriller
ruralRural / Small-Town
true-crimeTrue Crime Fiction
technoTechno-Thriller
espionageEspionage / Spy

mystery Subgenres

ValueLabel
cozyCozy Mystery
domesticDomestic Thriller
psychologicalPsychological Thriller
legalLegal Thriller
politicalPolitical Thriller
proceduralPolice Procedural
dark-academiaDark Academia Thriller
ruralRural / Small-Town
true-crimeTrue Crime Fiction
technoTechno-Thriller
espionageEspionage / Spy

biography & memoir Subgenres

ValueLabel
literaryLiterary Memoir
historicalHistorical Biography
inspirationalInspirational & Recovery
culturalCultural & Travel

contemporary fiction Subgenres

ValueLabel
book-clubBook Club / Upmarket
womens-fictionWomen's Fiction
family-sagaFamily Saga
humorousHumorous & Satirical

historical fiction Subgenres

ValueLabel
historical-fictionHistorical Fiction

planner & journal Subgenres

ValueLabel
productivityProductivity & Business
wellnessWellness & Gratitude
budgetBudget & Finance
fitnessFitness & Health
minimalistMinimalist Notebook
feminineFeminine Lifestyle
faithFaith & Christian
goal-settingGoal-Setting & Vision

science fiction Subgenres

ValueLabel
space-operaSpace Opera
dystopianDystopian / Post-Apocalyptic
hard-sfHard Sci-Fi
litrpgLitRPG / Progression
cyberpunkCyberpunk / Cli-Fi

horror Subgenres

ValueLabel
gothicGothic Horror
cosmicCosmic / Lovecraftian
supernaturalSupernatural / Ghost Story
slasherSlasher / Splatterpunk
psychologicalPsychological Horror
folkFolk Horror
bodyBody Horror
dark-fantasyDark Fantasy Horror

self-help & personal development Subgenres

ValueLabel
self-helpSelf-Help

business & economics Subgenres

ValueLabel
businessBusiness

religion & spirituality Subgenres

ValueLabel
religionReligion & Spirituality

health & fitness Subgenres

ValueLabel
health-fitnessHealth & Fitness
Example: Book with subgenre
{
  "title": "Crown of Shadows",
  "author": "Elena Blackwood",
  "genre": "fantasy",
  "subgenre": "dark-fantasy",
  "summary": "A disgraced knight seeks redemption..."
}

Webhooks

Configure a webhook URL in your dashboard to receive job completion notifications. You can also override the URL per-job via the webhookUrl field in the generate request. Payloads are signed with HMAC-SHA256.

Webhook Header
X-BYC-Signature: sha256=<hmac_hex_digest>
Verification (Node.js)
import crypto from 'crypto';

function verifyWebhook(body, signature, secret) {
  const expected = 'sha256=' +
    crypto.createHmac('sha256', secret)
      .update(body)
      .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}
Webhook Payload (generate / variation)
{
  "event": "job.completed",
  "jobId": "uuid",
  "external_ref": "gen-001",
  "status": "completed",
  "timestamp": "2025-01-15T10:32:00Z",
  "data": {
    "bookId": "uuid",
    "covers": [
      {
        "coverId": "uuid",
        "signedUrl": "https://...",
        "expiresAt": "2025-01-15T11:32:00.000Z",
        "coverStyle": "template-name",
        "prompt": "A dark, moody book cover featuring..."
      }
    ]
  }
}
Webhook Payload (edit_image)
{
  "event": "job.completed",
  "jobId": "uuid",
  "status": "completed",
  "timestamp": "2025-01-15T10:32:00Z",
  "data": {
    "sourceCoverId": "uuid",
    "covers": [
      {
        "coverId": "uuid",
        "signedUrl": "https://...",
        "expiresAt": "2025-01-15T11:32:00.000Z",
        "coverStyle": "template-name",
        "prompt": "A dark, moody book cover featuring..."
      }
    ]
  }
}
Webhook Payload (upscale / audiobook_cover)
{
  "event": "job.completed",
  "jobId": "uuid",
  "status": "completed",
  "timestamp": "2025-01-15T10:32:00Z",
  "data": {
    "covers": [
      {
        "coverId": "uuid",
        "asset": "full",
        "signedUrl": "https://...",
        "expiresAt": "2025-01-15T11:32:00.000Z"
      }
    ]
  }
}

Important: Webhook image URLs also expire after 1 hour. Download or cache images on your servers as soon as you receive the webhook. If a URL has expired, poll the job endpoint to get a fresh one.

Errors

All errors return a structured JSON object with a code and message.

Error Response Format
{
  "error": {
    "code": "insufficient_credits",
    "message": "Insufficient credits. Need 3, have 1 (0 monthly + 1 overage)."
  }
}
StatusCodeMeaning
400missing_required_fieldsRequired fields are missing from the request body
400missing_book_idbookId is required for cover generation
400invalid_countcount must be an integer between 1 and 5
400invalid_genreGenre value not recognized
400invalid_template_idtemplateId is not a valid template — see GET /templates
400unsupported_charactersText fields contain unsupported characters (Arabic, Hindi)
400field_too_longOne or more fields exceed their maximum length
400invalid_field_typeA field has the wrong type (expected string)
400invalid_field_valueA field value is not in the allowed set (e.g. mood, target_audience)
400content_policy_violationContent violates the content policy
400missing_promptEdit image requires a non-empty prompt
400missing_cover_imageCover has no preview image (required for edit/audiobook)
400invalid_source_assetsourceAsset must be "preview" or "audiobook_preview"
401unauthorizedInvalid or missing API key
402insufficient_creditsNot enough credits for this operation
403forbiddenNo active enterprise subscription for this key
404book_not_foundBook not found or doesn't belong to your account
404cover_not_foundCover not found or doesn't belong to your account
404asset_not_availableThe requested asset has not been generated yet (download or upscale of a missing asset)
404job_not_foundJob not found or doesn't belong to your account
409asset_already_existsThe upscaled version already exists for this cover
422unsupported_genreThe book's genre/subgenre is not supported for generation (e.g. a genre that uses subgenres with none set). No credits are charged.
429concurrency_limitToo many concurrent jobs running
500internal_errorInternal server error

Full Example

End-to-end flow (curl)
# 1. Create a book
curl -X POST https://beyourcover.com/api/v1/books \
  -H "Authorization: Bearer byc_sk_your_key" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: book-001" \
  -d '{"title":"My Novel","author":"Jane","genre":"fantasy"}'

# 2. Generate covers
curl -X POST https://beyourcover.com/api/v1/covers/generate \
  -H "Authorization: Bearer byc_sk_your_key" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: req-001" \
  -d '{"bookId":"<bookId>","count":3}'

# 3. Poll for results
curl https://beyourcover.com/api/v1/jobs/<jobId> \
  -H "Authorization: Bearer byc_sk_your_key"

# 4. Get cover metadata
curl https://beyourcover.com/api/v1/covers/<coverId> \
  -H "Authorization: Bearer byc_sk_your_key"

# 5. Edit a cover
curl -X POST https://beyourcover.com/api/v1/covers/<coverId>/edit-image \
  -H "Authorization: Bearer byc_sk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"prompt":"Make the sky more dramatic"}'

# 6. Upscale to high resolution
curl -X POST https://beyourcover.com/api/v1/covers/<coverId>/upscale \
  -H "Authorization: Bearer byc_sk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"sourceAsset":"preview"}'

# 7. Download the upscaled image
curl -L https://beyourcover.com/api/v1/covers/<coverId>/assets/full/download \
  -H "Authorization: Bearer byc_sk_your_key" \
  -o cover-hd.png

Frequently Asked Questions

What is the BeYourCover Book Cover Generation API?

The BeYourCover API is a REST API that lets you generate professional AI book covers programmatically. You send book details (title, author, genre, summary) and receive high-quality cover images. It supports generation, editing, variations, upscaling, and audiobook covers.

What programming languages can I use with the API?

The API uses standard REST conventions with JSON payloads, so it works with any language that can make HTTP requests — Python, JavaScript/Node.js, Ruby, PHP, Go, Java, C#, and more. All you need is an HTTP client and your API key.

How does API pricing work?

API plans start at $79/month for 150 credits (Starter), with Growth ($199/mo, 500 credits) and Scale ($399/mo, 1,500 credits) tiers available. Each cover generation, edit, variation, text removal, or audiobook cover costs 1 credit per image; upscales are free. Overage credits are available on all plans.

Can I generate book covers in bulk?

Yes. The API supports concurrent requests (5–20 depending on your plan) and asynchronous job processing. You can submit multiple generation requests and poll or use webhooks to collect results. This makes it ideal for batch processing entire book catalogs.

What book cover formats and sizes does the API support?

The API generates standard ebook covers (vertical aspect ratio) and square audiobook covers (1:1). You can also create a text-free version of any cover (all rendered text removed — useful for audiobook platforms and A+ content) and upscale any asset to high resolution for print-ready quality. Downloads are available as PNG files via signed URLs.

How do I get started with the API?

Sign up for an API plan on the Enterprise Plans page, get your API key from the Account Dashboard, and make your first request. The documentation on this page covers authentication, all 23 endpoints, webhooks, and includes a complete curl example.

Can AI agents like Claude use the API?

Yes. BeYourCover runs a remote MCP (Model Context Protocol) server at https://beyourcover.com/api/mcp/mcp over Streamable HTTP, authenticated with the same Bearer API keys. It exposes task-shaped tools for creating books, generating covers, polling jobs, checking credits, listing your books and their covers, downloading covers, upscaling to print resolution, editing covers with text instructions, removing all rendered text for text-free versions, creating audiobook covers, calculating KDP print-wrap dimensions, and building a complete print wrap — back artwork, typeset back-cover copy, spine and extended front panel — that comes back as a KDP-ready PDF, so MCP-capable agents can take a paperback from idea to upload without opening the editor. There is also a machine-readable capabilities endpoint, an OpenAPI 3.1 spec, an llms.txt, an RFC 9727 API catalog at /.well-known/api-catalog that indexes every API here with its spec, docs and health endpoint, and an auth.md guide at /auth.md that walks an agent through obtaining a credential. Every public page also does Markdown content negotiation: send Accept: text/markdown and you get the page as clean Markdown with frontmatter instead of HTML, so an agent reading the blog, the product guides, the genre pages or the marketplace never has to scrape a layout.

Do you support webhooks?

Yes. The API sends HMAC-SHA256 signed webhook events when jobs complete, so you don't need to poll. You can configure a default webhook URL in your dashboard and optionally override it per-job.

Can I use the API for a white-label product?

Yes. The API gives you control over the generation pipeline so you can integrate cover generation into your own product. You remain responsible for reviewing outputs, rights clearance, and any claims you make to your end users about the final files.

Start Building with the Book Cover API

Get your API key and generate your first cover in minutes. Plans start at $79/month with 150 credits.