{
  "openapi": "3.1.0",
  "info": {
    "title": "Siftivo Agent API",
    "version": "0.1.0",
    "description": "Book discovery and a reader's library, callable by agents. The same tools are available over MCP at https://api.siftivo.com/mcp",
    "contact": {
      "url": "https://siftivo.com/blog/siftivo-for-agents/"
    }
  },
  "servers": [
    {
      "url": "https://api.siftivo.com"
    }
  ],
  "paths": {
    "/api/agent/search_books": {
      "get": {
        "operationId": "search_books",
        "summary": "Search books",
        "description": "Find a book in the Siftivo catalog by its title or author, or by words from what it is about, and get the workId the other Siftivo tools take. Suits a named book (\"add Circe to my list\", \"what is Babel about\", \"is Demon Copperhead worth reading\") and the book behind a half-remembered plot (\"the novel about a man alone in an endless house of statues\").",
        "tags": [
          "catalog"
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "No such entity"
          }
        },
        "security": [],
        "parameters": [
          {
            "name": "query",
            "in": "query",
            "required": true,
            "description": "Words to search for",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200,
              "description": "Words to search for"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 20,
              "default": 10
            }
          },
          {
            "name": "isFiction",
            "in": "query",
            "required": false,
            "description": "Restrict to fiction (true) or nonfiction (false)",
            "schema": {
              "type": "boolean",
              "description": "Restrict to fiction (true) or nonfiction (false)"
            }
          }
        ]
      }
    },
    "/api/agent/get_book": {
      "get": {
        "operationId": "get_book",
        "summary": "Get a book",
        "description": "What one book is about: synopsis, authors, year, series and position, genres, and its siftivo.com page. Suits \"what is X about\" and \"is X part of a series\". For a reader who has linked their Siftivo account it also suits \"would I like X\": when the book fits their taste, the result says why. Takes a workId from search_books, or a siftivo.com slug.",
        "tags": [
          "catalog"
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "No such entity"
          }
        },
        "security": [],
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": true,
            "description": "A Siftivo work id, edition id, or URL slug",
            "schema": {
              "type": "string",
              "minLength": 1,
              "description": "A Siftivo work id, edition id, or URL slug"
            }
          }
        ]
      }
    },
    "/api/agent/what_to_read_next": {
      "get": {
        "operationId": "what_to_read_next",
        "summary": "What to read next",
        "description": "What to read after one particular book: the next books in its series, more by the same author, and books that read like it, the same set its siftivo.com page shows. Suits \"what should I read after X\", \"is there a sequel to X\" and \"more like X\". For a reader who has linked their Siftivo account, each list leaves out books already in their library and books they hid, avoided or recently passed on, and a book that fits their taste says why. Takes a workId from search_books.",
        "tags": [
          "catalog"
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "No such entity"
          }
        },
        "security": [],
        "parameters": [
          {
            "name": "workId",
            "in": "query",
            "required": true,
            "description": "A workId from search_books, get_book, or a URL slug",
            "schema": {
              "type": "string",
              "minLength": 1,
              "description": "A workId from search_books, get_book, or a URL slug"
            }
          }
        ]
      }
    },
    "/api/agent/get_author": {
      "get": {
        "operationId": "get_author",
        "summary": "Get an author",
        "description": "An author's biography and the books Siftivo holds for them, with years. Suits \"what else has X written\" and \"tell me about X\". Takes the author's name, an author id, or a siftivo.com slug.",
        "tags": [
          "catalog"
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "No such entity"
          }
        },
        "security": [],
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": true,
            "description": "An author name, an author id, or a siftivo.com slug",
            "schema": {
              "type": "string",
              "minLength": 1,
              "description": "An author name, an author id, or a siftivo.com slug"
            }
          }
        ]
      }
    },
    "/api/agent/get_series": {
      "get": {
        "operationId": "get_series",
        "summary": "Get a series",
        "description": "A book series in reading order: every book with its position and publication year, and whether the series is complete. Suits \"what order do the X books go in\", \"what is book 3 of X\" and \"is the next X book out\". Takes the series name, or a series id from get_book or what_to_read_next.",
        "tags": [
          "catalog"
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "No such entity"
          }
        },
        "security": [],
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": true,
            "description": "A series id, a URL slug, or the series name",
            "schema": {
              "type": "string",
              "minLength": 1,
              "description": "A series id, a URL slug, or the series name"
            }
          }
        ]
      }
    },
    "/api/agent/get_reading_index": {
      "get": {
        "operationId": "get_reading_index",
        "summary": "Get the Siftivo Reading Index",
        "description": "The weekly Siftivo Reading Index: the fiction and nonfiction books moving most in cultural circulation this week, ranked, with weeks on the chart and new entries. Suits \"what books are popular right now\", \"what is everyone reading\" and \"what are the big books this week\".",
        "tags": [
          "catalog"
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "No such entity"
          }
        },
        "security": [],
        "parameters": [
          {
            "name": "week",
            "in": "query",
            "required": false,
            "description": "Edition week, YYYY-MM-DD. Omit for the current edition.",
            "schema": {
              "type": "string",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
              "description": "Edition week, YYYY-MM-DD. Omit for the current edition."
            }
          }
        ]
      }
    },
    "/api/agent/recommend_from_description": {
      "get": {
        "operationId": "recommend_from_description",
        "summary": "Recommend books from a description",
        "description": "Book recommendations from a mood, theme or subject in the reader's own words: \"cozy fantasy with found family\", \"a good book about grief\", \"something light for the beach\". Matches on meaning rather than on a title or an author name. For a reader who has linked their Siftivo account, the results leave out books already in their library and books they hid, avoided or recently passed on, and a result that fits their taste says why.",
        "tags": [
          "catalog"
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "No such entity"
          }
        },
        "security": [],
        "parameters": [
          {
            "name": "description",
            "in": "query",
            "required": true,
            "description": "What the reader is after, in plain language",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 300,
              "description": "What the reader is after, in plain language"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 10,
              "default": 5
            }
          },
          {
            "name": "isFiction",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ]
      }
    },
    "/api/agent/recommend_from_titles": {
      "post": {
        "operationId": "recommend_from_titles",
        "summary": "Recommend books from titles",
        "description": "Book recommendations from books the reader already loved, named by title: \"books like Project Hail Mary\", \"I loved Circe and Piranesi, what else would I like\", a book club that enjoyed one pick. Titles are resolved against the catalog first, and any that do not resolve are reported back rather than guessed at. Other books by the same authors are left out. For a reader who has linked their Siftivo account, the results leave out books already in their library and books they hid, avoided or recently passed on, and a result that fits their taste says why.",
        "tags": [
          "catalog"
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "No such entity"
          }
        },
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "titles": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "minLength": 1
                    },
                    "minItems": 1,
                    "maxItems": 10,
                    "description": "Book titles, optionally \"Title by Author\""
                  },
                  "limit": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 10,
                    "default": 5
                  },
                  "isFiction": {
                    "type": "boolean"
                  }
                },
                "required": [
                  "titles"
                ],
                "additionalProperties": false,
                "$schema": "http://json-schema.org/draft-07/schema#"
              }
            }
          }
        }
      }
    },
    "/api/agent/get_my_library": {
      "get": {
        "operationId": "get_my_library",
        "summary": "Get my library",
        "description": "The signed-in reader's Siftivo shelves: what they want to read, are reading, finished or did not finish, with their ratings, progress and private notes. Suits \"what am I reading\", \"what is on my to-read list\" and \"what have I finished\". Filter to one shelf with status. Needs a linked Siftivo account.\n\nNot callable on this REST surface. It acts on the signed-in reader's own library, and this path answers 401 to every caller regardless of credentials. Reach it over MCP at https://api.siftivo.com/mcp, which runs the OAuth handshake.",
        "tags": [
          "library"
        ],
        "responses": {
          "401": {
            "description": "Always. This tool is reachable over MCP only; see the description for the endpoint that serves it."
          }
        },
        "security": [],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Filter to one shelf. Omit for the whole library.",
            "schema": {
              "type": "string",
              "enum": [
                "NOT_STARTED",
                "READING",
                "FINISHED",
                "DNF"
              ],
              "description": "Filter to one shelf. Omit for the whole library."
            }
          }
        ]
      }
    },
    "/api/agent/add_to_library": {
      "post": {
        "operationId": "add_to_library",
        "summary": "Add a book to my library",
        "description": "Log reading on the signed-in reader's Siftivo shelves: add a book to want to read (NOT_STARTED), mark it READING, FINISHED or DNF, rate it, or record progress. Suits \"add X to my list\", \"I just finished X, four stars\" and \"I'm halfway through X\". \"Finished it, four and a half stars\" is one call with readingStatus FINISHED and rating 4.5. The workId comes from search_books. Each field given replaces what the reader had there before, so send a rating or a note only when they asked for that one to change. Omitting readingStatus leaves the book on the shelf it is already on. Needs a linked Siftivo account.\n\nNot callable on this REST surface. It acts on the signed-in reader's own library, and this path answers 401 to every caller regardless of credentials. Reach it over MCP at https://api.siftivo.com/mcp, which runs the OAuth handshake.",
        "tags": [
          "library"
        ],
        "responses": {
          "401": {
            "description": "Always. This tool is reachable over MCP only; see the description for the endpoint that serves it."
          }
        },
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "workId": {
                    "type": "string",
                    "minLength": 1
                  },
                  "readingStatus": {
                    "type": "string",
                    "enum": [
                      "NOT_STARTED",
                      "READING",
                      "FINISHED",
                      "DNF"
                    ],
                    "description": "The shelf to put the book on. Omit to leave it where it is, or NOT_STARTED for a book the reader has not opened yet."
                  },
                  "rating": {
                    "type": "number",
                    "minimum": 0.5,
                    "maximum": 5,
                    "multipleOf": 0.5,
                    "description": "Stars, 0.5 to 5 in half-star steps"
                  },
                  "progress": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 100,
                    "description": "Percent read, 0 to 100"
                  },
                  "notes": {
                    "type": "string",
                    "maxLength": 2000,
                    "description": "The reader's own note on the book, private to them"
                  }
                },
                "required": [
                  "workId"
                ],
                "additionalProperties": false,
                "$schema": "http://json-schema.org/draft-07/schema#"
              }
            }
          }
        }
      }
    },
    "/api/agent/get_my_book": {
      "post": {
        "operationId": "get_my_book",
        "summary": "Get one book from my library",
        "description": "Which of up to 25 books the signed-in reader already has on a shelf, and for each one the shelf, their rating and their progress. Takes titles (\"Title by Author\" resolves best) or workIds. Suits \"have I read X\", \"which of these have I read\" and checking a list of book suggestions against what the reader has already read. Titles not in the catalog come back under unmatched. Needs a linked Siftivo account.\n\nNot callable on this REST surface. It acts on the signed-in reader's own library, and this path answers 401 to every caller regardless of credentials. Reach it over MCP at https://api.siftivo.com/mcp, which runs the OAuth handshake.",
        "tags": [
          "library"
        ],
        "responses": {
          "401": {
            "description": "Always. This tool is reachable over MCP only; see the description for the endpoint that serves it."
          }
        },
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "books": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 200
                    },
                    "minItems": 1,
                    "maxItems": 25,
                    "description": "Work ids, siftivo.com slugs, or titles, optionally \"Title by Author\""
                  }
                },
                "required": [
                  "books"
                ],
                "additionalProperties": false,
                "$schema": "http://json-schema.org/draft-07/schema#"
              }
            }
          }
        }
      }
    },
    "/api/agent/remove_from_library": {
      "post": {
        "operationId": "remove_from_library",
        "summary": "Remove a book from my library",
        "description": "Take a book off the signed-in reader's shelves entirely, discarding its shelf, progress and notes. The reader's rating for the book stays. Suits \"take X off my shelves\" and \"remove X from my list\". Moving a book between shelves is add_to_library with a new readingStatus. Needs a linked Siftivo account.\n\nNot callable on this REST surface. It acts on the signed-in reader's own library, and this path answers 401 to every caller regardless of credentials. Reach it over MCP at https://api.siftivo.com/mcp, which runs the OAuth handshake.",
        "tags": [
          "library"
        ],
        "responses": {
          "401": {
            "description": "Always. This tool is reachable over MCP only; see the description for the endpoint that serves it."
          }
        },
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "workId": {
                    "type": "string",
                    "minLength": 1
                  }
                },
                "required": [
                  "workId"
                ],
                "additionalProperties": false,
                "$schema": "http://json-schema.org/draft-07/schema#"
              }
            }
          }
        }
      }
    },
    "/api/agent/get_my_taste": {
      "get": {
        "operationId": "get_my_taste",
        "summary": "Get my taste",
        "description": "The signed-in reader's taste: the books, authors, series, genres and moods they love, what they avoid or quit, why each one counts, and how far from their usual taste they like to range. A recommendation for this reader rests on it, so it suits \"what should I read next\", \"recommend me a book\", \"something I would like\" and \"what kind of books do I like\" when no book or mood is named. The strongest 40 entries come back by default, and limit raises that. Needs a linked Siftivo account. It is the same profile the app's own recommendations use.\n\nNot callable on this REST surface. It acts on the signed-in reader's own library, and this path answers 401 to every caller regardless of credentials. Reach it over MCP at https://api.siftivo.com/mcp, which runs the OAuth handshake.",
        "tags": [
          "library"
        ],
        "responses": {
          "401": {
            "description": "Always. This tool is reachable over MCP only; see the description for the endpoint that serves it."
          }
        },
        "security": [],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Most steering entries to return, strongest first",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 40,
              "description": "Most steering entries to return, strongest first"
            }
          }
        ]
      }
    }
  },
  "components": {
    "securitySchemes": {
      "siftivoOAuth": {
        "type": "oauth2",
        "description": "Per-reader consent through Siftivo, used by the MCP endpoint at https://api.siftivo.com/mcp. No operation in this document requires it.",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://clerk.siftivo.com/oauth/authorize",
            "tokenUrl": "https://clerk.siftivo.com/oauth/token",
            "scopes": {
              "profile": "Read which reader is calling",
              "email": "Read the reader's email address"
            }
          }
        }
      }
    }
  }
}