BeYourCover Books API
The Books API from BeYourCover — 3 operation(s) for books.
The Books API from BeYourCover — 3 operation(s) for books.
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
find_apisBrowse and filter every API in the catalog.get_api_artifactsOne API's artifacts, grouped by type.get_openapiThe primary OpenAPI for this API.find_similar_apisAPIs that look like this one.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.curl "https://apis.io/api/v1/apis/beyourcover-com:beyourcover-com-books-api"
curl "https://apis.io/api/v1/apis?limit=25"
Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: BeYourCover Partner Books API
version: 1.1.0
description: 'Enterprise/partner REST API for AI-powered book cover generation: covers from book details or from reference images, variations, edits, replacing a person with a photo, text removal, upscales, audiobook covers, and full print wraps for Amazon KDP with a print-ready PDF. Every endpoint except `GET /api/v1/health` requires a partner API key (`Authorization: Bearer byc_sk_...`). Long-running operations (generation, reference-image generation, variations, edits, replacing a person, text removal, upscales, audiobook covers, print wraps and a wrap''s front-panel re-extension) return `202 Accepted` with a job envelope; poll `GET /api/v1/jobs/{jobId}` or receive a webhook. Re-typesetting a wrap (`POST /api/v1/wraps/{wrapId}/render`) runs no model, so it answers `200` directly. All error responses use a uniform envelope: `{ "error": { "code": string, "message": string } }`.'
servers:
- url: https://beyourcover.com
description: Production. All paths below are relative to the site origin.
security:
- ApiKeyBearer: []
tags:
- name: Books
paths:
/api/v1/books:
post:
tags:
- Books
operationId: createBook
summary: Create a book record
description: 'Creates a book that covers can be generated against. `author` is required unless `genre` is `Planner & Journal` / `planner-journal` or `Puzzles, Coloring & Activity` / `puzzles-coloring-activity`. When `subgenre` is omitted for a high-variance genre, the server auto-detects one from the book details (an explicit `subgenre` always wins; detection failure leaves it null). An explicit `subgenre` must be one of the genre''s values, else `400 invalid_subgenre`. Supports idempotent replay via the `Idempotency-Key` header: a repeated key returns `200` with the previously created book instead of `201`.'
parameters:
- $ref: '#/components/parameters/IdempotencyKey'
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- title
- genre
properties:
title:
type: string
maxLength: 100
description: Book title. Required. Rendered on the cover, so Arabic and Hindi/Devanagari scripts are rejected (`unsupported_characters`).
author:
type: string
maxLength: 100
description: Author name. Required unless `genre` is `Planner & Journal` / `planner-journal` or `Puzzles, Coloring & Activity` / `puzzles-coloring-activity`. Same script restrictions as `title`.
subtitle:
type: string
maxLength: 300
description: Optional subtitle. Same script restrictions as `title`.
genre:
type: string
description: Required. Accepts either a kebab-case genre slug (e.g. `science-fiction`, `business-economics`, `religion-spirituality`, `non-fiction`, `fantasy`, `romance`, `thriller`, `mystery`, `horror`, `historical-fiction`, `health-fitness`, `contemporary-fiction`, `young-adult`, `childrens`, `self-help`, `biography-memoir`, `poetry`, `planner-journal`, `puzzles-coloring-activity`, `true-crime`, `cookbooks-food`, `other`) or the canonical genre value (e.g. `Science Fiction`). Unrecognized values return `invalid_genre`.
subgenre:
type: string
maxLength: 100
description: Optional subgenre value. Must be one of the genre's values, exactly as written (see `GET /api/v1/capabilities`, `genres[].subgenres[].value`). Any other value returns `invalid_subgenre`, and the message lists the valid values. A genre with no subgenres (`other`) takes none. If omitted for genres that have subgenres, the server auto-detects one.
summary:
type: string
maxLength: 1000
description: Optional plot/content summary used to inform generation.
target_audience:
type: string
enum:
- children
- middle-grade
- young-adult
- new-adult
- adult
maxLength: 500
description: Optional. Must be one of the predefined audience values.
external_ref:
type: string
maxLength: 200
description: Optional caller-supplied reference. Echoed back in the response (not stored on the book).
planner_year:
type: string
description: Optional. Only meaningful for the planner genre. Must be a string if provided (type-checked; no length limit is enforced in code).
responses:
'200':
description: 'Idempotent replay: a book with the same `Idempotency-Key` already exists for this user. `external_ref` is echoed from the current request, not the original one.'
content:
application/json:
schema:
$ref: '#/components/schemas/BookCreated'
'201':
description: Book created.
content:
application/json:
schema:
$ref: '#/components/schemas/BookCreated'
'400':
description: 'Validation or moderation failure. `code` is one of: `missing_required_fields`, `invalid_field_type`, `field_too_long`, `unsupported_characters`, `invalid_field_value`, `content_policy_violation`, `invalid_genre`, `invalid_subgenre`.'
x-error-codes:
- missing_required_fields
- invalid_field_type
- field_too_long
- unsupported_characters
- invalid_field_value
- content_policy_violation
- invalid_genre
- invalid_subgenre
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'500':
description: Server error. `code` is `book_creation_failed` (insert failed) or `internal_error`.
x-error-codes:
- book_creation_failed
- internal_error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
get:
tags:
- Books
operationId: listBooks
summary: List books
description: Lists books owned by the API key's account, newest first, with keyset cursor pagination. Hidden books stay out unless `include_hidden=true`, as on the dashboard shelf. Each book carries its cover count and its shelf thumbnail (`thumbnail_cover_id`). Lists every member's books of the workspace, as the app shelf; each names its creator (`created_by`) and client (`client_id`).
parameters:
- $ref: '#/components/parameters/PageLimit'
- $ref: '#/components/parameters/PageCursor'
- name: q
in: query
required: false
schema:
type: string
maxLength: 100
description: Only books whose title or author contains this text (case-insensitive).
- name: include_hidden
in: query
required: false
schema:
type: boolean
default: false
description: Also list books hidden from the shelf.
- name: source_type
in: query
required: false
schema:
type: string
enum:
- generated
- external_wrap
- premade
description: Only books of this kind.
- name: client_id
in: query
required: false
schema:
type: string
format: uuid
description: Only books filed under this client (`GET /api/v1/clients`).
responses:
'200':
description: One page of books.
content:
application/json:
schema:
$ref: '#/components/schemas/BookList'
'400':
description: '`code` is one of: `invalid_limit`, `invalid_cursor`, `invalid_q`, `invalid_include_hidden`, `invalid_source_type`, `invalid_client_id`.'
x-error-codes:
- invalid_limit
- invalid_cursor
- invalid_q
- invalid_include_hidden
- invalid_source_type
- invalid_client_id
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'500':
description: Server error. `code` is `fetch_failed` or `internal_error`.
x-error-codes:
- fetch_failed
- internal_error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
/api/v1/books/{bookId}:
patch:
tags:
- Books
operationId: updateBook
summary: Update a book
description: Edits a book's details, as the app's edit form does, or hides it from the shelf. Free. Send only the fields to change. Covers generated later use the new details; existing covers do not change. Text fields pass the same moderation as `POST /api/v1/books`.
parameters:
- name: bookId
in: path
required: true
schema:
type: string
format: uuid
description: The book id returned by POST /api/v1/books.
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/BookUpdate'
responses:
'200':
description: The updated book.
content:
application/json:
schema:
$ref: '#/components/schemas/BookSummary'
'400':
description: '`code` is one of: `invalid_body`, `unknown_fields`, `no_changes`, `missing_required_fields`, `invalid_field_type`, `field_too_long`, `unsupported_characters`, `invalid_field_value`, `invalid_genre`, `invalid_subgenre`, `content_policy_violation`.'
x-error-codes:
- invalid_body
- unknown_fields
- no_changes
- missing_required_fields
- invalid_field_type
- field_too_long
- unsupported_characters
- invalid_field_value
- invalid_genre
- invalid_subgenre
- content_policy_violation
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'404':
description: '`code` is `book_not_found`.'
x-error-codes:
- book_not_found
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
'500':
description: Server error. `code` is `book_update_failed` or `internal_error`.
x-error-codes:
- book_update_failed
- internal_error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
/api/v1/books/{bookId}/motifs:
get:
tags:
- Books
operationId: listBookMotifs
summary: List a book's motif candidates
description: 'Lists the book''s motif candidates: the story objects, symbols and places the V2 engine extracted from its summary, plus any added in the app (user-added first). Pass one `id` as `motif_id` on POST /api/v1/covers/generate. A book with none gets them extracted from its summary on this call (a few seconds). Free.'
parameters:
- name: bookId
in: path
required: true
schema:
type: string
format: uuid
description: The book id returned by POST /api/v1/books.
responses:
'200':
description: The book's motifs.
content:
application/json:
schema:
$ref: '#/components/schemas/BookMotifList'
'400':
description: '`code`: `missing_book_id`.'
x-error-codes:
- missing_book_id
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'404':
description: 'Book not found or not owned by this API key''s account. `code`: `book_not_found`.'
x-error-codes:
- book_not_found
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
'500':
description: 'Server error. `code`: `internal_error`.'
x-error-codes:
- internal_error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
components:
schemas:
BookCreated:
type: object
required:
- bookId
- subgenre
- external_ref
- created_at
properties:
bookId:
type: string
format: uuid
subgenre:
type:
- string
- 'null'
description: 'The stored subgenre: the caller-provided value, an auto-detected one, or null.'
external_ref:
type:
- string
- 'null'
description: Echo of the request's external_ref (not persisted on the book).
created_at:
type: string
format: date-time
BookSummary:
type: object
required:
- bookId
- title
- genre
- visibility
- source_type
- thumbnail_cover_id
- covers_count
- created_at
properties:
bookId:
type: string
format: uuid
title:
type: string
author:
type:
- string
- 'null'
subtitle:
type:
- string
- 'null'
genre:
type: string
description: Canonical genre value (e.g. `Science Fiction`).
subgenre:
type:
- string
- 'null'
summary:
type:
- string
- 'null'
target_audience:
type:
- string
- 'null'
planner_year:
type:
- string
- 'null'
description: 'Planner & Journal books only: the year on the cover.'
visibility:
type: string
enum:
- default
- hidden
description: '`hidden` books are off the dashboard shelf and out of `GET /api/v1/books` unless `include_hidden=true`.'
source_type:
type: string
enum:
- generated
- external_wrap
- premade
description: '`generated` = made in the generator or the API; `external_wrap` = an uploaded cover (External Cover Studio); `premade` = a bought premade cover.'
thumbnail_cover_id:
type:
- string
- 'null'
format: uuid
description: 'The coverId that represents the book on the shelf: the newest cover marked `favorite`, else the newest cover. Null when the book has no covers.'
covers_count:
type: integer
description: Every cover of the book, hidden ones included (the dashboard's "N covers").
app_url:
type: string
format: uri
description: The book's page in the BeYourCover app (sign-in required). Unlike the signed asset links it does not expire, so it is the link to keep or hand to a person.
created_at:
type: string
format: date-time
client_id:
type:
- string
- 'null'
format: uuid
description: The agency client the book is filed under (`GET /api/v1/clients`); null when Unassigned.
created_by:
type: object
description: The workspace member who created the book. The list covers every member's books, as the app shelf.
properties:
user_id:
type:
- string
- 'null'
format: uuid
email:
type:
- string
- 'null'
BookMotifList:
type: object
required:
- bookId
- motifs
- allowed_types
properties:
bookId:
type: string
format: uuid
motifs:
type: array
items:
type: object
required:
- id
- label
- description
- type
- user_added
properties:
id:
type: string
description: Pass as `motif_id` on POST /api/v1/covers/generate.
label:
type: string
description:
type: string
type:
type: string
description: A motif kind (`object`, `symbol`, `place`, `structure`, `interior`) or a composition role.
user_added:
type: boolean
description: True for a motif the author added in the app.
allowed_types:
type: array
items:
type: string
description: The motif types the book's template pool renders.
ErrorEnvelope:
type: object
required:
- error
properties:
error:
type: object
required:
- code
- message
properties:
code:
type: string
description: Machine-readable error code (snake_case).
message:
type: string
description: Human-readable explanation. For 500s this is always a generic message.
details:
type: object
description: Optional machine-readable recovery information. 402 responses carry { balance, required, billing_url }; unknown-path 404s carry absolute URLs for the OpenAPI spec, documentation, API catalog, authentication guide and health probe.
description: Uniform error envelope used by every non-2xx JSON response.
BookUpdate:
type: object
minProperties: 1
additionalProperties: false
description: 'Send only the fields to change. `null` clears an optional field. The app''s edit-form rules apply: a title is required, and an author is required except for Planner & Journal and Puzzles, Coloring & Activity books.'
properties:
title:
type: string
minLength: 1
maxLength: 100
author:
type:
- string
- 'null'
maxLength: 100
subtitle:
type:
- string
- 'null'
maxLength: 300
summary:
type:
- string
- 'null'
maxLength: 1000
genre:
type: string
description: A genre slug or canonical value, as in `POST /api/v1/books`. A new genre keeps the stored subgenre only when it belongs to that genre; otherwise the subgenre is cleared.
subgenre:
type:
- string
- 'null'
description: One of the genre's subgenres (see `GET /api/v1/templates`).
target_audience:
type:
- string
- 'null'
planner_year:
type:
- string
- 'null'
visibility:
type: string
enum:
- default
- hidden
description: '`hidden` takes the book off the shelf; nothing is deleted.'
BookList:
type: object
required:
- books
- next_cursor
properties:
books:
type: array
items:
$ref: '#/components/schemas/BookSummary'
description: Newest first.
next_cursor:
type:
- string
- 'null'
description: Pass as `cursor` to fetch the next page. `null` when there are no more results.
responses:
Forbidden:
description: 'The API key is valid but its owner has no active enterprise subscription (`forbidden`); or the acting member''s role does not allow the call: a reviewer cannot spend credits or change books (`forbidden_role`), and only the member who created a book may edit it or its covers (`not_book_creator`).'
x-error-codes:
- forbidden
- forbidden_role
- not_book_creator
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
Unauthorized:
description: 'Missing/malformed API key, unknown or inactive key, or inactive subscription detected during credit checks. `code`: `unauthorized`.'
x-error-codes:
- unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
parameters:
PageCursor:
name: cursor
in: query
required: false
schema:
type: string
description: Opaque cursor from a previous response's `next_cursor`. Omit for the first page.
IdempotencyKey:
name: Idempotency-Key
in: header
required: false
schema:
type: string
description: Optional idempotency key. If a resource/job was already created with the same key (scoped to the API key for jobs, to the user for books), the endpoint returns `200` with the existing resource instead of creating a duplicate. Concurrent duplicates are also collapsed via a unique-constraint retry.
PageLimit:
name: limit
in: query
required: false
schema:
type: integer
minimum: 1
maximum: 100
description: Page size (default 20, max 100).
securitySchemes:
ApiKeyBearer:
type: http
scheme: bearer
bearerFormat: byc_sk_{32 hex chars}
description: 'Partner API key sent as `Authorization: Bearer byc_sk_...`. The key must match `^byc_sk_[0-9a-f]{32}$`. A malformed, unknown, or inactive key yields `401 unauthorized`; a valid key whose owner has no active enterprise subscription yields `403 forbidden`.'