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.
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
Create a Book
Send title, author, genre, and a summary to POST /books. The summary helps the AI generate relevant imagery.
Generate Covers
Call POST /generate with your book ID. Get up to 5 AI-generated covers per request, delivered via polling or webhooks.
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.
- Create a book — only
title,author, andgenreare required. - Generate a cover — pass the
bookId. Returns a job ID. - Poll the job until
statusiscompleted. - Download the cover from the asset download endpoint.
# 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.pngTip: 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.
Authorization: Bearer byc_sk_your_api_key_hereRate Limits
| Plan | Credits/mo | Concurrent Jobs |
|---|---|---|
| Starter | 150 | 5 |
| Growth | 500 | 10 |
| Scale | 1,500 | 20 |
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 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:
{
"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:
Connector URL: https://beyourcover.com/api/mcp/mcpThe 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:
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.
curl https://beyourcover.com/auth.md
curl https://beyourcover.com/.well-known/oauth-protected-resourceMarkdown 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.
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.mdGET /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.
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.
| Field | Required | Max | Description |
|---|---|---|---|
title | required | 100 | Book title |
author | required* | 100 | Author name. *Optional when genre is planner-journal — planner covers typically lead with a brand wordmark and omit the author. |
genre | required | — | Genre slug — see Genres section |
subtitle | optional | 300 | Book subtitle |
subgenre | optional | 100 | Subgenre (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. |
summary | recommended | 1000 | Book synopsis — strongly recommended, used by the AI to create relevant imagery |
target_audience | optional | — | Restricted values: children, middle-grade, young-adult, new-adult, adult |
external_ref | optional | 200 | Your internal ID — echoed back in responses |
planner_year | optional | — | Free-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.
{
"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"
}{
"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"
}Idempotency-Key: unique-request-id{
"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.
| Field | Required | Max | Description |
|---|---|---|---|
bookId | required | — | UUID of the book created via POST /api/v1/books |
count | optional | — | Number of covers to generate. Integer 1–5, default 1. Each cover costs 1 credit. |
templateId | optional | — | Template 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. |
prompt | optional | 1500 | Free-text prompt or instructions for the cover. Short text is treated as visual elements and enhanced by our AI. |
mood | optional | — | Restricted values: intense, mysterious, romantic, intellectual, uplifting, epic, melancholic |
colorPalette | optional | — | Restricted values: monochrome, pastel, earth, muted, dark, bold, warm, cool, metallic, duotone |
external_ref | optional | 200 | Your internal ID — echoed back in responses and webhooks |
webhookUrl | optional | 500 | Per-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.
{
"bookId": "550e8400-e29b-41d4-a716-446655440000",
"count": 3,
"mood": "intellectual",
"colorPalette": "muted"
}Idempotency-Key: unique-request-id{
"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.
{
"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.
?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=romantasysubgenre 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).
{
"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.
| Param | In | Description |
|---|---|---|
coverId | path | UUID of the cover (from generate or variation results) |
{
"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.
| Param | In | Description |
|---|---|---|
coverId | path | UUID of the cover |
assetType | path | One of: preview, full, audiobook_preview, audiobook_full |
curl -L https://beyourcover.com/api/v1/covers/<coverId>/assets/preview/download \
-H "Authorization: Bearer byc_sk_your_key" \
-o cover.pngPOST/api/v1/covers/:coverId/variations
Generate new cover variations using the same prompt and style as the source cover. Async job — returns 202.
| Field | Required | Description |
|---|---|---|
coverId | path | UUID of the source cover |
count | optional | Number of variations (1–5, default 1). Each costs 1 credit. |
external_ref | optional | Your internal ID |
webhookUrl | optional | Per-job webhook override |
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}'Idempotency-Key: unique-request-id{
"jobId": "uuid",
"status": "queued",
"operation": "variation",
"external_ref": null,
"created_at": "2025-01-15T10:30:00Z",
"poll_url": "/api/v1/jobs/uuid"
}{
"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.
| Field | Required | Max | Description |
|---|---|---|---|
coverId | path | — | UUID of the cover to edit |
prompt | required | 1000 | Description of the changes to make (e.g. "make the sky more dramatic") |
external_ref | optional | — | Your internal ID |
webhookUrl | optional | — | Per-job webhook override |
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"}'Idempotency-Key: unique-request-id{
"jobId": "uuid",
"status": "queued",
"operation": "edit_image",
"external_ref": null,
"created_at": "2025-01-15T10:30:00Z",
"poll_url": "/api/v1/jobs/uuid"
}{
"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.
| Field | Required | Description |
|---|---|---|
coverId | path | UUID of the cover |
sourceAsset | required | Which asset to upscale: preview → full, audiobook_preview → audiobook_full, or no_text → no_text_full |
external_ref | optional | Your internal ID |
webhookUrl | optional | Per-job webhook override |
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"}'Idempotency-Key: unique-request-id{
"jobId": "uuid",
"status": "queued",
"operation": "upscale",
"external_ref": null,
"created_at": "2025-01-15T10:30:00Z",
"poll_url": "/api/v1/jobs/uuid"
}{
"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.
| Field | Required | Description |
|---|---|---|
coverId | path | UUID of the cover |
external_ref | optional | Your internal ID |
webhookUrl | optional | Per-job webhook override |
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 '{}'Idempotency-Key: unique-request-id{
"jobId": "uuid",
"status": "queued",
"operation": "audiobook_cover",
"external_ref": null,
"created_at": "2025-01-15T10:30:00Z",
"poll_url": "/api/v1/jobs/uuid"
}{
"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".
| Field | Required | Description |
|---|---|---|
coverId | path | UUID of the cover |
external_ref | optional | Your internal ID |
webhookUrl | optional | Per-job webhook override |
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 '{}'Idempotency-Key: unique-request-id{
"jobId": "uuid",
"status": "queued",
"operation": "remove_text",
"external_ref": null,
"created_at": "2025-01-15T10:30:00Z",
"poll_url": "/api/v1/jobs/uuid"
}{
"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.
| Field | Required | Description |
|---|---|---|
content_type | required | image/jpeg, image/png, or image/webp |
size_bytes | optional | Declared size; rejected early when over the limit |
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{
"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).
| Field | Required | Description |
|---|---|---|
bookId | required | The book the new cover belongs to |
instructions | required | Art direction (max 1000 chars): what to take from the references, what to change |
reference_upload_ids | optional | upload_ids from /api/v1/uploads (1–4 refs total) |
reference_cover_ids | optional | coverIds of existing covers to use as references |
external_ref | optional | Your internal ID |
webhookUrl | optional | Per-job webhook override |
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>"]
}'Idempotency-Key: unique-request-id{
"jobId": "uuid",
"status": "queued",
"operation": "generate_reference",
"external_ref": null,
"created_at": "2025-01-15T10:30:00Z",
"poll_url": "/api/v1/jobs/uuid"
}{
"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 param | Required | Description |
|---|---|---|
trimWidth, trimHeight | required | Trim size in inches, e.g. 6 × 9 |
pageCount | required | Interior pages — this drives spine width |
paperType | required | white | cream | premium_color | standard_color |
bindingType | optional | paperback (default) | hardcover |
curl "https://beyourcover.com/api/v1/wraps/calculate?trimWidth=6&trimHeight=9&pageCount=300&paperType=white" \
-H "Authorization: Bearer byc_sk_your_key"{
"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.
| Field | Required | Description |
|---|---|---|
coverId | required | The cover to use as the front panel |
trimWidth, trimHeight, pageCount, paperType | required | Same values as /wraps/calculate — validated identically |
designStyle | optional | solid (2 credits, flat colour, no AI) | textured | continuation (panoramic wrap-around) | complementary (default) |
preset | optional | standard (default: tagline + blurb + bio) | blurb-only | minimal |
tagline, blurb, authorBio | optional | Back-cover copy (200 / 2000 / 600 chars). Blocks with no text are omitted. |
spineTitle, spineAuthor | optional | Spine lettering. Dropped with a warning when the page count makes the spine too thin. |
solidColor, spineColor | optional | Hex colours. Omitted, both are sampled from the artwork. |
customInstructions | optional | Extra art direction for the back cover (max 500 chars). Ignored for solid. |
bindingType | optional | paperback (default) | hardcover |
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"
}'{
"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"
}{
"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.
{
"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.
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"
}'{
"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".
curl -X POST https://beyourcover.com/api/v1/wraps/<wrapId>/extend-front \
-H "Authorization: Bearer byc_sk_your_key"{
"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).
{
"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.
{
"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.
?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{
"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.)
?limit=20 // optional, 1–100 (default 20)
?cursor=<opaque> // optional, from a previous next_cursor{
"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.
?limit=100 // optional, 1–200 (default 100){
"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-economics | Business & Economics |
religion-spirituality | Religion & Spirituality |
non-fiction | Non-Fiction |
fantasy | Fantasy |
romance | Romance |
thriller | Thriller |
mystery | Mystery |
science-fiction | Science Fiction |
horror | Horror |
historical-fiction | Historical Fiction |
health-fitness | Health & Fitness |
contemporary-fiction | Contemporary Fiction |
young-adult | Young Adult |
childrens | Children's |
self-help | Self-Help & Personal Development |
biography-memoir | Biography & Memoir |
poetry | Poetry |
planner-journal | Planner & Journal |
romance Subgenres
| Value | Label |
|---|---|
contemporary | Contemporary Romance |
romantasy | Romantasy |
new-adult | New Adult Romance |
dark-romance | Dark Romance |
sports | Sports Romance |
romantic-suspense | Romantic Suspense |
erotic | Erotic Romance |
paranormal-monster | Paranormal & Monster Romance |
historical-romance | Historical Romance |
small-town | Small Town Romance |
clean-sweet | Clean & Sweet Romance |
romcom | Romantic Comedy |
fantasy Subgenres
| Value | Label |
|---|---|
romantasy | Romantasy |
epic-fantasy | Epic & High Fantasy |
dystopian | Dystopian |
dark-fantasy | Dark Fantasy & Horror |
cozy-fantasy | Cozy Fantasy |
grimdark | Grimdark |
litrpg | LitRPG & Progression |
dark-academia | Dark Academia Fantasy |
myth-folklore | Myth & Folklore Retellings |
contemporary-urban | Contemporary & Urban Fantasy |
grounded-low | Grounded & Low Fantasy |
children's Subgenres
| Value | Label |
|---|---|
picture-book | Picture Book |
early-reader | Early Reader |
chapter-book | Chapter Book |
middle-grade | Middle Grade |
other | Other |
thriller Subgenres
| Value | Label |
|---|---|
cozy | Cozy Mystery |
domestic | Domestic Thriller |
psychological | Psychological Thriller |
legal | Legal Thriller |
political | Political Thriller |
procedural | Police Procedural |
dark-academia | Dark Academia Thriller |
rural | Rural / Small-Town |
true-crime | True Crime Fiction |
techno | Techno-Thriller |
espionage | Espionage / Spy |
mystery Subgenres
| Value | Label |
|---|---|
cozy | Cozy Mystery |
domestic | Domestic Thriller |
psychological | Psychological Thriller |
legal | Legal Thriller |
political | Political Thriller |
procedural | Police Procedural |
dark-academia | Dark Academia Thriller |
rural | Rural / Small-Town |
true-crime | True Crime Fiction |
techno | Techno-Thriller |
espionage | Espionage / Spy |
biography & memoir Subgenres
| Value | Label |
|---|---|
literary | Literary Memoir |
historical | Historical Biography |
inspirational | Inspirational & Recovery |
cultural | Cultural & Travel |
contemporary fiction Subgenres
| Value | Label |
|---|---|
book-club | Book Club / Upmarket |
womens-fiction | Women's Fiction |
family-saga | Family Saga |
humorous | Humorous & Satirical |
historical fiction Subgenres
| Value | Label |
|---|---|
historical-fiction | Historical Fiction |
planner & journal Subgenres
| Value | Label |
|---|---|
productivity | Productivity & Business |
wellness | Wellness & Gratitude |
budget | Budget & Finance |
fitness | Fitness & Health |
minimalist | Minimalist Notebook |
feminine | Feminine Lifestyle |
faith | Faith & Christian |
goal-setting | Goal-Setting & Vision |
science fiction Subgenres
| Value | Label |
|---|---|
space-opera | Space Opera |
dystopian | Dystopian / Post-Apocalyptic |
hard-sf | Hard Sci-Fi |
litrpg | LitRPG / Progression |
cyberpunk | Cyberpunk / Cli-Fi |
horror Subgenres
| Value | Label |
|---|---|
gothic | Gothic Horror |
cosmic | Cosmic / Lovecraftian |
supernatural | Supernatural / Ghost Story |
slasher | Slasher / Splatterpunk |
psychological | Psychological Horror |
folk | Folk Horror |
body | Body Horror |
dark-fantasy | Dark Fantasy Horror |
self-help & personal development Subgenres
| Value | Label |
|---|---|
self-help | Self-Help |
business & economics Subgenres
| Value | Label |
|---|---|
business | Business |
religion & spirituality Subgenres
| Value | Label |
|---|---|
religion | Religion & Spirituality |
health & fitness Subgenres
| Value | Label |
|---|---|
health-fitness | Health & Fitness |
{
"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.
X-BYC-Signature: sha256=<hmac_hex_digest>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)
);
}{
"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..."
}
]
}
}{
"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..."
}
]
}
}{
"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": {
"code": "insufficient_credits",
"message": "Insufficient credits. Need 3, have 1 (0 monthly + 1 overage)."
}
}| Status | Code | Meaning |
|---|---|---|
| 400 | missing_required_fields | Required fields are missing from the request body |
| 400 | missing_book_id | bookId is required for cover generation |
| 400 | invalid_count | count must be an integer between 1 and 5 |
| 400 | invalid_genre | Genre value not recognized |
| 400 | invalid_template_id | templateId is not a valid template — see GET /templates |
| 400 | unsupported_characters | Text fields contain unsupported characters (Arabic, Hindi) |
| 400 | field_too_long | One or more fields exceed their maximum length |
| 400 | invalid_field_type | A field has the wrong type (expected string) |
| 400 | invalid_field_value | A field value is not in the allowed set (e.g. mood, target_audience) |
| 400 | content_policy_violation | Content violates the content policy |
| 400 | missing_prompt | Edit image requires a non-empty prompt |
| 400 | missing_cover_image | Cover has no preview image (required for edit/audiobook) |
| 400 | invalid_source_asset | sourceAsset must be "preview" or "audiobook_preview" |
| 401 | unauthorized | Invalid or missing API key |
| 402 | insufficient_credits | Not enough credits for this operation |
| 403 | forbidden | No active enterprise subscription for this key |
| 404 | book_not_found | Book not found or doesn't belong to your account |
| 404 | cover_not_found | Cover not found or doesn't belong to your account |
| 404 | asset_not_available | The requested asset has not been generated yet (download or upscale of a missing asset) |
| 404 | job_not_found | Job not found or doesn't belong to your account |
| 409 | asset_already_exists | The upscaled version already exists for this cover |
| 422 | unsupported_genre | The book's genre/subgenre is not supported for generation (e.g. a genre that uses subgenres with none set). No credits are charged. |
| 429 | concurrency_limit | Too many concurrent jobs running |
| 500 | internal_error | Internal server error |
Full Example
# 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.pngFrequently Asked Questions
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.
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.
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.
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.
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.
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.
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.
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.
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.