BeYourCover Books API

The Books API from BeYourCover — 3 operation(s) for books.

Operations 4

POST /api/v1/books Create a book record #
GET /api/v1/books List books #
PATCH /api/v1/books/{bookId} Update a book #
GET /api/v1/books/{bookId}/motifs List a book's motif candidates #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • 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.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/beyourcover-com:beyourcover-com-books-api"
All apis
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.

Get an API 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 Specification

beyourcover-com-books-api-openapi.yml Raw ↑
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`.'