{
  "openapi": "3.1.0",
  "info": {
    "title": "Foundation4 API",
    "description": "The Foundation4 REST API manages pipelines, documents, search, language models, agents and the objects that they depend on. This section lists every operation of the API server, grouped by the type of object. Each page describes the request, the responses and the permissions that the operation requires, with the same request as a `curl`, Python, TypeScript and Ruby example.\n\n- **Base URL.** Every path is relative to the base URL of the API server in a deployment. The API has no path prefix.\n- **Authentication.** Every operation except the welcome message and the health check requires an API key, sent in the `x-api-key` and `x-api-key-secret` headers. [Authenticate](../../get-started/02-authenticate.md) describes the headers and defines the shell variables `FOUNDATION4_URL`, `FOUNDATION4_API_KEY` and `FOUNDATION4_API_SECRET` that every example uses.\n- **Examples.** The Python, TypeScript and Ruby examples use only the standard library of each language (`urllib.request` in Python 3, `fetch` in Node.js 18 or later, `net/http` in Ruby), so they run on hosts without access to a package registry. They read `FOUNDATION4_URL`, `FOUNDATION4_API_KEY`, `FOUNDATION4_API_SECRET` and identifiers such as `PIPELINE_ID` from the environment, so the shell exports each variable. The TypeScript examples use top-level `await` and run as ES modules: Node.js 22.6 or later runs a `.mts` file directly with the `--experimental-strip-types` option. Each example prints the status code and the response body.\n- **Conventions.** [API conventions](../01-api-conventions.md) describes pagination, list filters, ordering, identifiers, timestamps and streaming responses, which the operation pages do not repeat.\n- **Errors.** Every authenticated operation can also return the errors of the key check and of request parsing. [Errors](../04-errors.md) describes the error format and every error message.\n- **Search and filters.** [Search requests](../02-search-requests.md) and [Filter operators](../03-filter-operators.md) describe the body of a search request in detail.\n\nEach deployment also serves the OpenAPI document of the installed version at `GET /openapi.json` and an interactive reference at `GET /docs`. The document offered for download on this page includes the corrections from the review of the code. The same requests are offered as a [collection in Postman format](pathname:///openapi/foundation4-api.postman_collection.json) for API clients, and [Send requests from an API client](../../guides/08-send-requests-from-an-api-client.md) describes the import.\n",
    "version": "2026-09"
  },
  "paths": {
    "/": {
      "get": {
        "tags": [
          "Core"
        ],
        "summary": "Get the welcome message",
        "description": "Returns the plain-text string `Foundation4.ai API`. Client applications and operators use the operation to check that the API server is reachable.\n\n**Permissions.** None. The operation requires no API key.",
        "operationId": "root",
        "responses": {
          "200": {
            "description": "The API server is reachable. The body is the plain-text string `Foundation4.ai API`.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                },
                "examples": {
                  "Success": {
                    "value": "Foundation4.ai API"
                  }
                }
              }
            }
          }
        },
        "x-position": 0,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl \"$FOUNDATION4_URL/\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/\",\n    method=\"GET\",\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/`);\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/\")\nrequest = Net::HTTP::Get.new(uri)\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/agents": {
      "get": {
        "tags": [
          "Agents"
        ],
        "summary": "List agents",
        "operationId": "list_agents",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "uuid"
            },
            "description": "Returns only the agent with this identifier."
          },
          {
            "name": "name",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Returns only the agent with exactly this name."
          },
          {
            "name": "name$contains",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "Matches objects whose `name` contains the value, case-sensitive. Repeat the parameter to require several values."
          },
          {
            "name": "name$startswith",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Matches objects whose `name` starts with the value."
          },
          {
            "name": "name$gt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Matches objects whose `name` is greater than the value."
          },
          {
            "name": "name$ge",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Matches objects whose `name` is greater than or equal to the value."
          },
          {
            "name": "name$lt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Matches objects whose `name` is less than the value."
          },
          {
            "name": "name$le",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Matches objects whose `name` is less than or equal to the value."
          },
          {
            "name": "description",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Returns only agents with exactly this description."
          },
          {
            "name": "description$contains",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "Matches objects whose `description` contains the value, case-sensitive. Repeat the parameter to require several values."
          },
          {
            "name": "created_at",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Returns only agents created at exactly this time, as an RFC 3339 timestamp."
          },
          {
            "name": "created_at$gt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` is greater than the value."
          },
          {
            "name": "created_at$lt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` is less than the value."
          },
          {
            "name": "created_at$ge",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` is greater than or equal to the value."
          },
          {
            "name": "created_at$le",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` is less than or equal to the value."
          },
          {
            "name": "updated_at",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Returns only agents last changed at exactly this time, as an RFC 3339 timestamp."
          },
          {
            "name": "updated_at$gt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` is greater than the value."
          },
          {
            "name": "updated_at$lt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` is less than the value."
          },
          {
            "name": "updated_at$ge",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` is greater than or equal to the value."
          },
          {
            "name": "updated_at$le",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` is less than or equal to the value."
          },
          {
            "name": "first",
            "in": "query",
            "description": "Cursor mode: the number of objects to return from the start of the list, or after the `after` cursor.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "after",
            "in": "query",
            "description": "Cursor mode: the cursor after which the page starts, taken from `page_info.after` of the previous page.",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "name": "last",
            "in": "query",
            "description": "Cursor mode: the number of objects to return before the `before` cursor.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "before",
            "in": "query",
            "description": "Cursor mode: the cursor before which the page ends, taken from `page_info.before`.",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Offset mode: the number of objects to return. The default page size is 25.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Offset mode: the number of objects to skip.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "count",
            "in": "query",
            "description": "When `true`, adds `page_info.count`, the total number of matching objects.",
            "required": false,
            "schema": {
              "type": [
                "boolean",
                "null"
              ]
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Sort fields: `id`, `created_at`, `updated_at`, `name`. A `-` prefix sorts in descending order. A field name alone sorts in ascending order, as does a `+` prefix sent encoded as `%2B`. Repeat the parameter to sort by several fields. The default order is `id` ascending.",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of agents. `data` holds the agents, `page_info` describes the page and `query_info` repeats the filters that the server recognized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Paginated_AgentResponse"
                }
              }
            }
          },
          "400": {
            "description": "`order_by` names a field that the list cannot sort by (`Invalid order_by parameter`), or the pagination parameters conflict or carry an invalid cursor (`Pagination error`)."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Returns one page of the agents that the key can read, in the list envelope. Query parameters filter the list by field values and set the order and the page.\n\n**Permissions.** Read on the agents in the list. The list contains only the agents that the key can read, so a key without read permission on any agent receives an empty list.\n\n[API conventions](../01-api-conventions.md) describes pagination, filters and ordering.",
        "x-position": 1,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl \"$FOUNDATION4_URL/agents\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/agents\",\n    method=\"GET\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/agents`, {\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/agents\")\nrequest = Net::HTTP::Get.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      },
      "post": {
        "tags": [
          "Agents"
        ],
        "summary": "Create an agent",
        "operationId": "create_agent",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateAgentRequest"
              },
              "example": {
                "name": "support-answers",
                "description": "Answers support questions from the product knowledge base",
                "prompt": [
                  {
                    "role": "system",
                    "template": "Answer using only the reference text. If the reference text does not contain the answer, say that the answer is not available."
                  },
                  {
                    "role": "user",
                    "template": "Reference text:\n{context}\n\nQuestion: {question}"
                  }
                ],
                "placeholders": [
                  {
                    "name": "question",
                    "type": "query"
                  },
                  {
                    "name": "context",
                    "type": "similarity",
                    "target": "question",
                    "params": {
                      "k": 5
                    }
                  }
                ]
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "The agent was created. The body is the new agent, including the generated `id`, the `include` value of each message and every parameter of each retrieval placeholder.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentResponse"
                }
              }
            }
          },
          "400": {
            "description": "The prompt template or a placeholder breaks a validation rule (`Invalid prompt type`, `Invalid prompt` or `Invalid placeholder of type <placeholder>`)."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "403": {
            "description": "The key lacks write permission on the `agents` object type (`Unauthorized: access level ... required for Agent ...`), the license is not valid (`Invalid license: <reason>`) or the license limit for agents is reached (`License limits exceeded for Agent`)."
          },
          "409": {
            "description": "Another agent already has this name (`Conflict unique error`)."
          },
          "501": {
            "description": "A placeholder has the type `hybrid` or `history`, which agents do not implement (`Not implemented`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Creates an agent from a prompt template and the placeholders that the template uses. Foundation4 validates the definition before storing the agent: the prompt contains at least one `system` message and one `user` message, the last message is a `user` message, every name in braces is a placeholder of the agent and every retrieval placeholder targets a `query` placeholder. Agent executions run `query`, `similarity` and `mmr` placeholders.\n\n**Permissions.** Write on the agent object type (`agents`).\n\n[Agents and prompt templates](../../concepts/08-agents-prompt-templates.md) describes prompt templates and placeholders.",
        "x-position": 2,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X POST \"$FOUNDATION4_URL/agents\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"name\": \"support-answers\",\n  \"description\": \"Answers support questions from the product knowledge base\",\n  \"prompt\": [\n    {\n      \"role\": \"system\",\n      \"template\": \"Answer using only the reference text. If the reference text does not contain the answer, say that the answer is not available.\"\n    },\n    {\n      \"role\": \"user\",\n      \"template\": \"Reference text:\\n{context}\\n\\nQuestion: {question}\"\n    }\n  ],\n  \"placeholders\": [\n    {\n      \"name\": \"question\",\n      \"type\": \"query\"\n    },\n    {\n      \"name\": \"context\",\n      \"type\": \"similarity\",\n      \"target\": \"question\",\n      \"params\": {\n        \"k\": 5\n      }\n    }\n  ]\n}'"
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import json\nimport os\nimport urllib.error\nimport urllib.request\n\nbody = {\n    \"name\": \"support-answers\",\n    \"description\": \"Answers support questions from the product knowledge base\",\n    \"prompt\": [\n        {\n            \"role\": \"system\",\n            \"template\": \"Answer using only the reference text. If the reference text does not contain the answer, say that the answer is not available.\",\n        },\n        {\n            \"role\": \"user\",\n            \"template\": \"Reference text:\\n{context}\\n\\nQuestion: {question}\",\n        },\n    ],\n    \"placeholders\": [\n        {\n            \"name\": \"question\",\n            \"type\": \"query\",\n        },\n        {\n            \"name\": \"context\",\n            \"type\": \"similarity\",\n            \"target\": \"question\",\n            \"params\": {\n                \"k\": 5,\n            },\n        },\n    ],\n}\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/agents\",\n    method=\"POST\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n        \"Content-Type\": \"application/json\",\n    },\n    data=json.dumps(body).encode(),\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/agents`, {\n  method: \"POST\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    name: \"support-answers\",\n    description: \"Answers support questions from the product knowledge base\",\n    prompt: [\n      {\n        role: \"system\",\n        template: \"Answer using only the reference text. If the reference text does not contain the answer, say that the answer is not available.\",\n      },\n      {\n        role: \"user\",\n        template: \"Reference text:\\n{context}\\n\\nQuestion: {question}\",\n      },\n    ],\n    placeholders: [\n      {\n        name: \"question\",\n        type: \"query\",\n      },\n      {\n        name: \"context\",\n        type: \"similarity\",\n        target: \"question\",\n        params: {\n          k: 5,\n        },\n      },\n    ],\n  }),\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"json\"\nrequire \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/agents\")\nrequest = Net::HTTP::Post.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nrequest[\"Content-Type\"] = \"application/json\"\nrequest.body = JSON.generate({\n  \"name\" => \"support-answers\",\n  \"description\" => \"Answers support questions from the product knowledge base\",\n  \"prompt\" => [\n    {\n      \"role\" => \"system\",\n      \"template\" => \"Answer using only the reference text. If the reference text does not contain the answer, say that the answer is not available.\",\n    },\n    {\n      \"role\" => \"user\",\n      \"template\" => \"Reference text:\\n{context}\\n\\nQuestion: {question}\",\n    },\n  ],\n  \"placeholders\" => [\n    {\n      \"name\" => \"question\",\n      \"type\" => \"query\",\n    },\n    {\n      \"name\" => \"context\",\n      \"type\" => \"similarity\",\n      \"target\" => \"question\",\n      \"params\" => {\n        \"k\" => 5,\n      },\n    },\n  ],\n})\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/agents/{agent_id}": {
      "get": {
        "tags": [
          "Agents"
        ],
        "summary": "Get an agent",
        "operationId": "get_agent",
        "parameters": [
          {
            "name": "agent_id",
            "in": "path",
            "description": "Identifier of the agent.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The agent.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentResponse"
                }
              }
            }
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "404": {
            "description": "No agent with this identifier exists, or the key lacks read permission on the agent (`Agent not found`). `details.id` holds the identifier."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Returns the stored definition of an agent: the prompt template, the placeholders and the metadata. An agent stores no pipeline and no LLM, because each execution names both.\n\n**Permissions.** Read on the agent.\n\n[Agents and prompt templates](../../concepts/08-agents-prompt-templates.md) describes the agent definition.",
        "x-position": 3,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl \"$FOUNDATION4_URL/agents/$AGENT_ID\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/agents/{os.environ['AGENT_ID']}\",\n    method=\"GET\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/agents/${process.env.AGENT_ID}`, {\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/agents/#{ENV.fetch(\"AGENT_ID\")}\")\nrequest = Net::HTTP::Get.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      },
      "delete": {
        "tags": [
          "Agents"
        ],
        "summary": "Delete an agent",
        "operationId": "delete_agent",
        "parameters": [
          {
            "name": "agent_id",
            "in": "path",
            "description": "Identifier of the agent.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "The agent was deleted. The response has no body."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "403": {
            "description": "The key lacks write permission on the agent (`Unauthorized: access level ... required for Agent with id ...`)."
          },
          "404": {
            "description": "No agent with this identifier exists (`Agent with id <id> not found`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Deletes an agent. Executions that name the deleted agent then return HTTP 404.\n\n**Permissions.** Write on the agent.",
        "x-position": 5,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X DELETE \"$FOUNDATION4_URL/agents/$AGENT_ID\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/agents/{os.environ['AGENT_ID']}\",\n    method=\"DELETE\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/agents/${process.env.AGENT_ID}`, {\n  method: \"DELETE\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/agents/#{ENV.fetch(\"AGENT_ID\")}\")\nrequest = Net::HTTP::Delete.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      },
      "patch": {
        "tags": [
          "Agents"
        ],
        "summary": "Update an agent",
        "operationId": "update_agent",
        "parameters": [
          {
            "name": "agent_id",
            "in": "path",
            "description": "Identifier of the agent.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateAgentRequest"
              },
              "example": {
                "description": "Answers support questions from the product and billing knowledge base"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "The agent was updated. The body is the updated agent.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentResponse"
                }
              }
            }
          },
          "400": {
            "description": "The prompt template or a placeholder breaks a validation rule (`Invalid prompt type`, `Invalid prompt` or `Invalid placeholder of type <placeholder>`)."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "403": {
            "description": "The license is not valid (`Invalid license: <reason>`)."
          },
          "404": {
            "description": "No agent with this identifier exists, or the key lacks write permission on the agent (`Agent with id <id> not found`)."
          },
          "409": {
            "description": "Another agent already has the requested name (`Conflict unique error`)."
          },
          "501": {
            "description": "A placeholder has the type `hybrid` or `history`, which agents do not implement (`Not implemented`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Changes the fields of an agent that the request names, and keeps the stored value of every omitted field. `prompt`, `placeholders` and `metadata` replace the stored values whole, and `description` accepts `null` to clear the description. Foundation4 validates the resulting prompt template and placeholders with the rules of agent creation, including stored values that the request leaves unchanged.\n\n**Permissions.** Write on the agent.\n\n[Agents and prompt templates](../../concepts/08-agents-prompt-templates.md) describes prompt templates and placeholders.",
        "x-position": 4,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X PATCH \"$FOUNDATION4_URL/agents/$AGENT_ID\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"description\": \"Answers support questions from the product and billing knowledge base\"\n}'"
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import json\nimport os\nimport urllib.error\nimport urllib.request\n\nbody = {\n    \"description\": \"Answers support questions from the product and billing knowledge base\",\n}\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/agents/{os.environ['AGENT_ID']}\",\n    method=\"PATCH\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n        \"Content-Type\": \"application/json\",\n    },\n    data=json.dumps(body).encode(),\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/agents/${process.env.AGENT_ID}`, {\n  method: \"PATCH\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    description: \"Answers support questions from the product and billing knowledge base\",\n  }),\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"json\"\nrequire \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/agents/#{ENV.fetch(\"AGENT_ID\")}\")\nrequest = Net::HTTP::Patch.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nrequest[\"Content-Type\"] = \"application/json\"\nrequest.body = JSON.generate({\n  \"description\" => \"Answers support questions from the product and billing knowledge base\",\n})\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/agents/{agent_id}/execute": {
      "post": {
        "tags": [
          "Agents"
        ],
        "summary": "Execute an agent",
        "operationId": "post_agent_query_execute",
        "parameters": [
          {
            "name": "agent_id",
            "in": "path",
            "description": "Identifier of the agent.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "x-pipeline-id",
            "in": "header",
            "description": "Identifier of the pipeline that the retrieval placeholders search.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "x-llm-id",
            "in": "header",
            "description": "Identifier of the LLM that generates the answer.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AgentQueryExecuteRequest"
              },
              "example": {
                "prompt": {
                  "question": "How can finance export invoices?"
                },
                "classification": "internal",
                "stream": false
              }
            }
          },
          "required": true,
          "description": "The values of the agent's query placeholders, the classifications to search, optional metadata filters for each retrieval placeholder and the response options."
        },
        "responses": {
          "200": {
            "description": "The answer in the format that `stream` selects: NDJSON lines of `ApiLlmResponse` objects, server-sent events with the same objects as data, or the complete answer as plain text. With `tracing` set to `true`, the `x-foundation4ai-tracing-id` header holds the trace identifier.",
            "headers": {
              "x-foundation4ai-tracing-id": {
                "description": "The identifier of the execution trace, present when the request sets `tracing` to `true`. `GET /tracing/{execution_id}` returns the trace.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            },
            "content": {
              "application/jsonstream": {
                "schema": {
                  "$ref": "#/components/schemas/ApiLlmResponse"
                }
              },
              "text/event-stream": {
                "schema": {
                  "$ref": "#/components/schemas/ApiLlmResponse"
                }
              },
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "A required header is missing (plain text ``Header of type `x-llm-id` was missing`` or the same for `x-pipeline-id`) or is not a valid identifier (`Invalid pipeline ID`, `Invalid LLM ID`), or the execution cannot run (`Invalid parameter`). `details.error` holds the reason, such as `Missing prompt variables: <names>` or `API key is required for OpenAI provider`."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "404": {
            "description": "The agent (`Agent not found`), the pipeline (`Pipeline not found`) or the LLM (`LLM with id <id> not found`) does not exist, or the key lacks execute permission on that object. A placeholder that names an embedding model outside the pipeline returns `Embedding Model with id <id> not found`."
          },
          "500": {
            "description": "Retrieval failed (`Internal error`, with the cause in `details.error`), or, with `\"stream\": false`, the model server returned an error or could not be reached (`Stream error: <reason>`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Runs an agent: retrieves fragments for the retrieval placeholders from the pipeline named in `x-pipeline-id`, inserts the input values and the fragment text into the prompt template, and sends the messages to the LLM named in `x-llm-id`. The `stream` field selects the response format: newline-delimited JSON (NDJSON) by default, server-sent events with `\"sse\"` or plain text with `false`. With `tracing` set to `true`, Foundation4 records a trace for 60 minutes and returns the trace identifier in the `x-foundation4ai-tracing-id` response header.\n\n**Permissions.** Execute on the agent, the pipeline and the LLM.\n\n[Agents and prompt templates](../../concepts/08-agents-prompt-templates.md) describes execution, and [LLMs](../../concepts/07-llms.md) describes the requirements on the model server and the response formats.",
        "x-position": 6,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X POST \"$FOUNDATION4_URL/agents/$AGENT_ID/execute\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\" \\\n  -H \"x-pipeline-id: $PIPELINE_ID\" \\\n  -H \"x-llm-id: $LLM_ID\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"prompt\": {\n    \"question\": \"How can finance export invoices?\"\n  },\n  \"classification\": \"internal\",\n  \"stream\": false\n}'"
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import json\nimport os\nimport urllib.error\nimport urllib.request\n\nbody = {\n    \"prompt\": {\n        \"question\": \"How can finance export invoices?\",\n    },\n    \"classification\": \"internal\",\n    \"stream\": False,\n}\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/agents/{os.environ['AGENT_ID']}/execute\",\n    method=\"POST\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n        \"x-pipeline-id\": os.environ[\"PIPELINE_ID\"],\n        \"x-llm-id\": os.environ[\"LLM_ID\"],\n        \"Content-Type\": \"application/json\",\n    },\n    data=json.dumps(body).encode(),\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/agents/${process.env.AGENT_ID}/execute`, {\n  method: \"POST\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n    \"x-pipeline-id\": process.env.PIPELINE_ID!,\n    \"x-llm-id\": process.env.LLM_ID!,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    prompt: {\n      question: \"How can finance export invoices?\",\n    },\n    classification: \"internal\",\n    stream: false,\n  }),\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"json\"\nrequire \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/agents/#{ENV.fetch(\"AGENT_ID\")}/execute\")\nrequest = Net::HTTP::Post.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nrequest[\"x-pipeline-id\"] = ENV.fetch(\"PIPELINE_ID\")\nrequest[\"x-llm-id\"] = ENV.fetch(\"LLM_ID\")\nrequest[\"Content-Type\"] = \"application/json\"\nrequest.body = JSON.generate({\n  \"prompt\" => {\n    \"question\" => \"How can finance export invoices?\",\n  },\n  \"classification\" => \"internal\",\n  \"stream\" => false,\n})\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/agents/{agent_id}/prompt": {
      "get": {
        "tags": [
          "Agents"
        ],
        "summary": "Get the prompt of an agent",
        "operationId": "get_agent_prompt",
        "parameters": [
          {
            "name": "agent_id",
            "in": "path",
            "description": "Identifier of the agent.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The prompt template, the placeholders and the input variables of the agent.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentPromptResponse"
                }
              }
            }
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "404": {
            "description": "No agent with this identifier exists, or the key lacks read permission on the agent (`Agent not found`). `details.id` holds the identifier."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Returns the prompt template and the placeholders of an agent as stored, without substitution, and `input_variables`: the names of the `query` placeholders whose values each execution supplies in `prompt`.\n\n**Permissions.** Read on the agent.\n\n[Agents and prompt templates](../../concepts/08-agents-prompt-templates.md) describes the tools for testing an agent.",
        "x-position": 7,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl \"$FOUNDATION4_URL/agents/$AGENT_ID/prompt\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/agents/{os.environ['AGENT_ID']}/prompt\",\n    method=\"GET\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/agents/${process.env.AGENT_ID}/prompt`, {\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/agents/#{ENV.fetch(\"AGENT_ID\")}/prompt\")\nrequest = Net::HTTP::Get.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/agents/{agent_id}/search": {
      "post": {
        "tags": [
          "Agents"
        ],
        "summary": "Run an agent retrieval dry run",
        "operationId": "post_agent_query_search",
        "parameters": [
          {
            "name": "agent_id",
            "in": "path",
            "description": "Identifier of the agent.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "x-pipeline-id",
            "in": "header",
            "description": "Identifier of the pipeline that the retrieval placeholders search.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AgentQuerySearchRequest"
              },
              "example": {
                "prompt": {
                  "question": "How can finance export invoices?"
                },
                "classification": "internal"
              }
            }
          },
          "required": true,
          "description": "The values of the agent's query placeholders, the classifications to search and optional metadata filters for each retrieval placeholder."
        },
        "responses": {
          "200": {
            "description": "An object that maps the name of each retrieval placeholder to the fragments that the placeholder retrieved, in ascending order of distance. `query` placeholders do not appear.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Maps the name of each retrieval placeholder to the fragments that the placeholder's search returns.",
                  "additionalProperties": {
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/Fragment"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "The `x-pipeline-id` header is missing (plain text ``Header of type `x-pipeline-id` was missing``) or is not a valid identifier (`Invalid pipeline ID`), or a placeholder cannot run (`Invalid parameter`). `details.error` holds the reason, such as `Missing parameter '<name>'` when `prompt` lacks the value that a retrieval placeholder targets."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "404": {
            "description": "The agent does not exist or the key lacks execute permission on the agent (`Agent not found`), the pipeline does not exist or the key lacks execute permission on the pipeline (`Pipeline not found`), or a placeholder names an embedding model outside the pipeline (`Embedding Model with id <id> not found`)."
          },
          "500": {
            "description": "Retrieval failed (`Internal error`). `details.error` holds the cause, such as a failure of the embedding model or an invalid filter."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Runs the retrieval placeholders of an agent against the pipeline named in the `x-pipeline-id` header, without calling an LLM, and returns the fragments that each retrieval placeholder retrieves. The body takes the `prompt`, `classification` and `filters` fields of an agent execution. A client application uses the dry run to test the placeholders, filters and classifications of an agent.\n\n**Permissions.** Execute on the agent and on the pipeline.\n\n[Agents and prompt templates](../../concepts/08-agents-prompt-templates.md) describes retrieval placeholders, and [Filter operators](../03-filter-operators.md) describes the filter language.",
        "x-position": 8,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X POST \"$FOUNDATION4_URL/agents/$AGENT_ID/search\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\" \\\n  -H \"x-pipeline-id: $PIPELINE_ID\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"prompt\": {\n    \"question\": \"How can finance export invoices?\"\n  },\n  \"classification\": \"internal\"\n}'"
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import json\nimport os\nimport urllib.error\nimport urllib.request\n\nbody = {\n    \"prompt\": {\n        \"question\": \"How can finance export invoices?\",\n    },\n    \"classification\": \"internal\",\n}\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/agents/{os.environ['AGENT_ID']}/search\",\n    method=\"POST\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n        \"x-pipeline-id\": os.environ[\"PIPELINE_ID\"],\n        \"Content-Type\": \"application/json\",\n    },\n    data=json.dumps(body).encode(),\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/agents/${process.env.AGENT_ID}/search`, {\n  method: \"POST\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n    \"x-pipeline-id\": process.env.PIPELINE_ID!,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    prompt: {\n      question: \"How can finance export invoices?\",\n    },\n    classification: \"internal\",\n  }),\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"json\"\nrequire \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/agents/#{ENV.fetch(\"AGENT_ID\")}/search\")\nrequest = Net::HTTP::Post.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nrequest[\"x-pipeline-id\"] = ENV.fetch(\"PIPELINE_ID\")\nrequest[\"Content-Type\"] = \"application/json\"\nrequest.body = JSON.generate({\n  \"prompt\" => {\n    \"question\" => \"How can finance export invoices?\",\n  },\n  \"classification\" => \"internal\",\n})\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/api-keys": {
      "get": {
        "tags": [
          "Authentication"
        ],
        "summary": "List API keys",
        "operationId": "list_api_keys",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "uuid"
            },
            "description": "Returns only the API key with this identifier."
          },
          {
            "name": "name",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Returns only API keys whose name equals this value, case-sensitive."
          },
          {
            "name": "name$contains",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "Matches objects whose `name` contains the value, case-sensitive. Repeat the parameter to require several values."
          },
          {
            "name": "name$startswith",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Matches objects whose `name` starts with the value."
          },
          {
            "name": "name$gt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Matches objects whose `name` is greater than the value."
          },
          {
            "name": "name$ge",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Matches objects whose `name` is greater than or equal to the value."
          },
          {
            "name": "name$lt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Matches objects whose `name` is less than the value."
          },
          {
            "name": "name$le",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Matches objects whose `name` is less than or equal to the value."
          },
          {
            "name": "description",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Returns only API keys whose description equals this value, case-sensitive."
          },
          {
            "name": "description$contains",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "Matches objects whose `description` contains the value, case-sensitive. Repeat the parameter to require several values."
          },
          {
            "name": "created_at",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Returns only API keys created at exactly this time, in RFC 3339 format."
          },
          {
            "name": "created_at$gt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` is greater than the value."
          },
          {
            "name": "created_at$lt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` is less than the value."
          },
          {
            "name": "created_at$ge",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` is greater than or equal to the value."
          },
          {
            "name": "created_at$le",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` is less than or equal to the value."
          },
          {
            "name": "updated_at",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Returns only API keys last changed at exactly this time, in RFC 3339 format."
          },
          {
            "name": "updated_at$gt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` is greater than the value."
          },
          {
            "name": "updated_at$lt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` is less than the value."
          },
          {
            "name": "updated_at$ge",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` is greater than or equal to the value."
          },
          {
            "name": "updated_at$le",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` is less than or equal to the value."
          },
          {
            "name": "first",
            "in": "query",
            "description": "Cursor mode: the number of objects to return from the start of the list, or after the `after` cursor.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "after",
            "in": "query",
            "description": "Cursor mode: the cursor after which the page starts, taken from `page_info.after` of the previous page.",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "name": "last",
            "in": "query",
            "description": "Cursor mode: the number of objects to return before the `before` cursor.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "before",
            "in": "query",
            "description": "Cursor mode: the cursor before which the page ends, taken from `page_info.before`.",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Offset mode: the number of objects to return. The default page size is 25.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Offset mode: the number of objects to skip.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "count",
            "in": "query",
            "description": "When `true`, adds `page_info.count`, the total number of matching objects.",
            "required": false,
            "schema": {
              "type": [
                "boolean",
                "null"
              ]
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Sort fields: `id`, `created_at`, `updated_at`, `name`, `active`, `expiration`. A `-` prefix sorts in descending order. A field name alone sorts in ascending order, as does a `+` prefix sent encoded as `%2B`. Repeat the parameter to sort by several fields. The default order is `id` ascending.",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The body is a page of API keys, without secrets, in the pagination envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Paginated_ApiKeyResponse"
                }
              }
            }
          },
          "400": {
            "description": "The request combines cursor and offset parameters, combines `first` with `last` or carries an invalid cursor (`Pagination error`), or `order_by` names a field that the list cannot be sorted by (`Invalid order_by parameter`)."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Returns a page of the API keys that the calling key can read, without the secrets. The list supports filters, ordering and cursor or offset pagination, as described in [API conventions](../01-api-conventions.md).\n\n**Permissions.** Read on the API keys. The list contains only the keys that the calling key can read.",
        "x-position": 9,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl \"$FOUNDATION4_URL/api-keys\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/api-keys\",\n    method=\"GET\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/api-keys`, {\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/api-keys\")\nrequest = Net::HTTP::Get.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      },
      "post": {
        "tags": [
          "Authentication"
        ],
        "summary": "Create an API key",
        "operationId": "create_api_key",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateApiKeyRequest"
              },
              "example": {
                "name": "support-portal-search",
                "description": "Search key for the support portal",
                "expiration": "2027-09-30T00:00:00Z"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "The API key was created. The body is the new key, including the generated secret in `secret`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyWithSecret"
                }
              }
            }
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "403": {
            "description": "The calling key lacks write permission on the `api-keys` object type, or requests a permission or classification that the calling key does not hold (`Unauthorized: access level ... required for Api Key with id None`). The same status is returned when the license is not valid (`Invalid license: ...`) or the license limit for API keys is reached (`License limits exceeded for Api Key`)."
          },
          "409": {
            "description": "An API key with the same name exists (`Conflict unique error`)."
          },
          "422": {
            "description": "The body does not match the request schema, for example a permission value outside 0 to 7 or an unknown object type. The response body is plain text."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Creates an API key with permissions on object types and returns the new key with a generated secret. Foundation4 returns the secret only in this response and stores only a hash, so a lost secret cannot be recovered. Permissions on individual objects are granted afterward with `POST /api-keys/{api_key_id}/permissions`.\n\n**Permissions.** Write on the `api-keys` object type. Each permission in `permissions` must be contained in the calling key's permission on the same object type. When the calling key's allow-list on `pipelines` is not `*`, each classification in `classifications` must be in the calling key's allow-list.\n\n[Access control](../../concepts/09-access-control.md) describes permissions and classification allow-lists.",
        "x-position": 10,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X POST \"$FOUNDATION4_URL/api-keys\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"name\": \"support-portal-search\",\n  \"description\": \"Search key for the support portal\",\n  \"expiration\": \"2027-09-30T00:00:00Z\"\n}'"
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import json\nimport os\nimport urllib.error\nimport urllib.request\n\nbody = {\n    \"name\": \"support-portal-search\",\n    \"description\": \"Search key for the support portal\",\n    \"expiration\": \"2027-09-30T00:00:00Z\",\n}\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/api-keys\",\n    method=\"POST\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n        \"Content-Type\": \"application/json\",\n    },\n    data=json.dumps(body).encode(),\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/api-keys`, {\n  method: \"POST\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    name: \"support-portal-search\",\n    description: \"Search key for the support portal\",\n    expiration: \"2027-09-30T00:00:00Z\",\n  }),\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"json\"\nrequire \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/api-keys\")\nrequest = Net::HTTP::Post.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nrequest[\"Content-Type\"] = \"application/json\"\nrequest.body = JSON.generate({\n  \"name\" => \"support-portal-search\",\n  \"description\" => \"Search key for the support portal\",\n  \"expiration\" => \"2027-09-30T00:00:00Z\",\n})\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/api-keys/{api_key_id}": {
      "get": {
        "tags": [
          "Authentication"
        ],
        "summary": "Get an API key",
        "operationId": "get_api_key",
        "parameters": [
          {
            "name": "api_key_id",
            "in": "path",
            "description": "Identifier of the API key.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The body is the API key, without the secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyResponse"
                }
              }
            }
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "404": {
            "description": "No API key with this identifier exists, or the calling key lacks read permission on the API key (`ApiKey not found`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Returns one API key, without the secret.\n\n**Permissions.** Read on the API key.",
        "x-position": 11,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl \"$FOUNDATION4_URL/api-keys/$API_KEY_ID\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/api-keys/{os.environ['API_KEY_ID']}\",\n    method=\"GET\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/api-keys/${process.env.API_KEY_ID}`, {\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/api-keys/#{ENV.fetch(\"API_KEY_ID\")}\")\nrequest = Net::HTTP::Get.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      },
      "delete": {
        "tags": [
          "Authentication"
        ],
        "summary": "Delete an API key",
        "operationId": "delete_api_key",
        "parameters": [
          {
            "name": "api_key_id",
            "in": "path",
            "description": "Identifier of the API key.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "The API key and the key's permission entries were deleted. The response has no body."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "403": {
            "description": "The request names the calling key, or the calling key lacks write permission on the `api-keys` object type (`Unauthorized: access level AccessLevel(WRITE) required for Api Key with id Some(<id>)`)."
          },
          "404": {
            "description": "No API key with this identifier exists, or the calling key lacks write permission on the API key (`Api Key with id <id> not found`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Deletes an API key and the key's permission entries. Requests that use the deleted key are refused from the next request. A key cannot delete itself.\n\n**Permissions.** Write on the `api-keys` object type.",
        "x-position": 13,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X DELETE \"$FOUNDATION4_URL/api-keys/$API_KEY_ID\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/api-keys/{os.environ['API_KEY_ID']}\",\n    method=\"DELETE\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/api-keys/${process.env.API_KEY_ID}`, {\n  method: \"DELETE\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/api-keys/#{ENV.fetch(\"API_KEY_ID\")}\")\nrequest = Net::HTTP::Delete.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      },
      "patch": {
        "tags": [
          "Authentication"
        ],
        "summary": "Update an API key",
        "operationId": "update_api_key",
        "parameters": [
          {
            "name": "api_key_id",
            "in": "path",
            "description": "Identifier of the API key.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateApiKeyRequest"
              },
              "example": {
                "active": false
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "The API key was updated. The body is the updated key, without the secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyResponse"
                }
              }
            }
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "403": {
            "description": "The license does not permit changes (`Invalid license: ...`)."
          },
          "404": {
            "description": "No API key with this identifier exists, or the calling key lacks write permission on the API key (`Api Key with id <id> not found`)."
          },
          "409": {
            "description": "Another API key has the same name (`Conflict unique error`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Changes the name, description, active status or expiration time of an API key. Fields that the request omits keep their values, and `null` removes the description or the expiration time. Deactivation with `\"active\": false` takes effect on the next request that uses the key.\n\n**Permissions.** Write on the API key.",
        "x-position": 12,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X PATCH \"$FOUNDATION4_URL/api-keys/$API_KEY_ID\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"active\": false\n}'"
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import json\nimport os\nimport urllib.error\nimport urllib.request\n\nbody = {\n    \"active\": False,\n}\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/api-keys/{os.environ['API_KEY_ID']}\",\n    method=\"PATCH\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n        \"Content-Type\": \"application/json\",\n    },\n    data=json.dumps(body).encode(),\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/api-keys/${process.env.API_KEY_ID}`, {\n  method: \"PATCH\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    active: false,\n  }),\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"json\"\nrequire \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/api-keys/#{ENV.fetch(\"API_KEY_ID\")}\")\nrequest = Net::HTTP::Patch.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nrequest[\"Content-Type\"] = \"application/json\"\nrequest.body = JSON.generate({\n  \"active\" => false,\n})\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/api-keys/{api_key_id}/permissions": {
      "get": {
        "tags": [
          "Authentication"
        ],
        "summary": "List the permissions of an API key",
        "operationId": "get_api_key_permissions",
        "parameters": [
          {
            "name": "api_key_id",
            "in": "path",
            "description": "Identifier of the API key.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The body is the list of permission entries of the API key. The classifications of each entry are listed in alphabetical order, whatever the order in which they were granted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ApiKeyPermission"
                  }
                }
              }
            }
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "404": {
            "description": "No API key with this identifier exists, or the calling key lacks read permission on the API key (`Api Key with id <id> not found`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Returns every permission entry of an API key: the entries on object types and the entries on individual objects. An entry on an object type has the object identifier `00000000-0000-0000-0000-000000000000`.\n\n**Permissions.** Read on the API key.\n\n[Access control](../../concepts/09-access-control.md) describes permission entries.",
        "x-position": 14,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl \"$FOUNDATION4_URL/api-keys/$API_KEY_ID/permissions\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/api-keys/{os.environ['API_KEY_ID']}/permissions\",\n    method=\"GET\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/api-keys/${process.env.API_KEY_ID}/permissions`, {\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/api-keys/#{ENV.fetch(\"API_KEY_ID\")}/permissions\")\nrequest = Net::HTTP::Get.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      },
      "post": {
        "tags": [
          "Authentication"
        ],
        "summary": "Set the permissions of an API key",
        "operationId": "set_api_key_permissions",
        "parameters": [
          {
            "name": "api_key_id",
            "in": "path",
            "description": "Identifier of the API key.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetApiKeyPermissionRequest"
              },
              "example": {
                "permissions": [
                  {
                    "object_type": "pipelines",
                    "object_id": "$PIPELINE_ID",
                    "permission": 5
                  }
                ],
                "classifications": [
                  "public",
                  "internal"
                ]
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "The permission entries were applied. The response has no body."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "403": {
            "description": "The request grants a permission or classification that the calling key does not hold (`Unauthorized: access level ... required for Api Key with id ...`), or the license does not permit changes (`Invalid license: ...`)."
          },
          "404": {
            "description": "No API key with this identifier exists, or the calling key lacks write permission on the API key (`Api Key with id <id> not found`)."
          },
          "422": {
            "description": "The body does not match the request schema, for example a permission value outside 0 to 7 or an unknown object type. The response body is plain text."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Adds, changes or removes permission entries of an API key; entries that the request does not name are unchanged. An entry replaces the entry with the same object type and object identifier, and a permission of 0 removes the entry. Foundation4 applies all entries in one transaction, so a refused entry leaves every entry unchanged.\n\n**Permissions.** Write on the API key. Each granted permission must be contained in the calling key's permission on the object type or on the object. When the calling key's allow-list on `pipelines` is not `*`, the granted classifications must be in the calling key's allow-list for the pipeline.\n\n[Scoped keys](../../concepts/09-access-control.md#scoped-keys) describes the request with an example.",
        "x-position": 15,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X POST \"$FOUNDATION4_URL/api-keys/$API_KEY_ID/permissions\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"permissions\": [\n    {\n      \"object_type\": \"pipelines\",\n      \"object_id\": \"'\"$PIPELINE_ID\"'\",\n      \"permission\": 5\n    }\n  ],\n  \"classifications\": [\n    \"public\",\n    \"internal\"\n  ]\n}'"
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import json\nimport os\nimport urllib.error\nimport urllib.request\n\nbody = {\n    \"permissions\": [\n        {\n            \"object_type\": \"pipelines\",\n            \"object_id\": os.environ[\"PIPELINE_ID\"],\n            \"permission\": 5,\n        },\n    ],\n    \"classifications\": [\n        \"public\",\n        \"internal\",\n    ],\n}\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/api-keys/{os.environ['API_KEY_ID']}/permissions\",\n    method=\"POST\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n        \"Content-Type\": \"application/json\",\n    },\n    data=json.dumps(body).encode(),\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/api-keys/${process.env.API_KEY_ID}/permissions`, {\n  method: \"POST\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    permissions: [\n      {\n        object_type: \"pipelines\",\n        object_id: process.env.PIPELINE_ID,\n        permission: 5,\n      },\n    ],\n    classifications: [\n      \"public\",\n      \"internal\",\n    ],\n  }),\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"json\"\nrequire \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/api-keys/#{ENV.fetch(\"API_KEY_ID\")}/permissions\")\nrequest = Net::HTTP::Post.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nrequest[\"Content-Type\"] = \"application/json\"\nrequest.body = JSON.generate({\n  \"permissions\" => [\n    {\n      \"object_type\" => \"pipelines\",\n      \"object_id\" => ENV.fetch(\"PIPELINE_ID\"),\n      \"permission\" => 5,\n    },\n  ],\n  \"classifications\" => [\n    \"public\",\n    \"internal\",\n  ],\n})\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/documents": {
      "post": {
        "summary": "Add a document with pipeline ID in body",
        "operationId": "create_document",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateDocumentRequest"
              },
              "example": {
                "pipeline_id": "$PIPELINE_ID",
                "classification": "public",
                "external_identifier": "kb-password-reset",
                "metadata": {
                  "product": "accounts"
                },
                "contents": "To reset a password, open Settings, choose Security and select Reset password. A reset link is sent to the registered email address and expires after 30 minutes."
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "The version was accepted. The body is the new version, with the status `pending`, or `failed` when the processing job could not be queued.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentResponse"
                }
              }
            }
          },
          "400": {
            "description": "The metadata does not satisfy the pipeline's metadata schema (`Invalid metadata`), or a new version names a classification that differs from the classification of the existing document (`Classification mismatch`)."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "403": {
            "description": "The license does not permit the operation (`Invalid license: ...`), or the key's classification allow-list does not permit the classification (`Unauthorized: access level ... required for Pipeline with id ...`)."
          },
          "404": {
            "description": "No pipeline with the identifier in `pipeline_id` exists or the key lacks execute permission on the pipeline (`Pipeline with id <id> not found`), or the pipeline does not define the classification or the key's allow-list excludes the classification (`Classification not found`). The text splitter does not exist or the key lacks execute permission on the text splitter (`Text Splitter with id <id> not found`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "tags": [
          "Documents"
        ],
        "description": "Adds a document, or a new version of an existing document, to the pipeline named in the `pipeline_id` field of the body. The operation behaves as `POST /pipelines/{pipeline_id}/documents`: processing is asynchronous, and the response returns the new version with the status `pending`, or `failed` when the processing job cannot be queued.\n\n**Permissions.** Read and execute on the pipeline, execute on the text splitter that processes the document, and the document's classification in the allow-list.\n\n[Documents, versions and fragments](../../concepts/02-documents-versions-fragments.md) describes the request fields, processing and versions.",
        "x-position": 16,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X POST \"$FOUNDATION4_URL/documents\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"pipeline_id\": \"'\"$PIPELINE_ID\"'\",\n  \"classification\": \"public\",\n  \"external_identifier\": \"kb-password-reset\",\n  \"metadata\": {\n    \"product\": \"accounts\"\n  },\n  \"contents\": \"To reset a password, open Settings, choose Security and select Reset password. A reset link is sent to the registered email address and expires after 30 minutes.\"\n}'"
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import json\nimport os\nimport urllib.error\nimport urllib.request\n\nbody = {\n    \"pipeline_id\": os.environ[\"PIPELINE_ID\"],\n    \"classification\": \"public\",\n    \"external_identifier\": \"kb-password-reset\",\n    \"metadata\": {\n        \"product\": \"accounts\",\n    },\n    \"contents\": \"To reset a password, open Settings, choose Security and select Reset password. A reset link is sent to the registered email address and expires after 30 minutes.\",\n}\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/documents\",\n    method=\"POST\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n        \"Content-Type\": \"application/json\",\n    },\n    data=json.dumps(body).encode(),\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/documents`, {\n  method: \"POST\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    pipeline_id: process.env.PIPELINE_ID,\n    classification: \"public\",\n    external_identifier: \"kb-password-reset\",\n    metadata: {\n      product: \"accounts\",\n    },\n    contents: \"To reset a password, open Settings, choose Security and select Reset password. A reset link is sent to the registered email address and expires after 30 minutes.\",\n  }),\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"json\"\nrequire \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/documents\")\nrequest = Net::HTTP::Post.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nrequest[\"Content-Type\"] = \"application/json\"\nrequest.body = JSON.generate({\n  \"pipeline_id\" => ENV.fetch(\"PIPELINE_ID\"),\n  \"classification\" => \"public\",\n  \"external_identifier\" => \"kb-password-reset\",\n  \"metadata\" => {\n    \"product\" => \"accounts\",\n  },\n  \"contents\" => \"To reset a password, open Settings, choose Security and select Reset password. A reset link is sent to the registered email address and expires after 30 minutes.\",\n})\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/documents/{document_id}": {
      "get": {
        "tags": [
          "Documents"
        ],
        "summary": "Get a document version",
        "description": "Returns one version of a document, found by the document identifier alone. Without the `version` query parameter, the response is the latest version of the document, whether or not that version has expired. The `status` field of the response shows whether processing of the version is complete.\n\n**Permissions.** Read on the document's pipeline.\n\n[Documents, versions and fragments](../../concepts/02-documents-versions-fragments.md) describes versions and the processing status.",
        "operationId": "get_document_info",
        "parameters": [
          {
            "name": "document_id",
            "in": "path",
            "description": "Identifier of the document.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "version",
            "in": "query",
            "description": "Version to return, in microseconds since the Unix epoch, as returned in the `version` field. Without the parameter, the operation returns the latest version.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The version was found. The body is the document version.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentResponse"
                }
              }
            }
          },
          "400": {
            "description": "The `version` value lies outside the range of valid timestamps (`Invalid version`)."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "403": {
            "description": "The key lacks read permission on the pipeline that contains the document (`Unauthorized: access level ... required for Pipeline with id ...`)."
          },
          "404": {
            "description": "No document with this identifier exists, or the document has no version with the given `version` value (`Document not found`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "x-position": 17,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl \"$FOUNDATION4_URL/documents/$DOCUMENT_ID\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/documents/{os.environ['DOCUMENT_ID']}\",\n    method=\"GET\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/documents/${process.env.DOCUMENT_ID}`, {\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/documents/#{ENV.fetch(\"DOCUMENT_ID\")}\")\nrequest = Net::HTTP::Get.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      },
      "delete": {
        "summary": "Delete or expire a document by ID",
        "operationId": "delete_document",
        "parameters": [
          {
            "name": "document_id",
            "in": "path",
            "description": "Identifier of the document.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "as_of",
            "in": "query",
            "description": "Point in time in microseconds since the Unix epoch. The operation then applies only to versions created at or before that time.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "expire",
            "in": "query",
            "description": "Whether to expire the document instead of deleting the document. The default is `false`.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The document was expired (`expire=true`). The body is empty."
          },
          "204": {
            "description": "The document was deleted. The body is empty."
          },
          "400": {
            "description": "The `as_of` value lies outside the range of valid timestamps (`Invalid version`)."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "403": {
            "description": "The key lacks write or execute permission on the pipeline, or the key's classification allow-list for the pipeline does not include the document's classification (`Unauthorized: access level ... required for Pipeline with id ...`). An expiry also returns 403 when the license does not permit the operation (`Invalid license: ...`)."
          },
          "404": {
            "description": "No document with this identifier exists, or no version of the document was created at or before `as_of` (`Document with id <id> not found`). A deletion also returns 404 when the key lacks read permission on the pipeline (`Pipeline with id <id> not found`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "tags": [
          "Documents"
        ],
        "description": "Deletes or expires a document found by the document identifier alone, without the pipeline identifier. Without `expire`, the operation permanently removes every version and every fragment of the document and returns status 204. With `expire=true`, the operation marks every current version as expired and returns status 200, and the version history remains readable.\n\n**Permissions.** To delete: read, write and execute on the pipeline, and the document's classification in the allow-list. To expire: write and execute on the pipeline, and the document's classification in the allow-list.\n\n[Documents, versions and fragments](../../concepts/02-documents-versions-fragments.md) compares expiry and deletion.",
        "x-position": 18,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X DELETE \"$FOUNDATION4_URL/documents/$DOCUMENT_ID\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/documents/{os.environ['DOCUMENT_ID']}\",\n    method=\"DELETE\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/documents/${process.env.DOCUMENT_ID}`, {\n  method: \"DELETE\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/documents/#{ENV.fetch(\"DOCUMENT_ID\")}\")\nrequest = Net::HTTP::Delete.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/documents/{document_id}/versions": {
      "get": {
        "tags": [
          "Documents"
        ],
        "summary": "List document versions",
        "description": "Returns the versions of a document as a JSON array, newest first, without the list envelope. By default the array contains only current versions, and `include_expired=true` adds the expired versions. A document identifier that matches no version returns an empty array.\n\n**Permissions.** Read on the document's pipeline.\n\n[Documents, versions and fragments](../../concepts/02-documents-versions-fragments.md) describes versions and point-in-time reads.",
        "operationId": "get_document_versions",
        "parameters": [
          {
            "name": "document_id",
            "in": "path",
            "description": "Identifier of the document.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "as_of",
            "in": "query",
            "description": "Point in time in microseconds since the Unix epoch. The array then contains the versions created at or before that time and, without `include_expired`, only the versions that had not expired at that time.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "include_expired",
            "in": "query",
            "description": "Whether to include expired versions. The default is `false`.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The body is an array of the document's versions, newest first. The array is empty when no version matches.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/DocumentResponse"
                  }
                }
              }
            }
          },
          "400": {
            "description": "The `as_of` value lies outside the range of valid timestamps (`Invalid version`)."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "403": {
            "description": "The key lacks read permission on the pipeline that contains the document (`Unauthorized: access level ... required for Pipeline with id ...`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "x-position": 19,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl \"$FOUNDATION4_URL/documents/$DOCUMENT_ID/versions\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/documents/{os.environ['DOCUMENT_ID']}/versions\",\n    method=\"GET\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/documents/${process.env.DOCUMENT_ID}/versions`, {\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/documents/#{ENV.fetch(\"DOCUMENT_ID\")}/versions\")\nrequest = Net::HTTP::Get.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/embedding-models": {
      "get": {
        "tags": [
          "Embedding Models"
        ],
        "summary": "List embedding models",
        "operationId": "list_embedding_models",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "uuid"
            },
            "description": "Returns only the embedding model with this identifier."
          },
          {
            "name": "name",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Returns only embedding models whose name equals this value, case-sensitive."
          },
          {
            "name": "name$contains",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "Matches objects whose `name` contains the value, case-sensitive. Repeat the parameter to require several values."
          },
          {
            "name": "name$startswith",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Matches objects whose `name` starts with the value."
          },
          {
            "name": "name$gt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Matches objects whose `name` is greater than the value."
          },
          {
            "name": "name$ge",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Matches objects whose `name` is greater than or equal to the value."
          },
          {
            "name": "name$lt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Matches objects whose `name` is less than the value."
          },
          {
            "name": "name$le",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Matches objects whose `name` is less than or equal to the value."
          },
          {
            "name": "provider",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Returns only embedding models whose provider name equals this value, such as `FastEmbedEmbeddings`. The match is case-sensitive."
          },
          {
            "name": "provider$contains",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "Matches objects whose `provider` contains the value, case-sensitive. Repeat the parameter to require several values."
          },
          {
            "name": "provider$startswith",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Matches objects whose `provider` starts with the value."
          },
          {
            "name": "description",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Returns only embedding models whose description equals this value, case-sensitive."
          },
          {
            "name": "description$contains",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "Matches objects whose `description` contains the value, case-sensitive. Repeat the parameter to require several values."
          },
          {
            "name": "created_at",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Returns only embedding models created at exactly this time, in RFC 3339 format."
          },
          {
            "name": "created_at$gt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` is greater than the value."
          },
          {
            "name": "created_at$lt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` is less than the value."
          },
          {
            "name": "created_at$ge",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` is greater than or equal to the value."
          },
          {
            "name": "created_at$le",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` is less than or equal to the value."
          },
          {
            "name": "updated_at",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Returns only embedding models last changed at exactly this time, in RFC 3339 format."
          },
          {
            "name": "updated_at$gt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` is greater than the value."
          },
          {
            "name": "updated_at$lt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` is less than the value."
          },
          {
            "name": "updated_at$ge",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` is greater than or equal to the value."
          },
          {
            "name": "updated_at$le",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` is less than or equal to the value."
          },
          {
            "name": "first",
            "in": "query",
            "description": "Cursor mode: the number of objects to return from the start of the list, or after the `after` cursor.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "after",
            "in": "query",
            "description": "Cursor mode: the cursor after which the page starts, taken from `page_info.after` of the previous page.",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "name": "last",
            "in": "query",
            "description": "Cursor mode: the number of objects to return before the `before` cursor.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "before",
            "in": "query",
            "description": "Cursor mode: the cursor before which the page ends, taken from `page_info.before`.",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Offset mode: the number of objects to return. The default page size is 25.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Offset mode: the number of objects to skip.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "count",
            "in": "query",
            "description": "When `true`, adds `page_info.count`, the total number of matching objects.",
            "required": false,
            "schema": {
              "type": [
                "boolean",
                "null"
              ]
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Sort fields: `id`, `created_at`, `updated_at`, `name`, `provider`. A `-` prefix sorts in descending order. A field name alone sorts in ascending order, as does a `+` prefix sent encoded as `%2B`. Repeat the parameter to sort by several fields. The default order is `id` ascending.",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of embedding models. The body is the pagination envelope, with the embedding models in `data`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Paginated_EmbeddingModelResponse"
                }
              }
            }
          },
          "400": {
            "description": "The pagination parameters are invalid, such as cursor and offset parameters in one request (`Pagination error`), or `order_by` names a field that the operation cannot sort by (`Invalid order_by parameter`)."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Returns a page of the embedding models that the key can read. Filters apply to the name, provider, description and timestamps. `order_by` accepts `id`, `created_at`, `updated_at`, `name` and `provider`. [API conventions](../01-api-conventions.md) describes pagination, filters and ordering.\n\n**Permissions.** Read on the embedding models. The list contains only the embedding models that the key can read.",
        "x-position": 20,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl \"$FOUNDATION4_URL/embedding-models\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/embedding-models\",\n    method=\"GET\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/embedding-models`, {\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/embedding-models\")\nrequest = Net::HTTP::Get.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      },
      "post": {
        "tags": [
          "Embedding Models"
        ],
        "summary": "Create an embedding model",
        "operationId": "create_embedding_model",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateEmbeddingModelRequest"
              },
              "example": {
                "name": "minilm-l6",
                "description": "FastEmbed all-MiniLM-L6-v2",
                "provider": "FastEmbedEmbeddings",
                "model": "Qdrant/all-MiniLM-L6-v2-onnx",
                "size": 0
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "The embedding model was created. The body is the new embedding model, with `size` set to the measured number of dimensions.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmbeddingModelResponse"
                }
              }
            }
          },
          "400": {
            "description": "The request is invalid (`Invalid parameter`), and `details.error` names the cause: an unknown provider name, settings that the provider does not accept or a `size` that differs from the measured number of dimensions."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "403": {
            "description": "The key lacks write permission on the `embedding-models` object type (`Unauthorized: access level AccessLevel(WRITE) required for Embedding Model with id None`). The same status reports a license that is not valid (`Invalid license: <reason>`) and a reached license limit (`License limits exceeded for Embedding Model`)."
          },
          "404": {
            "description": "The key lacks write permission on the embedding provider that `provider` names (`Embedding Provider not found`)."
          },
          "409": {
            "description": "An embedding model with this `name` already exists (`Conflict unique error`)."
          },
          "500": {
            "description": "The provider failed while embedding the test string, for example because the gRPC service or the model server is unreachable (`Internal error`). `details.error` holds the cause."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Creates an embedding model: a configured instance of an embedding provider, with a model name and provider parameters. Before storing the embedding model, Foundation4 embeds a test string with the provider, so the request fails when the provider cannot load the model. A `size` of 0 stores the measured number of dimensions, and a nonzero `size` must equal the measured number. After creation, only `name` and `description` can change.\n\n**Permissions.** Write on the `embedding-models` object type and write on the embedding provider that `provider` names.\n\n[Embedding models and text splitters](../../concepts/06-embedding-models-text-splitters.md) shows example requests, and [Providers and models](../../reference/01-providers-and-models.md) lists the models and parameters of each provider.",
        "x-position": 21,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X POST \"$FOUNDATION4_URL/embedding-models\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"name\": \"minilm-l6\",\n  \"description\": \"FastEmbed all-MiniLM-L6-v2\",\n  \"provider\": \"FastEmbedEmbeddings\",\n  \"model\": \"Qdrant/all-MiniLM-L6-v2-onnx\",\n  \"size\": 0\n}'"
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import json\nimport os\nimport urllib.error\nimport urllib.request\n\nbody = {\n    \"name\": \"minilm-l6\",\n    \"description\": \"FastEmbed all-MiniLM-L6-v2\",\n    \"provider\": \"FastEmbedEmbeddings\",\n    \"model\": \"Qdrant/all-MiniLM-L6-v2-onnx\",\n    \"size\": 0,\n}\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/embedding-models\",\n    method=\"POST\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n        \"Content-Type\": \"application/json\",\n    },\n    data=json.dumps(body).encode(),\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/embedding-models`, {\n  method: \"POST\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    name: \"minilm-l6\",\n    description: \"FastEmbed all-MiniLM-L6-v2\",\n    provider: \"FastEmbedEmbeddings\",\n    model: \"Qdrant/all-MiniLM-L6-v2-onnx\",\n    size: 0,\n  }),\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"json\"\nrequire \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/embedding-models\")\nrequest = Net::HTTP::Post.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nrequest[\"Content-Type\"] = \"application/json\"\nrequest.body = JSON.generate({\n  \"name\" => \"minilm-l6\",\n  \"description\" => \"FastEmbed all-MiniLM-L6-v2\",\n  \"provider\" => \"FastEmbedEmbeddings\",\n  \"model\" => \"Qdrant/all-MiniLM-L6-v2-onnx\",\n  \"size\" => 0,\n})\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/embedding-models/{embedding_model_id}": {
      "get": {
        "tags": [
          "Embedding Models"
        ],
        "summary": "Get an embedding model",
        "operationId": "get_embedding",
        "parameters": [
          {
            "name": "embedding_model_id",
            "in": "path",
            "description": "Identifier of the embedding model.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The embedding model was found. The body is the embedding model.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmbeddingModelResponse"
                }
              }
            }
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "404": {
            "description": "No embedding model with this identifier exists, or the key lacks read permission on the embedding model (`Embedding model not found`). `details.id` holds the identifier."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Returns one embedding model: the provider, the model name, the number of dimensions and the provider parameters.\n\n**Permissions.** Read on the embedding model.",
        "x-position": 22,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl \"$FOUNDATION4_URL/embedding-models/$EMBEDDING_MODEL_ID\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/embedding-models/{os.environ['EMBEDDING_MODEL_ID']}\",\n    method=\"GET\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/embedding-models/${process.env.EMBEDDING_MODEL_ID}`, {\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/embedding-models/#{ENV.fetch(\"EMBEDDING_MODEL_ID\")}\")\nrequest = Net::HTTP::Get.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      },
      "delete": {
        "tags": [
          "Embedding Models"
        ],
        "summary": "Delete an embedding model",
        "operationId": "delete_embedding_model",
        "parameters": [
          {
            "name": "embedding_model_id",
            "in": "path",
            "description": "Identifier of the embedding model.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "The embedding model was deleted. The response has no body."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "403": {
            "description": "The key lacks write permission on the embedding model (`Unauthorized: access level AccessLevel(WRITE) required for Embedding Model with id Some(<id>)`)."
          },
          "404": {
            "description": "No embedding model with this identifier exists (`Embedding Model with id <id> not found`)."
          },
          "409": {
            "description": "A pipeline uses the embedding model (`Conflict related error`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Deletes an embedding model. An embedding model that a pipeline uses cannot be deleted: the request returns HTTP 409 until every pipeline that uses the embedding model is deleted.\n\n**Permissions.** Write on the embedding model.",
        "x-position": 24,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X DELETE \"$FOUNDATION4_URL/embedding-models/$EMBEDDING_MODEL_ID\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/embedding-models/{os.environ['EMBEDDING_MODEL_ID']}\",\n    method=\"DELETE\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/embedding-models/${process.env.EMBEDDING_MODEL_ID}`, {\n  method: \"DELETE\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/embedding-models/#{ENV.fetch(\"EMBEDDING_MODEL_ID\")}\")\nrequest = Net::HTTP::Delete.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      },
      "patch": {
        "tags": [
          "Embedding Models"
        ],
        "summary": "Update an embedding model",
        "operationId": "update_embedding_model",
        "parameters": [
          {
            "name": "embedding_model_id",
            "in": "path",
            "description": "Identifier of the embedding model.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateEmbeddingModelRequest"
              },
              "example": {
                "description": "FastEmbed all-MiniLM-L6-v2, 384 dimensions"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "The embedding model was updated. The body is the updated embedding model.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmbeddingModelResponse"
                }
              }
            }
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "403": {
            "description": "The license is not valid (`Invalid license: <reason>`)."
          },
          "404": {
            "description": "No embedding model with this identifier exists, or the key lacks write permission on the embedding model (`Embedding Model with id <id> not found`)."
          },
          "409": {
            "description": "Another embedding model already uses the new `name` (`Conflict unique error`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Changes the `name` or the `description` of an embedding model. Fields that the request omits keep their values, and `\"description\": null` removes the description. The provider, model name, size and parameters cannot change, and Foundation4 ignores these fields in the request. A different model or different parameters require a new embedding model.\n\n**Permissions.** Write on the embedding model.",
        "x-position": 23,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X PATCH \"$FOUNDATION4_URL/embedding-models/$EMBEDDING_MODEL_ID\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"description\": \"FastEmbed all-MiniLM-L6-v2, 384 dimensions\"\n}'"
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import json\nimport os\nimport urllib.error\nimport urllib.request\n\nbody = {\n    \"description\": \"FastEmbed all-MiniLM-L6-v2, 384 dimensions\",\n}\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/embedding-models/{os.environ['EMBEDDING_MODEL_ID']}\",\n    method=\"PATCH\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n        \"Content-Type\": \"application/json\",\n    },\n    data=json.dumps(body).encode(),\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/embedding-models/${process.env.EMBEDDING_MODEL_ID}`, {\n  method: \"PATCH\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    description: \"FastEmbed all-MiniLM-L6-v2, 384 dimensions\",\n  }),\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"json\"\nrequire \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/embedding-models/#{ENV.fetch(\"EMBEDDING_MODEL_ID\")}\")\nrequest = Net::HTTP::Patch.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nrequest[\"Content-Type\"] = \"application/json\"\nrequest.body = JSON.generate({\n  \"description\" => \"FastEmbed all-MiniLM-L6-v2, 384 dimensions\",\n})\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/embedding-models/{embedding_model_id}/query": {
      "post": {
        "tags": [
          "Embedding Models"
        ],
        "summary": "Embed a text with an embedding model",
        "operationId": "query_embedding_model",
        "parameters": [
          {
            "name": "embedding_model_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Identifier of the embedding model."
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/QueryEmbeddingRequest"
              },
              "example": {
                "query": "How can finance export invoices?"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "The text was converted. The body is a JSON array of numbers whose length equals the `size` of the embedding model.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "number",
                    "format": "double"
                  }
                }
              }
            }
          },
          "400": {
            "description": "The API server cannot load the embedding model, for example because the model files are missing (`Invalid parameter`). `details.error` holds the reason."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "404": {
            "description": "No embedding model with this identifier exists, or the key lacks read and execute permission on the embedding model (`Embedding model not found`). `details.id` holds the identifier."
          },
          "500": {
            "description": "The embedding model failed to convert the text, for example because the gRPC service or the model server is unreachable (`Internal error`). `details.error` holds the cause."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Converts one text into a vector with the embedding model and returns the vector. Client applications use this operation to test an embedding model. The vector has `size` numbers, one for each dimension of the embedding model. Foundation4 embeds the text as given, with no prefix or instruction. The first request for an embedding model on each API server instance loads the model.\n\n**Permissions.** Read and execute on the embedding model.",
        "x-position": 25,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X POST \"$FOUNDATION4_URL/embedding-models/$EMBEDDING_MODEL_ID/query\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"query\": \"How can finance export invoices?\"\n}'"
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import json\nimport os\nimport urllib.error\nimport urllib.request\n\nbody = {\n    \"query\": \"How can finance export invoices?\",\n}\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/embedding-models/{os.environ['EMBEDDING_MODEL_ID']}/query\",\n    method=\"POST\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n        \"Content-Type\": \"application/json\",\n    },\n    data=json.dumps(body).encode(),\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/embedding-models/${process.env.EMBEDDING_MODEL_ID}/query`, {\n  method: \"POST\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    query: \"How can finance export invoices?\",\n  }),\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"json\"\nrequire \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/embedding-models/#{ENV.fetch(\"EMBEDDING_MODEL_ID\")}/query\")\nrequest = Net::HTTP::Post.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nrequest[\"Content-Type\"] = \"application/json\"\nrequest.body = JSON.generate({\n  \"query\" => \"How can finance export invoices?\",\n})\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/healthz": {
      "get": {
        "tags": [
          "Core"
        ],
        "summary": "Check the API server health",
        "description": "Returns a health report of the API server in JSON. A response shows that the API server accepts HTTP requests.\n\n**Permissions.** None. The operation requires no API key.",
        "operationId": "health",
        "responses": {
          "200": {
            "description": "The API server accepts HTTP requests. The body is the health report.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthResponse"
                },
                "examples": {
                  "System up and working": {
                    "value": {
                      "cache": "ok",
                      "database": "ok",
                      "llm_service": "ok",
                      "message_queue": "ok",
                      "status": "ok"
                    }
                  }
                }
              }
            }
          }
        },
        "x-position": 26,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl \"$FOUNDATION4_URL/healthz\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/healthz\",\n    method=\"GET\",\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/healthz`);\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/healthz\")\nrequest = Net::HTTP::Get.new(uri)\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/llms": {
      "get": {
        "summary": "List LLMs",
        "operationId": "list_llms",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "uuid"
            },
            "description": "Returns only the LLM with this identifier."
          },
          {
            "name": "name",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Returns only the LLM with exactly this name."
          },
          {
            "name": "name$contains",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "Matches objects whose `name` contains the value, case-sensitive. Repeat the parameter to require several values."
          },
          {
            "name": "name$startswith",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Matches objects whose `name` starts with the value."
          },
          {
            "name": "name$gt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Matches objects whose `name` is greater than the value."
          },
          {
            "name": "name$ge",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Matches objects whose `name` is greater than or equal to the value."
          },
          {
            "name": "name$lt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Matches objects whose `name` is less than the value."
          },
          {
            "name": "name$le",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Matches objects whose `name` is less than or equal to the value."
          },
          {
            "name": "description",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Returns only LLMs with exactly this description."
          },
          {
            "name": "description$contains",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "Matches objects whose `description` contains the value, case-sensitive. Repeat the parameter to require several values."
          },
          {
            "name": "endpoint",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Returns only LLMs with exactly this endpoint URL."
          },
          {
            "name": "endpoint$contains",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "Matches objects whose `endpoint` contains the value, case-sensitive. Repeat the parameter to require several values."
          },
          {
            "name": "created_at",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Returns only LLMs created at exactly this time, as an RFC 3339 timestamp."
          },
          {
            "name": "created_at$gt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` is greater than the value."
          },
          {
            "name": "created_at$lt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` is less than the value."
          },
          {
            "name": "created_at$ge",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` is greater than or equal to the value."
          },
          {
            "name": "created_at$le",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` is less than or equal to the value."
          },
          {
            "name": "updated_at",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Returns only LLMs last changed at exactly this time, as an RFC 3339 timestamp."
          },
          {
            "name": "updated_at$gt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` is greater than the value."
          },
          {
            "name": "updated_at$lt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` is less than the value."
          },
          {
            "name": "updated_at$ge",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` is greater than or equal to the value."
          },
          {
            "name": "updated_at$le",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` is less than or equal to the value."
          },
          {
            "name": "first",
            "in": "query",
            "description": "Cursor mode: the number of objects to return from the start of the list, or after the `after` cursor.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "after",
            "in": "query",
            "description": "Cursor mode: the cursor after which the page starts, taken from `page_info.after` of the previous page.",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "name": "last",
            "in": "query",
            "description": "Cursor mode: the number of objects to return before the `before` cursor.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "before",
            "in": "query",
            "description": "Cursor mode: the cursor before which the page ends, taken from `page_info.before`.",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Offset mode: the number of objects to return. The default page size is 25.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Offset mode: the number of objects to skip.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "count",
            "in": "query",
            "description": "When `true`, adds `page_info.count`, the total number of matching objects.",
            "required": false,
            "schema": {
              "type": [
                "boolean",
                "null"
              ]
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Sort fields: `id`, `created_at`, `updated_at`, `name`. A `-` prefix sorts in descending order. A field name alone sorts in ascending order, as does a `+` prefix sent encoded as `%2B`. Repeat the parameter to sort by several fields. The default order is `id` ascending.",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of LLM registrations. `data` holds the LLMs, `page_info` describes the page and `query_info` repeats the filters that the server recognized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Paginated_LlmResponse"
                }
              }
            }
          },
          "400": {
            "description": "`order_by` names a field that the list cannot sort by (`Invalid order_by parameter`), or the pagination parameters conflict or carry an invalid cursor (`Pagination error`)."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "tags": [
          "Llms"
        ],
        "description": "Returns one page of the LLM registrations that the key can read, in the list envelope. Query parameters filter the list by field values and set the order and the page. The list has no filter on the model name.\n\n**Permissions.** Read on the LLMs in the list. The list contains only the LLMs that the key can read, so a key without read permission on any LLM receives an empty list.\n\n[API conventions](../01-api-conventions.md) describes pagination, filters and ordering.",
        "x-position": 27,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl \"$FOUNDATION4_URL/llms\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/llms\",\n    method=\"GET\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/llms`, {\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/llms\")\nrequest = Net::HTTP::Get.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      },
      "post": {
        "summary": "Register an LLM",
        "operationId": "create_llm",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateLLMRequest"
              },
              "example": {
                "name": "internal-general",
                "description": "General-purpose model on the internal model server",
                "endpoint": "http://llm.internal:8000/v1",
                "model": "example-model-8b-instruct",
                "api_key": "change-me"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "The LLM was registered. The body is the new LLM registration, without the API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LlmResponse"
                }
              }
            }
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "403": {
            "description": "The key lacks write permission on the `llms` object type (`Unauthorized: access level ... required for LLM ...`), the license is not valid (`Invalid license: <reason>`) or the license limit for LLMs is reached (`License limits exceeded for LLM`)."
          },
          "409": {
            "description": "Another LLM already has this name (`Conflict unique error`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "tags": [
          "Llms"
        ],
        "description": "Registers a connection to a model server that exposes an OpenAI-compatible API. Foundation4 does not contact the model server during registration, so an incorrect endpoint or API key appears only when the LLM is first used. Foundation4 encrypts the API key before storage, and no response returns the key.\n\n**Permissions.** Write on the LLM object type (`llms`).\n\n[LLMs](../../concepts/07-llms.md) describes the fields of a registration and the requirements on the model server.",
        "x-position": 28,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X POST \"$FOUNDATION4_URL/llms\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"name\": \"internal-general\",\n  \"description\": \"General-purpose model on the internal model server\",\n  \"endpoint\": \"http://llm.internal:8000/v1\",\n  \"model\": \"example-model-8b-instruct\",\n  \"api_key\": \"change-me\"\n}'"
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import json\nimport os\nimport urllib.error\nimport urllib.request\n\nbody = {\n    \"name\": \"internal-general\",\n    \"description\": \"General-purpose model on the internal model server\",\n    \"endpoint\": \"http://llm.internal:8000/v1\",\n    \"model\": \"example-model-8b-instruct\",\n    \"api_key\": \"change-me\",\n}\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/llms\",\n    method=\"POST\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n        \"Content-Type\": \"application/json\",\n    },\n    data=json.dumps(body).encode(),\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/llms`, {\n  method: \"POST\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    name: \"internal-general\",\n    description: \"General-purpose model on the internal model server\",\n    endpoint: \"http://llm.internal:8000/v1\",\n    model: \"example-model-8b-instruct\",\n    api_key: \"change-me\",\n  }),\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"json\"\nrequire \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/llms\")\nrequest = Net::HTTP::Post.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nrequest[\"Content-Type\"] = \"application/json\"\nrequest.body = JSON.generate({\n  \"name\" => \"internal-general\",\n  \"description\" => \"General-purpose model on the internal model server\",\n  \"endpoint\" => \"http://llm.internal:8000/v1\",\n  \"model\" => \"example-model-8b-instruct\",\n  \"api_key\" => \"change-me\",\n})\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/llms/{llm_id}": {
      "get": {
        "summary": "Get an LLM",
        "operationId": "get_llm",
        "parameters": [
          {
            "name": "llm_id",
            "in": "path",
            "description": "Identifier of the LLM.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The LLM registration, without the API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LlmResponse"
                }
              }
            }
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "404": {
            "description": "No LLM with this identifier exists, or the key lacks read permission on the LLM (`LLM not found`). `details.id` holds the identifier."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "tags": [
          "Llms"
        ],
        "description": "Returns the registration of one LLM. The response never contains the API key of the registration.\n\n**Permissions.** Read on the LLM.\n\n[LLMs](../../concepts/07-llms.md) describes the fields of an LLM registration.",
        "x-position": 29,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl \"$FOUNDATION4_URL/llms/$LLM_ID\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/llms/{os.environ['LLM_ID']}\",\n    method=\"GET\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/llms/${process.env.LLM_ID}`, {\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/llms/#{ENV.fetch(\"LLM_ID\")}\")\nrequest = Net::HTTP::Get.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      },
      "delete": {
        "summary": "Delete an LLM",
        "operationId": "delete_llm",
        "parameters": [
          {
            "name": "llm_id",
            "in": "path",
            "description": "Identifier of the LLM.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "The LLM was deleted. The response has no body."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "403": {
            "description": "The key lacks write permission on the LLM (`Unauthorized: access level ... required for LLM with id ...`)."
          },
          "404": {
            "description": "No LLM with this identifier exists (`LLM with id <id> not found`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "tags": [
          "Llms"
        ],
        "description": "Deletes an LLM registration. Agents store no LLM, so the deletion changes no agent. Agent executions and queries that name the deleted LLM then return HTTP 404.\n\n**Permissions.** Write on the LLM.",
        "x-position": 31,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X DELETE \"$FOUNDATION4_URL/llms/$LLM_ID\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/llms/{os.environ['LLM_ID']}\",\n    method=\"DELETE\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/llms/${process.env.LLM_ID}`, {\n  method: \"DELETE\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/llms/#{ENV.fetch(\"LLM_ID\")}\")\nrequest = Net::HTTP::Delete.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      },
      "patch": {
        "summary": "Update an LLM",
        "operationId": "update_llm",
        "parameters": [
          {
            "name": "llm_id",
            "in": "path",
            "description": "Identifier of the LLM.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateLLMRequest"
              },
              "example": {
                "model": "example-model-70b-instruct",
                "api_key": "change-me"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "The LLM was updated. The body is the updated LLM registration, without the API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LlmResponse"
                }
              }
            }
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "403": {
            "description": "The license is not valid (`Invalid license: <reason>`)."
          },
          "404": {
            "description": "No LLM with this identifier exists, or the key lacks write permission on the LLM (`LLM with id <id> not found`)."
          },
          "409": {
            "description": "Another LLM already has the requested name (`Conflict unique error`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "tags": [
          "Llms"
        ],
        "description": "Changes the fields of an LLM registration that the request names, and keeps the stored value of every omitted field. A `null` value clears `description` or `api_key`, and a new `api_key` value replaces the stored key. Foundation4 does not contact the model server during the update.\n\n**Permissions.** Write on the LLM.\n\n[LLMs](../../concepts/07-llms.md) describes the fields of a registration.",
        "x-position": 30,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X PATCH \"$FOUNDATION4_URL/llms/$LLM_ID\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"model\": \"example-model-70b-instruct\",\n  \"api_key\": \"change-me\"\n}'"
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import json\nimport os\nimport urllib.error\nimport urllib.request\n\nbody = {\n    \"model\": \"example-model-70b-instruct\",\n    \"api_key\": \"change-me\",\n}\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/llms/{os.environ['LLM_ID']}\",\n    method=\"PATCH\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n        \"Content-Type\": \"application/json\",\n    },\n    data=json.dumps(body).encode(),\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/llms/${process.env.LLM_ID}`, {\n  method: \"PATCH\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    model: \"example-model-70b-instruct\",\n    api_key: \"change-me\",\n  }),\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"json\"\nrequire \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/llms/#{ENV.fetch(\"LLM_ID\")}\")\nrequest = Net::HTTP::Patch.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nrequest[\"Content-Type\"] = \"application/json\"\nrequest.body = JSON.generate({\n  \"model\" => \"example-model-70b-instruct\",\n  \"api_key\" => \"change-me\",\n})\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/llms/{llm_id}/query": {
      "post": {
        "summary": "Query an LLM",
        "operationId": "query_llm",
        "parameters": [
          {
            "name": "llm_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Identifier of the LLM."
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/QueryLlmRequest"
              },
              "example": {
                "query": "In one sentence, what is a text splitter?",
                "stream": false
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "The answer in the format that `stream` selects: NDJSON lines of `ApiLlmResponse` objects, server-sent events with the same objects as data, or the complete answer as plain text. A streamed response has status 200 as soon as the response starts.",
            "content": {
              "application/jsonstream": {
                "schema": {
                  "$ref": "#/components/schemas/ApiLlmResponse"
                }
              },
              "text/event-stream": {
                "schema": {
                  "$ref": "#/components/schemas/ApiLlmResponse"
                }
              },
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "The LLM registration has no API key (`Invalid parameter`, with `API key is required for OpenAI provider` in `details.error`)."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "403": {
            "description": "The license is not valid (`Invalid license: <reason>`)."
          },
          "404": {
            "description": "No LLM with this identifier exists, or the key lacks execute permission on the LLM (`LLM with id <id> not found`)."
          },
          "500": {
            "description": "With `\"stream\": false`, the model server returned an error or could not be reached (`Stream error: <reason>`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "tags": [
          "Llms"
        ],
        "description": "Sends `query` to the LLM as a single user message, without a system message or retrieval, and returns the generated answer. The `stream` field selects the response format: newline-delimited JSON (NDJSON) by default, server-sent events with `\"sse\"` or plain text with `false`. The direct query calls the Responses API of the model server, so the LLM registration requires an API key.\n\n**Permissions.** Execute on the LLM.\n\n[Response formats](../../concepts/07-llms.md#response-formats) describes the three formats, and [API conventions](../01-api-conventions.md#streaming-responses) describes how a model server failure appears in each format.",
        "x-position": 32,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X POST \"$FOUNDATION4_URL/llms/$LLM_ID/query\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"query\": \"In one sentence, what is a text splitter?\",\n  \"stream\": false\n}'"
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import json\nimport os\nimport urllib.error\nimport urllib.request\n\nbody = {\n    \"query\": \"In one sentence, what is a text splitter?\",\n    \"stream\": False,\n}\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/llms/{os.environ['LLM_ID']}/query\",\n    method=\"POST\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n        \"Content-Type\": \"application/json\",\n    },\n    data=json.dumps(body).encode(),\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/llms/${process.env.LLM_ID}/query`, {\n  method: \"POST\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    query: \"In one sentence, what is a text splitter?\",\n    stream: false,\n  }),\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"json\"\nrequire \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/llms/#{ENV.fetch(\"LLM_ID\")}/query\")\nrequest = Net::HTTP::Post.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nrequest[\"Content-Type\"] = \"application/json\"\nrequest.body = JSON.generate({\n  \"query\" => \"In one sentence, what is a text splitter?\",\n  \"stream\" => false,\n})\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/login": {
      "post": {
        "tags": [
          "Authentication"
        ],
        "summary": "Check an API key",
        "description": "Checks the API key in the `x-api-key` and `x-api-key-secret` headers and returns the name and description of the key and the key's permissions on object types. The request has no body. The response has status 201, although the operation creates no object.\n\n**Permissions.** None. Any valid API key can call the operation.\n\n[Authenticate](../../get-started/02-authenticate.md) describes the authentication headers.",
        "operationId": "login",
        "responses": {
          "201": {
            "description": "The key is valid. The body contains the name and description of the key and the key's permissions on object types.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "x-position": 33,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X POST \"$FOUNDATION4_URL/login\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/login\",\n    method=\"POST\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/login`, {\n  method: \"POST\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/login\")\nrequest = Net::HTTP::Post.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/openai/v1/chat/completions": {
      "post": {
        "summary": "Relay a chat completion",
        "operationId": "post_completions",
        "parameters": [
          {
            "name": "X-Llm-Id",
            "in": "header",
            "description": "Identifier of the registered LLM that receives the request.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GenericObject"
              },
              "example": {
                "messages": [
                  {
                    "role": "system",
                    "content": "Answer in one sentence."
                  },
                  {
                    "role": "user",
                    "content": "What is retrieval-augmented generation?"
                  }
                ],
                "temperature": 0.2
              }
            }
          },
          "required": true,
          "description": "An OpenAI chat completion request, such as `{\"messages\": [{\"role\": \"user\", \"content\": \"What is retrieval-augmented generation?\"}]}`. Foundation4 forwards every field and inserts the registered model name when the body has no `model` field. A request with `\"stream\": true` receives server-sent events."
        },
        "responses": {
          "200": {
            "description": "The model server's response, relayed unchanged. A non-streamed request receives the model server's body and headers, typically a chat completion object in JSON; a request with `\"stream\": true` receives the model server's server-sent events as `text/event-stream`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "The chat completion object of the model server."
                }
              },
              "text/event-stream": {
                "schema": {
                  "type": "string",
                  "description": "The server-sent events of the model server, relayed unchanged."
                }
              }
            }
          },
          "400": {
            "description": "The `x-llm-id` header is missing or is not a valid identifier (`Invalid LLM ID: <reason>`), or the request carries one or two of the headers `X-Agent-Id`, `X-Pipeline-Id` and `X-Pipeline-Classification` (`Missing required headers: ...`)."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "404": {
            "description": "No LLM with this identifier exists, or the key lacks execute permission on the LLM (`LLM not found`)."
          },
          "500": {
            "description": "Foundation4 could not reach the model server or read the model server's response. The message is the error text of the HTTP client."
          },
          "501": {
            "description": "The request carries all three headers `X-Agent-Id`, `X-Pipeline-Id` and `X-Pipeline-Classification` (`F4ai enriched completions not implemented yet`)."
          },
          "default": {
            "description": "An error response of the model server, relayed with the model server's status and body."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "tags": [
          "Llms"
        ],
        "description": "Relays an OpenAI chat completion request to the chat completions API of the LLM named in the `x-llm-id` header. Foundation4 forwards the body unchanged, inserts the registered model name when the body has no `model` field and sends the API key of the registration, when the registration has one, as a bearer token. Foundation4 returns the model server's status and body, including error responses, and performs no retrieval, prompt templating or tracing.\n\n**Permissions.** Execute on the LLM.\n\n[LLMs](../../concepts/07-llms.md#openai-compatible-endpoint) describes the endpoint.",
        "x-position": 34,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X POST \"$FOUNDATION4_URL/openai/v1/chat/completions\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\" \\\n  -H \"x-llm-id: $LLM_ID\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"messages\": [\n    {\n      \"role\": \"system\",\n      \"content\": \"Answer in one sentence.\"\n    },\n    {\n      \"role\": \"user\",\n      \"content\": \"What is retrieval-augmented generation?\"\n    }\n  ],\n  \"temperature\": 0.2\n}'"
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import json\nimport os\nimport urllib.error\nimport urllib.request\n\nbody = {\n    \"messages\": [\n        {\n            \"role\": \"system\",\n            \"content\": \"Answer in one sentence.\",\n        },\n        {\n            \"role\": \"user\",\n            \"content\": \"What is retrieval-augmented generation?\",\n        },\n    ],\n    \"temperature\": 0.2,\n}\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/openai/v1/chat/completions\",\n    method=\"POST\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n        \"x-llm-id\": os.environ[\"LLM_ID\"],\n        \"Content-Type\": \"application/json\",\n    },\n    data=json.dumps(body).encode(),\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/openai/v1/chat/completions`, {\n  method: \"POST\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n    \"x-llm-id\": process.env.LLM_ID!,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    messages: [\n      {\n        role: \"system\",\n        content: \"Answer in one sentence.\",\n      },\n      {\n        role: \"user\",\n        content: \"What is retrieval-augmented generation?\",\n      },\n    ],\n    temperature: 0.2,\n  }),\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"json\"\nrequire \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/openai/v1/chat/completions\")\nrequest = Net::HTTP::Post.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nrequest[\"x-llm-id\"] = ENV.fetch(\"LLM_ID\")\nrequest[\"Content-Type\"] = \"application/json\"\nrequest.body = JSON.generate({\n  \"messages\" => [\n    {\n      \"role\" => \"system\",\n      \"content\" => \"Answer in one sentence.\",\n    },\n    {\n      \"role\" => \"user\",\n      \"content\" => \"What is retrieval-augmented generation?\",\n    },\n  ],\n  \"temperature\" => 0.2,\n})\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/permissions": {
      "get": {
        "tags": [
          "Authentication"
        ],
        "summary": "Get permissions on object types",
        "operationId": "get_object_type_permissions",
        "responses": {
          "200": {
            "description": "The body maps each object type on which the calling key holds a permission to an object with the permission (`access_level`) and the classification allow-list (`classifications`).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {
                    "$ref": "#/components/schemas/PermissionEntry"
                  },
                  "propertyNames": {
                    "type": "string",
                    "description": "Object type, such as `pipelines`.",
                    "enum": [
                      "agents",
                      "api-keys",
                      "contexts",
                      "context-messages",
                      "documents",
                      "embedding-models",
                      "embedding-providers",
                      "llms",
                      "pipelines",
                      "taxonomies",
                      "text-splitter-providers",
                      "text-splitters",
                      "permissions",
                      "fragments"
                    ]
                  }
                }
              }
            }
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Returns the permissions of the calling API key on object types, with the classification allow-list of the `pipelines` permission. Permissions on individual objects are not included; `GET /permissions/{object_type}/{object_id}` reports the permission on one object.\n\n**Permissions.** None. The operation reports the permissions of the calling key, and any valid API key can call the operation.\n\n[Access control](../../concepts/09-access-control.md) describes the permission model.",
        "x-position": 35,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl \"$FOUNDATION4_URL/permissions\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/permissions\",\n    method=\"GET\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/permissions`, {\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/permissions\")\nrequest = Net::HTTP::Get.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/permissions/{object_type}": {
      "get": {
        "tags": [
          "Authentication"
        ],
        "summary": "Get permissions on several objects",
        "operationId": "get_many_object_permissions",
        "parameters": [
          {
            "name": "object_type",
            "in": "path",
            "description": "Object type, in kebab case, such as `pipelines`, `api-keys` or `text-splitters`.",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/ObjectTypes"
            }
          },
          {
            "name": "object_id",
            "in": "query",
            "description": "Identifier of an object. The parameter is repeated for each object.",
            "required": true,
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "format": "uuid"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The body maps each requested object identifier to the calling key's permission on the object, a number from 0 to 7, whether or not the object exists. A request without `object_id` returns an empty object.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {
                    "$ref": "#/components/schemas/AccessLevel"
                  },
                  "propertyNames": {
                    "type": "string",
                    "format": "uuid"
                  }
                }
              }
            }
          },
          "400": {
            "description": "The object type is not a known object type (`Invalid object type`)."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Returns the permissions of the calling API key on several objects of one type, as an object that maps each object identifier to a permission from 0 to 7. The request names each object in a separate `object_id` query parameter, such as `?object_id=<id>&object_id=<id>`. Each permission combines the key's permission on the object type with the key's permission on the object.\n\n**Permissions.** None. The operation reports the permissions of the calling key, and any valid API key can call the operation.\n\n[Access control](../../concepts/09-access-control.md) describes the permission model.",
        "x-position": 36,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl \"$FOUNDATION4_URL/permissions/$OBJECT_TYPE?object_id=$OBJECT_ID\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/permissions/{os.environ['OBJECT_TYPE']}?object_id={os.environ['OBJECT_ID']}\",\n    method=\"GET\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/permissions/${process.env.OBJECT_TYPE}?object_id=${process.env.OBJECT_ID}`, {\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/permissions/#{ENV.fetch(\"OBJECT_TYPE\")}?object_id=#{ENV.fetch(\"OBJECT_ID\")}\")\nrequest = Net::HTTP::Get.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/permissions/{object_type}/{object_id}": {
      "get": {
        "tags": [
          "Authentication"
        ],
        "summary": "Get the permission on an object",
        "operationId": "get_object_permissions",
        "parameters": [
          {
            "name": "object_type",
            "in": "path",
            "description": "Object type, in kebab case, such as `pipelines`, `api-keys` or `text-splitters`.",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/ObjectTypes"
            }
          },
          {
            "name": "object_id",
            "in": "path",
            "description": "Identifier of the object.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The body is the calling key's permission on the object, a number from 0 to 7. The operation does not check that the object exists.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccessLevel"
                }
              }
            }
          },
          "400": {
            "description": "The object type is not a known object type (`Invalid object type`)."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Returns the permission of the calling API key on one object, as the sum of the permission bits: read 4, write 2 and execute 1. The value combines the key's permission on the object type with the key's permission on the object.\n\n**Permissions.** None. The operation reports the permissions of the calling key, and any valid API key can call the operation.\n\n[Access control](../../concepts/09-access-control.md) describes the permission model.",
        "x-position": 37,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl \"$FOUNDATION4_URL/permissions/$OBJECT_TYPE/$OBJECT_ID\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/permissions/{os.environ['OBJECT_TYPE']}/{os.environ['OBJECT_ID']}\",\n    method=\"GET\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/permissions/${process.env.OBJECT_TYPE}/${process.env.OBJECT_ID}`, {\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/permissions/#{ENV.fetch(\"OBJECT_TYPE\")}/#{ENV.fetch(\"OBJECT_ID\")}\")\nrequest = Net::HTTP::Get.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/pipelines": {
      "get": {
        "tags": [
          "Pipelines"
        ],
        "summary": "List pipelines",
        "operationId": "list_pipelines",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "uuid"
            },
            "description": "Returns only the pipeline with this identifier."
          },
          {
            "name": "name",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Returns only pipelines whose name equals this value, case-sensitive."
          },
          {
            "name": "name$contains",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "Matches objects whose `name` contains the value, case-sensitive. Repeat the parameter to require several values."
          },
          {
            "name": "name$startswith",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Matches objects whose `name` starts with the value."
          },
          {
            "name": "name$gt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Matches objects whose `name` is greater than the value."
          },
          {
            "name": "name$ge",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Matches objects whose `name` is greater than or equal to the value."
          },
          {
            "name": "name$lt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Matches objects whose `name` is less than the value."
          },
          {
            "name": "name$le",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Matches objects whose `name` is less than or equal to the value."
          },
          {
            "name": "description",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Returns only pipelines whose description equals this value, case-sensitive."
          },
          {
            "name": "description$contains",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "Matches objects whose `description` contains the value, case-sensitive. Repeat the parameter to require several values."
          },
          {
            "name": "created_at",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` equals the value."
          },
          {
            "name": "created_at$gt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` is greater than the value."
          },
          {
            "name": "created_at$lt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` is less than the value."
          },
          {
            "name": "created_at$ge",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` is greater than or equal to the value."
          },
          {
            "name": "created_at$le",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` is less than or equal to the value."
          },
          {
            "name": "updated_at",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` equals the value."
          },
          {
            "name": "updated_at$gt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` is greater than the value."
          },
          {
            "name": "updated_at$lt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` is less than the value."
          },
          {
            "name": "updated_at$ge",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` is greater than or equal to the value."
          },
          {
            "name": "updated_at$le",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` is less than or equal to the value."
          },
          {
            "name": "first",
            "in": "query",
            "description": "Cursor mode: the number of objects to return from the start of the list, or after the `after` cursor.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "after",
            "in": "query",
            "description": "Cursor mode: the cursor after which the page starts, taken from `page_info.after` of the previous page.",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "name": "last",
            "in": "query",
            "description": "Cursor mode: the number of objects to return before the `before` cursor.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "before",
            "in": "query",
            "description": "Cursor mode: the cursor before which the page ends, taken from `page_info.before`.",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Offset mode: the number of objects to return. The default page size is 25.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Offset mode: the number of objects to skip.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "count",
            "in": "query",
            "description": "When `true`, adds `page_info.count`, the total number of matching objects.",
            "required": false,
            "schema": {
              "type": [
                "boolean",
                "null"
              ]
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Sort fields: `id`, `created_at`, `updated_at`, `name`. A `-` prefix sorts in descending order. A field name alone sorts in ascending order, as does a `+` prefix sent encoded as `%2B`. Repeat the parameter to sort by several fields. The default order is `id` ascending.",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The body is a paginated envelope whose `data` array holds the pipelines the key can read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Paginated_PipelineResponse"
                }
              }
            }
          },
          "400": {
            "description": "A pagination or `order_by` parameter is invalid (`Pagination error` or `Invalid order_by parameter`)."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Returns a page of pipelines that the key can read. The response is a paginated envelope. Results can be filtered by field and ordered, as described in [API conventions](../01-api-conventions.md).\n\n**Permissions.** Read on a pipeline includes that pipeline in the list. The list returns only the pipelines the key can read.",
        "x-position": 38,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl \"$FOUNDATION4_URL/pipelines\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/pipelines\",\n    method=\"GET\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/pipelines`, {\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/pipelines\")\nrequest = Net::HTTP::Get.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      },
      "post": {
        "tags": [
          "Pipelines"
        ],
        "summary": "Create a pipeline",
        "operationId": "create_pipeline",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePipelineRequest"
              },
              "example": {
                "name": "support-kb",
                "description": "Support knowledge base",
                "embedding_model_id": "$EMBEDDING_MODEL_ID",
                "default_text_splitter_id": "$TEXT_SPLITTER_ID",
                "classifications": [
                  "public",
                  [
                    "internal",
                    "public"
                  ]
                ],
                "has_full_text_search": true,
                "schema": {
                  "type": "object",
                  "properties": {
                    "product": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "The pipeline was created. The body is the new pipeline.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PipelineResponse"
                }
              }
            }
          },
          "400": {
            "description": "The metadata schema in the request is not a valid schema (`Schema error`)."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "403": {
            "description": "The key lacks write permission on the `pipelines` object type, or the license does not allow another pipeline (`Invalid license` or `License limits exceeded for Pipeline`)."
          },
          "404": {
            "description": "The request names a text splitter or embedding model that does not exist, or that the key cannot use (`Text Splitter not found` or `Embedding Model with id <id> not found`)."
          },
          "409": {
            "description": "A pipeline with this name already exists (`Conflict unique error`)."
          },
          "422": {
            "description": "A required field such as `name`, `default_text_splitter_id` or `classifications` is missing, or a field has the wrong type. The response body is plain text and names the field (`Failed to deserialize the JSON body into the target type: missing field ...`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Creates a pipeline. The embedding model and the full-text search setting are fixed at creation and cannot change afterwards. The request names the classifications the pipeline defines and an optional metadata schema. The response body is the new pipeline.\n\n**Permissions.** Write on the `pipelines` object type. Creating a pipeline also requires write on the text splitter named in the request, and write on the embedding model when the request names one.\n\nSee [Pipelines](../../concepts/01-pipelines.md).",
        "x-position": 39,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X POST \"$FOUNDATION4_URL/pipelines\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"name\": \"support-kb\",\n  \"description\": \"Support knowledge base\",\n  \"embedding_model_id\": \"'\"$EMBEDDING_MODEL_ID\"'\",\n  \"default_text_splitter_id\": \"'\"$TEXT_SPLITTER_ID\"'\",\n  \"classifications\": [\n    \"public\",\n    [\n      \"internal\",\n      \"public\"\n    ]\n  ],\n  \"has_full_text_search\": true,\n  \"schema\": {\n    \"type\": \"object\",\n    \"properties\": {\n      \"product\": {\n        \"type\": \"string\"\n      }\n    }\n  }\n}'"
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import json\nimport os\nimport urllib.error\nimport urllib.request\n\nbody = {\n    \"name\": \"support-kb\",\n    \"description\": \"Support knowledge base\",\n    \"embedding_model_id\": os.environ[\"EMBEDDING_MODEL_ID\"],\n    \"default_text_splitter_id\": os.environ[\"TEXT_SPLITTER_ID\"],\n    \"classifications\": [\n        \"public\",\n        [\n            \"internal\",\n            \"public\",\n        ],\n    ],\n    \"has_full_text_search\": True,\n    \"schema\": {\n        \"type\": \"object\",\n        \"properties\": {\n            \"product\": {\n                \"type\": \"string\",\n            },\n        },\n    },\n}\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/pipelines\",\n    method=\"POST\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n        \"Content-Type\": \"application/json\",\n    },\n    data=json.dumps(body).encode(),\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/pipelines`, {\n  method: \"POST\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    name: \"support-kb\",\n    description: \"Support knowledge base\",\n    embedding_model_id: process.env.EMBEDDING_MODEL_ID,\n    default_text_splitter_id: process.env.TEXT_SPLITTER_ID,\n    classifications: [\n      \"public\",\n      [\n        \"internal\",\n        \"public\",\n      ],\n    ],\n    has_full_text_search: true,\n    schema: {\n      type: \"object\",\n      properties: {\n        product: {\n          type: \"string\",\n        },\n      },\n    },\n  }),\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"json\"\nrequire \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/pipelines\")\nrequest = Net::HTTP::Post.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nrequest[\"Content-Type\"] = \"application/json\"\nrequest.body = JSON.generate({\n  \"name\" => \"support-kb\",\n  \"description\" => \"Support knowledge base\",\n  \"embedding_model_id\" => ENV.fetch(\"EMBEDDING_MODEL_ID\"),\n  \"default_text_splitter_id\" => ENV.fetch(\"TEXT_SPLITTER_ID\"),\n  \"classifications\" => [\n    \"public\",\n    [\n      \"internal\",\n      \"public\",\n    ],\n  ],\n  \"has_full_text_search\" => true,\n  \"schema\" => {\n    \"type\" => \"object\",\n    \"properties\" => {\n      \"product\" => {\n        \"type\" => \"string\",\n      },\n    },\n  },\n})\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/pipelines/{pipeline_id}": {
      "get": {
        "tags": [
          "Pipelines"
        ],
        "summary": "Get a pipeline",
        "operationId": "get_pipeline",
        "parameters": [
          {
            "name": "pipeline_id",
            "in": "path",
            "description": "Identifier of the pipeline.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The body is the pipeline and the embedding models of the pipeline.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PipelineResponse"
                }
              }
            }
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "404": {
            "description": "No pipeline with this identifier exists, or the key lacks read permission on the pipeline (`Pipeline not found`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Returns a pipeline by identifier. The response body is the pipeline together with the embedding models the pipeline uses, keyed by vector embedding identifier.\n\n**Permissions.** Read on the pipeline.\n\nSee [Pipelines](../../concepts/01-pipelines.md).",
        "x-position": 40,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl \"$FOUNDATION4_URL/pipelines/$PIPELINE_ID\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/pipelines/{os.environ['PIPELINE_ID']}\",\n    method=\"GET\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/pipelines/${process.env.PIPELINE_ID}`, {\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/pipelines/#{ENV.fetch(\"PIPELINE_ID\")}\")\nrequest = Net::HTTP::Get.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      },
      "delete": {
        "tags": [
          "Pipelines"
        ],
        "summary": "Delete a pipeline",
        "operationId": "delete_pipeline",
        "parameters": [
          {
            "name": "pipeline_id",
            "in": "path",
            "description": "Identifier of the pipeline.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "The pipeline was deleted. The response has no body."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "403": {
            "description": "The key lacks write permission on the pipeline (`Unauthorized`)."
          },
          "404": {
            "description": "No pipeline with this identifier exists (`Pipeline with id <id> not found`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Deletes a pipeline, every document and version in the pipeline, and the pipeline's tables. The deletion is permanent. The response has no body.\n\n**Permissions.** Write on the pipeline.\n\nSee [Pipelines](../../concepts/01-pipelines.md).",
        "x-position": 42,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X DELETE \"$FOUNDATION4_URL/pipelines/$PIPELINE_ID\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/pipelines/{os.environ['PIPELINE_ID']}\",\n    method=\"DELETE\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/pipelines/${process.env.PIPELINE_ID}`, {\n  method: \"DELETE\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/pipelines/#{ENV.fetch(\"PIPELINE_ID\")}\")\nrequest = Net::HTTP::Delete.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      },
      "patch": {
        "tags": [
          "Pipelines"
        ],
        "summary": "Update a pipeline",
        "operationId": "update_pipeline",
        "parameters": [
          {
            "name": "pipeline_id",
            "in": "path",
            "description": "Identifier of the pipeline.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdatePipelineRequest"
              },
              "example": {
                "description": "Support knowledge base for every product"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "The pipeline was updated. The body is the pipeline as it was before the change.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PipelineResponse"
                }
              }
            }
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "403": {
            "description": "The license does not allow the change (`Invalid license`)."
          },
          "404": {
            "description": "No pipeline with this identifier exists, or the key lacks write permission on the pipeline (`Pipeline not found`)."
          },
          "409": {
            "description": "The new name is already in use, or the request names a text splitter that does not exist (`Conflict unique error` or `Conflict related error`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Changes the name, description, default text splitter or metadata schema of a pipeline. The embedding model, the full-text search setting and the classifications cannot be changed through this operation. The response body shows the pipeline as it was before the change, so a client application reads the pipeline with `GET /pipelines/{pipeline_id}` to confirm the new values.\n\n**Permissions.** Write on the pipeline.\n\n[Settings that can change](../../concepts/01-pipelines.md#settings-that-can-change) explains why a client sends every change to a pipeline in one request.",
        "x-position": 41,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X PATCH \"$FOUNDATION4_URL/pipelines/$PIPELINE_ID\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"description\": \"Support knowledge base for every product\"\n}'"
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import json\nimport os\nimport urllib.error\nimport urllib.request\n\nbody = {\n    \"description\": \"Support knowledge base for every product\",\n}\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/pipelines/{os.environ['PIPELINE_ID']}\",\n    method=\"PATCH\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n        \"Content-Type\": \"application/json\",\n    },\n    data=json.dumps(body).encode(),\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/pipelines/${process.env.PIPELINE_ID}`, {\n  method: \"PATCH\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    description: \"Support knowledge base for every product\",\n  }),\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"json\"\nrequire \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/pipelines/#{ENV.fetch(\"PIPELINE_ID\")}\")\nrequest = Net::HTTP::Patch.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nrequest[\"Content-Type\"] = \"application/json\"\nrequest.body = JSON.generate({\n  \"description\" => \"Support knowledge base for every product\",\n})\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/pipelines/{pipeline_id}/classifications": {
      "get": {
        "tags": [
          "Pipelines"
        ],
        "summary": "List pipeline classifications",
        "operationId": "get_pipeline_classifications",
        "parameters": [
          {
            "name": "pipeline_id",
            "in": "path",
            "description": "Identifier of the pipeline.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The body holds `classifications`, the list of classification names, and `hierarchy`, the inheritance pairs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PipelineClassificationsResponse"
                }
              }
            }
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "403": {
            "description": "The key lacks the `*` classification allow-list on the pipeline (`Unauthorized`)."
          },
          "404": {
            "description": "No pipeline with this identifier exists, or the key lacks read permission on the pipeline (`Pipeline not found`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Returns the classifications the pipeline defines and the inheritance relationships between them. The `hierarchy` field is a list of pairs, each holding a classification and the inherited classification.\n\n**Permissions.** Read on the pipeline and the `*` classification allow-list, because the response includes the inheritance relationships.\n\nSee [Classifications](../../concepts/03-classifications.md).",
        "x-position": 43,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl \"$FOUNDATION4_URL/pipelines/$PIPELINE_ID/classifications\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/pipelines/{os.environ['PIPELINE_ID']}/classifications\",\n    method=\"GET\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/pipelines/${process.env.PIPELINE_ID}/classifications`, {\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/pipelines/#{ENV.fetch(\"PIPELINE_ID\")}/classifications\")\nrequest = Net::HTTP::Get.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      },
      "post": {
        "tags": [
          "Pipelines"
        ],
        "summary": "Modify pipeline classifications",
        "operationId": "modify_pipeline_classifications",
        "parameters": [
          {
            "name": "pipeline_id",
            "in": "path",
            "description": "Identifier of the pipeline.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdatePipelineClassificationsRequest"
              },
              "example": {
                "add": [
                  [
                    "finance",
                    "internal"
                  ]
                ]
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "The classifications were changed. The response has no body."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "403": {
            "description": "The key lacks write permission on the pipeline or the `*` classification allow-list (`Unauthorized`)."
          },
          "404": {
            "description": "No pipeline with this identifier exists (`Pipeline not found`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Adds and removes classifications and inheritance relationships in one transaction. The request body holds an `add` list and a `remove` list, each using the classification forms of the create request. Additions are processed before removals. Removing a classification permanently deletes every document that carries the classification. The response has no body.\n\n**Permissions.** Write on the pipeline and the `*` classification allow-list.\n\nSee [Classifications](../../concepts/03-classifications.md).",
        "x-position": 44,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X POST \"$FOUNDATION4_URL/pipelines/$PIPELINE_ID/classifications\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"add\": [\n    [\n      \"finance\",\n      \"internal\"\n    ]\n  ]\n}'"
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import json\nimport os\nimport urllib.error\nimport urllib.request\n\nbody = {\n    \"add\": [\n        [\n            \"finance\",\n            \"internal\",\n        ],\n    ],\n}\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/pipelines/{os.environ['PIPELINE_ID']}/classifications\",\n    method=\"POST\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n        \"Content-Type\": \"application/json\",\n    },\n    data=json.dumps(body).encode(),\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/pipelines/${process.env.PIPELINE_ID}/classifications`, {\n  method: \"POST\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    add: [\n      [\n        \"finance\",\n        \"internal\",\n      ],\n    ],\n  }),\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"json\"\nrequire \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/pipelines/#{ENV.fetch(\"PIPELINE_ID\")}/classifications\")\nrequest = Net::HTTP::Post.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nrequest[\"Content-Type\"] = \"application/json\"\nrequest.body = JSON.generate({\n  \"add\" => [\n    [\n      \"finance\",\n      \"internal\",\n    ],\n  ],\n})\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/pipelines/{pipeline_id}/documents": {
      "get": {
        "summary": "List documents",
        "operationId": "list_pipeline_documents",
        "parameters": [
          {
            "name": "pipeline_id",
            "in": "path",
            "description": "Identifier of the pipeline.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "metadata",
            "in": "query",
            "description": "Metadata filter as URL-encoded JSON, in the filter language of search requests. The filter must match the pipeline's metadata schema.",
            "required": false,
            "schema": {
              "oneOf": [
                {
                  "type": "null"
                },
                {
                  "$ref": "#/components/schemas/Filter"
                }
              ]
            }
          },
          {
            "name": "first",
            "in": "query",
            "description": "Cursor mode: the number of objects to return from the start of the list, or after the `after` cursor.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "after",
            "in": "query",
            "description": "Cursor mode: the cursor after which the page starts, taken from `page_info.after` of the previous page.",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "name": "last",
            "in": "query",
            "description": "Cursor mode: the number of objects to return before the `before` cursor.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "before",
            "in": "query",
            "description": "Cursor mode: the cursor before which the page ends, taken from `page_info.before`.",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Offset mode: the number of objects to return. The default page size is 25.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Offset mode: the number of objects to skip.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "count",
            "in": "query",
            "description": "When `true`, adds `page_info.count`, the total number of matching objects.",
            "required": false,
            "schema": {
              "type": [
                "boolean",
                "null"
              ]
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Sort fields: `id`, `created_at`, `updated_at`, `external_identifier`, `classification`. A `-` prefix sorts in descending order. A field name alone sorts in ascending order, as does a `+` prefix sent encoded as `%2B`. Repeat the parameter to sort by several fields. The default order is `id` ascending.",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "as_of",
            "in": "query",
            "description": "Point in time in microseconds since the Unix epoch. The list then contains the versions created at or before that time that had not expired at that time.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "format": "int64"
            }
          },
          {
            "name": "id",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "uuid"
            },
            "description": "Returns only the versions of the document with this identifier."
          },
          {
            "name": "external_identifier",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Returns only the versions whose external identifier equals this value."
          },
          {
            "name": "external_identifier$contains",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "Matches objects whose `external_identifier` contains the value, case-sensitive. Repeat the parameter to require several values."
          },
          {
            "name": "created_at",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Returns only the versions created at this time, in RFC 3339 format."
          },
          {
            "name": "created_at$gt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` is greater than the value."
          },
          {
            "name": "created_at$lt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` is less than the value."
          },
          {
            "name": "created_at$ge",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` is greater than or equal to the value."
          },
          {
            "name": "created_at$le",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` is less than or equal to the value."
          },
          {
            "name": "updated_at",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Returns only the versions last changed at this time, in RFC 3339 format."
          },
          {
            "name": "updated_at$gt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` is greater than the value."
          },
          {
            "name": "updated_at$lt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` is less than the value."
          },
          {
            "name": "updated_at$ge",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` is greater than or equal to the value."
          },
          {
            "name": "updated_at$le",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` is less than or equal to the value."
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Returns only the versions with this processing status: `pending`, `success` or `failed`."
          }
        ],
        "responses": {
          "200": {
            "description": "The body is one page of document versions in the list envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Paginated_DocumentResponse"
                }
              }
            }
          },
          "400": {
            "description": "A query parameter is invalid: `as_of` lies outside the range of valid timestamps (`Invalid version`), `order_by` names another field (`Invalid order_by parameter`) or the pagination parameters conflict (`Pagination error`). A `metadata` filter that does not match the pipeline's metadata schema returns `Schema error`."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "404": {
            "description": "No pipeline with this identifier exists, or the key lacks read permission on the pipeline (`Pipeline with id <id> not found`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "tags": [
          "Documents"
        ],
        "description": "Returns one page of the document versions in a pipeline that are current, or that were current at the time given in `as_of`. A document with several current versions appears once for each version. Query parameters filter the list by document fields and by metadata, and the `status` filter finds versions whose processing is not complete.\n\n**Permissions.** Read on the pipeline.\n\n[API conventions](../01-api-conventions.md) describes pagination, field filters and ordering, and [Filter operators](../03-filter-operators.md) describes the `metadata` filter.",
        "x-position": 45,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl \"$FOUNDATION4_URL/pipelines/$PIPELINE_ID/documents\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/pipelines/{os.environ['PIPELINE_ID']}/documents\",\n    method=\"GET\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/pipelines/${process.env.PIPELINE_ID}/documents`, {\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/pipelines/#{ENV.fetch(\"PIPELINE_ID\")}/documents\")\nrequest = Net::HTTP::Get.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      },
      "post": {
        "summary": "Add a document",
        "operationId": "create_pipeline_document",
        "parameters": [
          {
            "name": "pipeline_id",
            "in": "path",
            "description": "Identifier of the pipeline.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePipelineDocumentRequest"
              },
              "example": {
                "classification": "public",
                "external_identifier": "kb-password-reset",
                "metadata": {
                  "product": "accounts"
                },
                "contents": "To reset a password, open Settings, choose Security and select Reset password. A reset link is sent to the registered email address and expires after 30 minutes."
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "The version was accepted. The body is the new version, with the status `pending`, or `failed` when the processing job could not be queued.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentResponse"
                }
              }
            }
          },
          "400": {
            "description": "The metadata does not satisfy the pipeline's metadata schema (`Invalid metadata`), or a new version names a classification that differs from the classification of the existing document (`Classification mismatch`)."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "403": {
            "description": "The license does not permit the operation (`Invalid license: ...`), or the key's classification allow-list does not permit the classification (`Unauthorized: access level ... required for Pipeline with id ...`)."
          },
          "404": {
            "description": "No pipeline with this identifier exists or the key lacks execute permission on the pipeline (`Pipeline with id <id> not found`), or the pipeline does not define the classification or the key's allow-list excludes the classification (`Classification not found`). The text splitter does not exist or the key lacks execute permission on the text splitter (`Text Splitter with id <id> not found`)."
          },
          "413": {
            "description": "The body is larger than 2 megabytes, counted in bytes. The response body is plain text (`Failed to buffer the request body: length limit exceeded`)."
          },
          "422": {
            "description": "A required field such as `contents` is missing, or a field has the wrong type. The response body is plain text and names the field (`Failed to deserialize the JSON body into the target type: missing field ...`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "tags": [
          "Documents"
        ],
        "description": "Adds a document to a pipeline, or a new version of the document that has the same `external_identifier` in the pipeline. Processing is asynchronous: the response returns the new version with the status `pending`, or `failed` when the processing job cannot be queued. The client application retrieves the document until the status is `success`.\n\n**Permissions.** Read and execute on the pipeline, execute on the text splitter that processes the document, and the document's classification in the allow-list.\n\n[Documents, versions and fragments](../../concepts/02-documents-versions-fragments.md) describes the request fields, processing and versions.",
        "x-position": 46,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X POST \"$FOUNDATION4_URL/pipelines/$PIPELINE_ID/documents\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"classification\": \"public\",\n  \"external_identifier\": \"kb-password-reset\",\n  \"metadata\": {\n    \"product\": \"accounts\"\n  },\n  \"contents\": \"To reset a password, open Settings, choose Security and select Reset password. A reset link is sent to the registered email address and expires after 30 minutes.\"\n}'"
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import json\nimport os\nimport urllib.error\nimport urllib.request\n\nbody = {\n    \"classification\": \"public\",\n    \"external_identifier\": \"kb-password-reset\",\n    \"metadata\": {\n        \"product\": \"accounts\",\n    },\n    \"contents\": \"To reset a password, open Settings, choose Security and select Reset password. A reset link is sent to the registered email address and expires after 30 minutes.\",\n}\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/pipelines/{os.environ['PIPELINE_ID']}/documents\",\n    method=\"POST\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n        \"Content-Type\": \"application/json\",\n    },\n    data=json.dumps(body).encode(),\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/pipelines/${process.env.PIPELINE_ID}/documents`, {\n  method: \"POST\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    classification: \"public\",\n    external_identifier: \"kb-password-reset\",\n    metadata: {\n      product: \"accounts\",\n    },\n    contents: \"To reset a password, open Settings, choose Security and select Reset password. A reset link is sent to the registered email address and expires after 30 minutes.\",\n  }),\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"json\"\nrequire \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/pipelines/#{ENV.fetch(\"PIPELINE_ID\")}/documents\")\nrequest = Net::HTTP::Post.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nrequest[\"Content-Type\"] = \"application/json\"\nrequest.body = JSON.generate({\n  \"classification\" => \"public\",\n  \"external_identifier\" => \"kb-password-reset\",\n  \"metadata\" => {\n    \"product\" => \"accounts\",\n  },\n  \"contents\" => \"To reset a password, open Settings, choose Security and select Reset password. A reset link is sent to the registered email address and expires after 30 minutes.\",\n})\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      },
      "delete": {
        "summary": "Delete or expire all documents",
        "description": "Deletes or expires every document in a pipeline. Without `expire`, the operation permanently removes every version and every fragment and returns status 204. With `expire=true`, the operation marks every current version as expired and returns status 200.\n\n**Permissions.** Write and execute on the pipeline, and an allow-list that includes every classification of the pipeline.\n\n[Documents, versions and fragments](../../concepts/02-documents-versions-fragments.md) compares expiry and deletion.",
        "operationId": "delete_all_pipeline_documents",
        "parameters": [
          {
            "name": "pipeline_id",
            "in": "path",
            "description": "Identifier of the pipeline.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "as_of",
            "in": "query",
            "description": "Point in time in microseconds since the Unix epoch. The operation then applies only to versions created at or before that time.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "expire",
            "in": "query",
            "description": "Whether to expire the documents instead of deleting the documents. The default is `false`.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The documents were expired (`expire=true`). The body is empty."
          },
          "204": {
            "description": "The documents were deleted. The body is empty."
          },
          "400": {
            "description": "The `as_of` value lies outside the range of valid timestamps (`Invalid version`)."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "403": {
            "description": "The pipeline exists, and the key lacks write or execute permission on the pipeline or the key's classification allow-list does not include every classification of the pipeline (`Unauthorized: access level ... required for Pipeline with id ...`). An expiry also returns 403 when the license does not permit the operation (`Invalid license: ...`)."
          },
          "404": {
            "description": "No pipeline with this identifier exists (`Pipeline with id <id> not found`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "tags": [
          "Documents"
        ],
        "x-position": 47,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X DELETE \"$FOUNDATION4_URL/pipelines/$PIPELINE_ID/documents\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/pipelines/{os.environ['PIPELINE_ID']}/documents\",\n    method=\"DELETE\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/pipelines/${process.env.PIPELINE_ID}/documents`, {\n  method: \"DELETE\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/pipelines/#{ENV.fetch(\"PIPELINE_ID\")}/documents\")\nrequest = Net::HTTP::Delete.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/pipelines/{pipeline_id}/documents/{document_id}": {
      "get": {
        "summary": "Get a document",
        "description": "Returns the latest current version of a document in a pipeline, with the processing status in the `status` field. A client application retrieves the document after adding the document to find out when processing is complete. `as_of` returns the version that was current at a given time, and `include_expired=true` also considers expired versions.\n\n**Permissions.** Read on the pipeline.\n\n[Documents, versions and fragments](../../concepts/02-documents-versions-fragments.md) describes the processing lifecycle and point-in-time reads.",
        "operationId": "get_pipeline_document_info",
        "parameters": [
          {
            "name": "pipeline_id",
            "in": "path",
            "description": "Identifier of the pipeline.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "document_id",
            "in": "path",
            "description": "Identifier of the document.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "as_of",
            "in": "query",
            "description": "Point in time in microseconds since the Unix epoch. The operation then returns the latest version created at or before that time and, without `include_expired`, only a version that had not expired at that time.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "include_expired",
            "in": "query",
            "description": "Whether to consider expired versions. The default is `false`.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The body is the document version.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentResponse"
                }
              }
            }
          },
          "400": {
            "description": "The `as_of` value lies outside the range of valid timestamps (`Invalid version`)."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "403": {
            "description": "The pipeline exists, and the key lacks read permission on the pipeline (`Unauthorized: access level ... required for Pipeline with id ...`)."
          },
          "404": {
            "description": "No pipeline with this identifier exists (`Pipeline with id <id> not found`), or the pipeline has no matching version of the document (`Document not found`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "tags": [
          "Documents"
        ],
        "x-position": 48,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl \"$FOUNDATION4_URL/pipelines/$PIPELINE_ID/documents/$DOCUMENT_ID\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/pipelines/{os.environ['PIPELINE_ID']}/documents/{os.environ['DOCUMENT_ID']}\",\n    method=\"GET\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/pipelines/${process.env.PIPELINE_ID}/documents/${process.env.DOCUMENT_ID}`, {\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/pipelines/#{ENV.fetch(\"PIPELINE_ID\")}/documents/#{ENV.fetch(\"DOCUMENT_ID\")}\")\nrequest = Net::HTTP::Get.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      },
      "delete": {
        "summary": "Delete or expire a document",
        "operationId": "delete_pipeline_document",
        "parameters": [
          {
            "name": "pipeline_id",
            "in": "path",
            "description": "Identifier of the pipeline.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "document_id",
            "in": "path",
            "description": "Identifier of the document.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "as_of",
            "in": "query",
            "description": "Point in time in microseconds since the Unix epoch. The operation then applies only to versions created at or before that time.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "expire",
            "in": "query",
            "description": "Whether to expire the document instead of deleting the document. The default is `false`.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The document was expired (`expire=true`). The body is empty."
          },
          "204": {
            "description": "The document was deleted. The body is empty."
          },
          "400": {
            "description": "The `as_of` value lies outside the range of valid timestamps (`Invalid version`)."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "403": {
            "description": "The pipeline exists, and the key lacks write or execute permission on the pipeline or the key's classification allow-list does not include the document's classification (`Unauthorized: access level ... required for Pipeline with id ...`). An expiry also returns 403 when the license does not permit the operation (`Invalid license: ...`)."
          },
          "404": {
            "description": "No pipeline with this identifier exists, or the pipeline has no version of the document created at or before `as_of` (`Pipeline with id <id> not found` or `Document with id <id> not found`). A deletion also returns `Pipeline with id <id> not found` when the key lacks read permission on the pipeline."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "tags": [
          "Documents"
        ],
        "description": "Deletes or expires a document in a pipeline. Without `expire`, the operation permanently removes every version and every fragment of the document and returns status 204. With `expire=true`, the operation marks every current version as expired and returns status 200, and the version history remains readable.\n\n**Permissions.** To delete: read, write and execute on the pipeline, and the document's classification in the allow-list. To expire: write and execute on the pipeline, and the document's classification in the allow-list.\n\n[Documents, versions and fragments](../../concepts/02-documents-versions-fragments.md) compares expiry and deletion.",
        "x-position": 49,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X DELETE \"$FOUNDATION4_URL/pipelines/$PIPELINE_ID/documents/$DOCUMENT_ID\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/pipelines/{os.environ['PIPELINE_ID']}/documents/{os.environ['DOCUMENT_ID']}\",\n    method=\"DELETE\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/pipelines/${process.env.PIPELINE_ID}/documents/${process.env.DOCUMENT_ID}`, {\n  method: \"DELETE\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/pipelines/#{ENV.fetch(\"PIPELINE_ID\")}/documents/#{ENV.fetch(\"DOCUMENT_ID\")}\")\nrequest = Net::HTTP::Delete.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/pipelines/{pipeline_id}/documents/{document_id}/fragments": {
      "get": {
        "summary": "List document fragments",
        "operationId": "list_pipeline_document_fragments",
        "parameters": [
          {
            "name": "pipeline_id",
            "in": "path",
            "description": "Identifier of the pipeline.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "document_id",
            "in": "path",
            "description": "Identifier of the document.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "first",
            "in": "query",
            "description": "Cursor mode: the number of objects to return from the start of the list, or after the `after` cursor.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "after",
            "in": "query",
            "description": "Cursor mode: the cursor after which the page starts, taken from `page_info.after` of the previous page.",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "name": "last",
            "in": "query",
            "description": "Cursor mode: the number of objects to return before the `before` cursor.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "before",
            "in": "query",
            "description": "Cursor mode: the cursor before which the page ends, taken from `page_info.before`.",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Offset mode: the number of objects to return. The default page size is 25.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Offset mode: the number of objects to skip.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "count",
            "in": "query",
            "description": "When `true`, adds `page_info.count`, the total number of matching objects.",
            "required": false,
            "schema": {
              "type": [
                "boolean",
                "null"
              ]
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Sort fields: `id`, `order_id`. A `-` prefix sorts in descending order. A field name alone sorts in ascending order, as does a `+` prefix sent encoded as `%2B`. Repeat the parameter to sort by several fields. The default order is `id` ascending.",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "as_of",
            "in": "query",
            "description": "Point in time in microseconds since the Unix epoch. The operation then lists the fragments of the latest version created at or before that time.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "format": "int64"
            }
          },
          {
            "name": "contents",
            "in": "query",
            "description": "Whether to include the decrypted text of each fragment in `page_content`. The default is `false`.",
            "required": false,
            "schema": {
              "type": [
                "boolean",
                "null"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The body is one page of fragments in the list envelope. `page_content` is present only with `contents=true`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Paginated_Fragment"
                }
              }
            }
          },
          "400": {
            "description": "A query parameter is invalid: `as_of` lies outside the range of valid timestamps (`Invalid version`), `order_by` names another field (`Invalid order_by parameter`) or the pagination parameters conflict (`Pagination error`)."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "404": {
            "description": "No pipeline with this identifier exists or the key lacks read and execute permission on the pipeline (`Pipeline with id <id> not found`), or the pipeline has no version of the document created at or before `as_of` (`Document with id <id> not found`)."
          },
          "500": {
            "description": "The text of a fragment could not be decrypted (`Decryption error`). Only a request with `contents=true` decrypts text."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "tags": [
          "Documents"
        ],
        "description": "Returns one page of the fragments of one document version, in the order of the fragments within the version. The version is the latest version of the document, or the latest version created at or before `as_of`, including an expired version. The fragment text is included in `page_content` only when the request sets `contents=true`.\n\n**Permissions.** Read and execute on the pipeline.\n\n[Documents, versions and fragments](../../concepts/02-documents-versions-fragments.md) describes fragments, and [API conventions](../01-api-conventions.md) describes pagination.",
        "x-position": 50,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl \"$FOUNDATION4_URL/pipelines/$PIPELINE_ID/documents/$DOCUMENT_ID/fragments\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/pipelines/{os.environ['PIPELINE_ID']}/documents/{os.environ['DOCUMENT_ID']}/fragments\",\n    method=\"GET\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/pipelines/${process.env.PIPELINE_ID}/documents/${process.env.DOCUMENT_ID}/fragments`, {\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/pipelines/#{ENV.fetch(\"PIPELINE_ID\")}/documents/#{ENV.fetch(\"DOCUMENT_ID\")}/fragments\")\nrequest = Net::HTTP::Get.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/pipelines/{pipeline_id}/fragments": {
      "get": {
        "summary": "Get fragments by ID",
        "operationId": "get_many_pipeline_fragments",
        "parameters": [
          {
            "name": "pipeline_id",
            "in": "path",
            "description": "Identifier of the pipeline.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "id",
            "in": "query",
            "description": "Identifier of a fragment to return. Repeat the parameter for each fragment, for example `?id=<uuid>&id=<uuid>`. Without the parameter, the array is empty.",
            "required": true,
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "format": "uuid"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The body is an array of the fragments found, which can be empty.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Fragment"
                  }
                }
              }
            }
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "404": {
            "description": "No pipeline with this identifier exists, or the key lacks read and execute permission on the pipeline (`Pipeline with id <id> not found`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "tags": [
          "Documents"
        ],
        "description": "Returns the fragments of a pipeline that have the given identifiers, as a JSON array without the list envelope. The array omits identifiers that match no fragment and fragments whose classification is outside the key's classification allow-list for the pipeline, and includes expired fragments. The order of the array is not defined. Each fragment holds the identifier, classification, metadata, version and position, but not the text: the fragment list of the document version returns the text when the request sets `contents=true`.\n\n**Permissions.** Read and execute on the pipeline.\n\n[Documents, versions and fragments](../../concepts/02-documents-versions-fragments.md) describes fragments.",
        "x-position": 51,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl \"$FOUNDATION4_URL/pipelines/$PIPELINE_ID/fragments?id=$ID\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/pipelines/{os.environ['PIPELINE_ID']}/fragments?id={os.environ['ID']}\",\n    method=\"GET\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/pipelines/${process.env.PIPELINE_ID}/fragments?id=${process.env.ID}`, {\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/pipelines/#{ENV.fetch(\"PIPELINE_ID\")}/fragments?id=#{ENV.fetch(\"ID\")}\")\nrequest = Net::HTTP::Get.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      },
      "post": {
        "summary": "Get fragments by ID (deprecated)",
        "description": "This operation is deprecated. `GET /pipelines/{pipeline_id}/fragments` with one `id` query parameter for each fragment replaces the operation. The operation returns the same fragments as the `GET` operation, for the identifiers in the `ids` field of the body.\n\n**Permissions.** Read and execute on the pipeline.",
        "operationId": "get_many_pipeline_fragments_old",
        "parameters": [
          {
            "name": "pipeline_id",
            "in": "path",
            "description": "Identifier of the pipeline.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BodyDataIds"
              },
              "example": {
                "ids": [
                  "$FRAGMENT_ID"
                ]
              }
            }
          },
          "required": true,
          "description": "The identifiers of the fragments to return, in the `ids` field."
        },
        "responses": {
          "200": {
            "description": "The body is an array of the fragments found, which can be empty.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Fragment"
                  }
                }
              }
            }
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "404": {
            "description": "No pipeline with this identifier exists, or the key lacks read and execute permission on the pipeline (`Pipeline with id <id> not found`)."
          }
        },
        "deprecated": true,
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "tags": [
          "Documents"
        ],
        "x-position": 52,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X POST \"$FOUNDATION4_URL/pipelines/$PIPELINE_ID/fragments\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"ids\": [\n    \"'\"$FRAGMENT_ID\"'\"\n  ]\n}'"
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import json\nimport os\nimport urllib.error\nimport urllib.request\n\nbody = {\n    \"ids\": [\n        os.environ[\"FRAGMENT_ID\"],\n    ],\n}\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/pipelines/{os.environ['PIPELINE_ID']}/fragments\",\n    method=\"POST\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n        \"Content-Type\": \"application/json\",\n    },\n    data=json.dumps(body).encode(),\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/pipelines/${process.env.PIPELINE_ID}/fragments`, {\n  method: \"POST\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    ids: [\n      process.env.FRAGMENT_ID,\n    ],\n  }),\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"json\"\nrequire \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/pipelines/#{ENV.fetch(\"PIPELINE_ID\")}/fragments\")\nrequest = Net::HTTP::Post.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nrequest[\"Content-Type\"] = \"application/json\"\nrequest.body = JSON.generate({\n  \"ids\" => [\n    ENV.fetch(\"FRAGMENT_ID\"),\n  ],\n})\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/pipelines/{pipeline_id}/indexes": {
      "get": {
        "tags": [
          "Pipelines"
        ],
        "summary": "List metadata indexes",
        "operationId": "list_pipeline_indexes",
        "parameters": [
          {
            "name": "pipeline_id",
            "in": "path",
            "description": "Identifier of the pipeline.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The body is a JSON array of metadata indexes.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PipelineIndexResponse"
                  }
                }
              }
            }
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "404": {
            "description": "No pipeline with this identifier exists, or the key lacks read and execute permission on the pipeline (`Pipeline not found`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Returns the metadata indexes defined on a pipeline. The response body is a JSON array. Each element holds the index identifier and the metadata fields the index covers.\n\n**Permissions.** Read and execute on the pipeline.\n\nSee [Pipelines](../../concepts/01-pipelines.md).",
        "x-position": 53,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl \"$FOUNDATION4_URL/pipelines/$PIPELINE_ID/indexes\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/pipelines/{os.environ['PIPELINE_ID']}/indexes\",\n    method=\"GET\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/pipelines/${process.env.PIPELINE_ID}/indexes`, {\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/pipelines/#{ENV.fetch(\"PIPELINE_ID\")}/indexes\")\nrequest = Net::HTTP::Get.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      },
      "post": {
        "tags": [
          "Pipelines"
        ],
        "summary": "Create a metadata index",
        "operationId": "create_pipeline_index",
        "parameters": [
          {
            "name": "pipeline_id",
            "in": "path",
            "description": "Identifier of the pipeline.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePipelineIndexRequest"
              },
              "example": {
                "columns": [
                  "product"
                ]
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "The index was created. The body is the new index.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PipelineIndexResponse"
                }
              }
            }
          },
          "400": {
            "description": "A field in `columns` is not a top-level field of the pipeline's metadata schema, or has a type that cannot be indexed (`Invalid parameter`)."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "403": {
            "description": "The license does not allow the change (`Invalid license`)."
          },
          "404": {
            "description": "No pipeline with this identifier exists, or the key lacks write and execute permission on the pipeline (`Pipeline not found`)."
          },
          "409": {
            "description": "An index on these fields already exists (`Conflict unique error`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Creates a metadata index on one or more top-level metadata fields of a pipeline. Each field named in `columns` must be a top-level field declared in the pipeline's metadata schema with a scalar type. The response body is the new index.\n\n**Permissions.** Write and execute on the pipeline.\n\nSee [Pipelines](../../concepts/01-pipelines.md).",
        "x-position": 54,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X POST \"$FOUNDATION4_URL/pipelines/$PIPELINE_ID/indexes\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"columns\": [\n    \"product\"\n  ]\n}'"
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import json\nimport os\nimport urllib.error\nimport urllib.request\n\nbody = {\n    \"columns\": [\n        \"product\",\n    ],\n}\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/pipelines/{os.environ['PIPELINE_ID']}/indexes\",\n    method=\"POST\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n        \"Content-Type\": \"application/json\",\n    },\n    data=json.dumps(body).encode(),\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/pipelines/${process.env.PIPELINE_ID}/indexes`, {\n  method: \"POST\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    columns: [\n      \"product\",\n    ],\n  }),\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"json\"\nrequire \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/pipelines/#{ENV.fetch(\"PIPELINE_ID\")}/indexes\")\nrequest = Net::HTTP::Post.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nrequest[\"Content-Type\"] = \"application/json\"\nrequest.body = JSON.generate({\n  \"columns\" => [\n    \"product\",\n  ],\n})\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/pipelines/{pipeline_id}/indexes/{index_id}": {
      "get": {
        "tags": [
          "Pipelines"
        ],
        "summary": "Get a metadata index",
        "operationId": "get_pipeline_index",
        "parameters": [
          {
            "name": "pipeline_id",
            "in": "path",
            "description": "Identifier of the pipeline.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "index_id",
            "in": "path",
            "description": "Identifier of the metadata index.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The body is the metadata index.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PipelineIndexResponse"
                }
              }
            }
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "404": {
            "description": "No pipeline with this identifier exists that the key can read and execute, or the pipeline has no metadata index (`Pipeline not found` or `Pipeline Index not found`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Returns a metadata index of a pipeline by identifier. The response body holds the index identifier and the fields the index covers.\n\n**Permissions.** Read and execute on the pipeline.\n\nSee [Pipelines](../../concepts/01-pipelines.md).",
        "x-position": 55,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl \"$FOUNDATION4_URL/pipelines/$PIPELINE_ID/indexes/$INDEX_ID\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/pipelines/{os.environ['PIPELINE_ID']}/indexes/{os.environ['INDEX_ID']}\",\n    method=\"GET\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/pipelines/${process.env.PIPELINE_ID}/indexes/${process.env.INDEX_ID}`, {\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/pipelines/#{ENV.fetch(\"PIPELINE_ID\")}/indexes/#{ENV.fetch(\"INDEX_ID\")}\")\nrequest = Net::HTTP::Get.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      },
      "delete": {
        "tags": [
          "Pipelines"
        ],
        "summary": "Delete a metadata index",
        "operationId": "delete_pipeline_index",
        "parameters": [
          {
            "name": "pipeline_id",
            "in": "path",
            "description": "Identifier of the pipeline.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "index_id",
            "in": "path",
            "description": "Identifier of the metadata index.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "The index was deleted. The response has no body."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "404": {
            "description": "No pipeline with this identifier exists, or the key lacks write and execute permission on the pipeline (`Pipeline not found`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Deletes a metadata index of a pipeline. The operation does not check that the index exists, so a request for an index that does not exist also returns HTTP 204. The response has no body.\n\n**Permissions.** Write and execute on the pipeline.\n\nSee [Pipelines](../../concepts/01-pipelines.md).",
        "x-position": 56,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X DELETE \"$FOUNDATION4_URL/pipelines/$PIPELINE_ID/indexes/$INDEX_ID\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/pipelines/{os.environ['PIPELINE_ID']}/indexes/{os.environ['INDEX_ID']}\",\n    method=\"DELETE\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/pipelines/${process.env.PIPELINE_ID}/indexes/${process.env.INDEX_ID}`, {\n  method: \"DELETE\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/pipelines/#{ENV.fetch(\"PIPELINE_ID\")}/indexes/#{ENV.fetch(\"INDEX_ID\")}\")\nrequest = Net::HTTP::Delete.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/pipelines/{pipeline_id}/search": {
      "post": {
        "summary": "Search a pipeline",
        "operationId": "post_pipeline_search",
        "parameters": [
          {
            "name": "pipeline_id",
            "in": "path",
            "description": "Identifier of the pipeline.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExecutePipelineRequest"
              },
              "example": {
                "query": "How can finance export invoices?",
                "classification": "internal",
                "type": "similarity",
                "params": {
                  "k": 3
                },
                "filters": {
                  "product": {
                    "$eq": "billing"
                  }
                }
              }
            }
          },
          "required": true,
          "description": "The query, the search type and the search parameters, the classifications to search and an optional metadata filter. [Search requests](../02-search-requests.md) describes every field."
        },
        "responses": {
          "200": {
            "description": "The body is an array of fragments ordered by score, which can be empty.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Fragment"
                  }
                }
              }
            }
          },
          "400": {
            "description": "The search names an embedding model that the pipeline does not use, or the pipeline has no embedding model (`Vector embedding not found`). The request sets `type` to `query` (`Invalid search type or parameters`), or the filter does not match the pipeline's metadata schema (`Schema error`)."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "404": {
            "description": "No pipeline with this identifier exists or the key lacks read and execute permission on the pipeline (`Pipeline not found`), or `search_type` is 1 or 3 and a named classification is not defined in the pipeline (`Classification not found`)."
          },
          "422": {
            "description": "The body does not match the request schema, for example a missing required field or an unknown `type` or `distance_strategy` value. The body is plain text."
          },
          "500": {
            "description": "The embedding model could not convert the query into a vector, the query language could not be detected, or the database rejected the query (`Internal error` or a database error message)."
          },
          "501": {
            "description": "The request sets `type` to `hybrid` or `history`, or sets `type` to `search` on a pipeline without full-text search (`Hybrid placeholder is not implemented yet`, `History placeholder is not implemented yet` or `Full text search is not enabled for this pipeline`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "tags": [
          "Search"
        ],
        "description": "Runs one similarity, maximal marginal relevance (MMR) or full-text search on a pipeline and returns the matching fragments as a JSON array, without the list envelope. The request body names the search text, the reader's classifications, the search type with the parameters of the type and an optional metadata filter.\n\n**Permissions.** Read and execute on the pipeline.\n\n[Search requests](../02-search-requests.md) describes every field, the search types, the response and the errors.",
        "x-position": 57,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X POST \"$FOUNDATION4_URL/pipelines/$PIPELINE_ID/search\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"query\": \"How can finance export invoices?\",\n  \"classification\": \"internal\",\n  \"type\": \"similarity\",\n  \"params\": {\n    \"k\": 3\n  },\n  \"filters\": {\n    \"product\": {\n      \"$eq\": \"billing\"\n    }\n  }\n}'"
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import json\nimport os\nimport urllib.error\nimport urllib.request\n\nbody = {\n    \"query\": \"How can finance export invoices?\",\n    \"classification\": \"internal\",\n    \"type\": \"similarity\",\n    \"params\": {\n        \"k\": 3,\n    },\n    \"filters\": {\n        \"product\": {\n            \"$eq\": \"billing\",\n        },\n    },\n}\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/pipelines/{os.environ['PIPELINE_ID']}/search\",\n    method=\"POST\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n        \"Content-Type\": \"application/json\",\n    },\n    data=json.dumps(body).encode(),\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/pipelines/${process.env.PIPELINE_ID}/search`, {\n  method: \"POST\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    query: \"How can finance export invoices?\",\n    classification: \"internal\",\n    type: \"similarity\",\n    params: {\n      k: 3,\n    },\n    filters: {\n      product: {\n        $eq: \"billing\",\n      },\n    },\n  }),\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"json\"\nrequire \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/pipelines/#{ENV.fetch(\"PIPELINE_ID\")}/search\")\nrequest = Net::HTTP::Post.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nrequest[\"Content-Type\"] = \"application/json\"\nrequest.body = JSON.generate({\n  \"query\" => \"How can finance export invoices?\",\n  \"classification\" => \"internal\",\n  \"type\" => \"similarity\",\n  \"params\" => {\n    \"k\" => 3,\n  },\n  \"filters\" => {\n    \"product\" => {\n      \"$eq\" => \"billing\",\n    },\n  },\n})\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/providers/embeddings": {
      "get": {
        "tags": [
          "Providers"
        ],
        "summary": "List embedding providers",
        "operationId": "list_embedding_providers",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "uuid"
            },
            "description": "Returns only the embedding provider with this identifier."
          },
          {
            "name": "provider",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Returns only embedding providers whose name equals this value, such as `FastEmbedEmbeddings`. The match is case-sensitive."
          },
          {
            "name": "provider$contains",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "Matches objects whose `provider` contains the value, case-sensitive. Repeat the parameter to require several values."
          },
          {
            "name": "provider$startswith",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Matches objects whose `provider` starts with the value."
          },
          {
            "name": "description",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Returns only embedding providers whose description equals this value, case-sensitive."
          },
          {
            "name": "description$contains",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "Matches objects whose `description` contains the value, case-sensitive. Repeat the parameter to require several values."
          },
          {
            "name": "first",
            "in": "query",
            "description": "Cursor mode: the number of objects to return from the start of the list, or after the `after` cursor.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "after",
            "in": "query",
            "description": "Cursor mode: the cursor after which the page starts, taken from `page_info.after` of the previous page.",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "name": "last",
            "in": "query",
            "description": "Cursor mode: the number of objects to return before the `before` cursor.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "before",
            "in": "query",
            "description": "Cursor mode: the cursor before which the page ends, taken from `page_info.before`.",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Offset mode: the number of objects to return. The default page size is 25.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Offset mode: the number of objects to skip.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "count",
            "in": "query",
            "description": "When `true`, adds `page_info.count`, the total number of matching objects.",
            "required": false,
            "schema": {
              "type": [
                "boolean",
                "null"
              ]
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Sort fields: `id`, `created_at`, `updated_at`, `provider`. A `-` prefix sorts in descending order. A field name alone sorts in ascending order, as does a `+` prefix sent encoded as `%2B`. Repeat the parameter to sort by several fields. The default order is `id` ascending.",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of embedding providers. The body is the pagination envelope, with the embedding providers in `data`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Paginated_EmbeddingProviderResponse"
                }
              }
            }
          },
          "400": {
            "description": "The pagination parameters are invalid, such as cursor and offset parameters in one request (`Pagination error`), or `order_by` names a field that the operation cannot sort by (`Invalid order_by parameter`)."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Returns a page of the embedding providers that the key can read. The five embedding providers that Foundation4 supports are created with the deployment, and no operation creates, changes or deletes a provider. Filters apply to the provider name and the description. `order_by` accepts `id`, `created_at`, `updated_at` and `provider`. [API conventions](../01-api-conventions.md) describes pagination, filters and ordering.\n\n**Permissions.** Read on the embedding providers. The list contains only the embedding providers that the key can read.\n\n[Providers and models](../../reference/01-providers-and-models.md) describes each provider.",
        "x-position": 58,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl \"$FOUNDATION4_URL/providers/embeddings\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/providers/embeddings\",\n    method=\"GET\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/providers/embeddings`, {\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/providers/embeddings\")\nrequest = Net::HTTP::Get.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/providers/embeddings/{embedding_provider_id}": {
      "get": {
        "tags": [
          "Providers"
        ],
        "summary": "Get an embedding provider",
        "operationId": "get_embedding_provider",
        "parameters": [
          {
            "name": "embedding_provider_id",
            "in": "path",
            "description": "Identifier of the embedding provider.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The embedding provider was found. The body is the embedding provider.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmbeddingProviderResponse"
                }
              }
            }
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "404": {
            "description": "No embedding provider with this identifier exists, or the key lacks read permission on the embedding provider (`Embedding provider not found`). `details.id` holds the identifier."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Returns one embedding provider. An embedding provider is an engine that Foundation4 supports for converting text into vectors, such as `FastEmbedEmbeddings`. The name of the provider is the value of the `provider` field of an embedding model.\n\n**Permissions.** Read on the embedding provider.\n\n[Providers and models](../../reference/01-providers-and-models.md) describes each provider.",
        "x-position": 59,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl \"$FOUNDATION4_URL/providers/embeddings/$EMBEDDING_PROVIDER_ID\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/providers/embeddings/{os.environ['EMBEDDING_PROVIDER_ID']}\",\n    method=\"GET\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/providers/embeddings/${process.env.EMBEDDING_PROVIDER_ID}`, {\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/providers/embeddings/#{ENV.fetch(\"EMBEDDING_PROVIDER_ID\")}\")\nrequest = Net::HTTP::Get.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/providers/text-splitters": {
      "get": {
        "tags": [
          "Providers"
        ],
        "summary": "List text splitter providers",
        "operationId": "list_text_splitter_providers",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "uuid"
            },
            "description": "Returns only the text splitter provider with this identifier."
          },
          {
            "name": "provider",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Returns only text splitter providers whose name equals this value, such as `RecursiveCharacterTextSplitter`. The match is case-sensitive."
          },
          {
            "name": "provider$contains",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "Matches objects whose `provider` contains the value, case-sensitive. Repeat the parameter to require several values."
          },
          {
            "name": "provider$startswith",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Matches objects whose `provider` starts with the value."
          },
          {
            "name": "description",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Returns only text splitter providers whose description equals this value, case-sensitive."
          },
          {
            "name": "description$contains",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "Matches objects whose `description` contains the value, case-sensitive. Repeat the parameter to require several values."
          },
          {
            "name": "first",
            "in": "query",
            "description": "Cursor mode: the number of objects to return from the start of the list, or after the `after` cursor.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "after",
            "in": "query",
            "description": "Cursor mode: the cursor after which the page starts, taken from `page_info.after` of the previous page.",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "name": "last",
            "in": "query",
            "description": "Cursor mode: the number of objects to return before the `before` cursor.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "before",
            "in": "query",
            "description": "Cursor mode: the cursor before which the page ends, taken from `page_info.before`.",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Offset mode: the number of objects to return. The default page size is 25.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Offset mode: the number of objects to skip.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "count",
            "in": "query",
            "description": "When `true`, adds `page_info.count`, the total number of matching objects.",
            "required": false,
            "schema": {
              "type": [
                "boolean",
                "null"
              ]
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Sort fields: `id`, `created_at`, `updated_at`, `provider`. A `-` prefix sorts in descending order. A field name alone sorts in ascending order, as does a `+` prefix sent encoded as `%2B`. Repeat the parameter to sort by several fields. The default order is `id` ascending.",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of text splitter providers. The body is the pagination envelope, with the text splitter providers in `data`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Paginated_TextSplitterProviderResponse"
                }
              }
            }
          },
          "400": {
            "description": "The pagination parameters are invalid, such as cursor and offset parameters in one request (`Pagination error`), or `order_by` names a field that the operation cannot sort by (`Invalid order_by parameter`)."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Returns a page of the text splitter providers that the key can read. The seven text splitter providers that Foundation4 supports are created with the deployment, and no operation creates, changes or deletes a provider. Filters apply to the provider name and the description. `order_by` accepts `id`, `created_at`, `updated_at` and `provider`. [API conventions](../01-api-conventions.md) describes pagination, filters and ordering.\n\n**Permissions.** Read on the text splitter providers. The list contains only the text splitter providers that the key can read.\n\n[Providers and models](../../reference/01-providers-and-models.md) describes each provider.",
        "x-position": 60,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl \"$FOUNDATION4_URL/providers/text-splitters\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/providers/text-splitters\",\n    method=\"GET\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/providers/text-splitters`, {\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/providers/text-splitters\")\nrequest = Net::HTTP::Get.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/providers/text-splitters/{text_splitter_provider_id}": {
      "get": {
        "tags": [
          "Providers"
        ],
        "summary": "Get a text splitter provider",
        "operationId": "get_text_splitter_provider",
        "parameters": [
          {
            "name": "text_splitter_provider_id",
            "in": "path",
            "description": "Identifier of the text splitter provider.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The text splitter provider was found. The body is the text splitter provider.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TextSplitterProviderResponse"
                }
              }
            }
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "404": {
            "description": "No text splitter provider with this identifier exists, or the key lacks read permission on the text splitter provider (`Text Splitter provider not found`). `details.id` holds the identifier."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Returns one text splitter provider. A text splitter provider is a splitting method that Foundation4 supports, such as `RecursiveCharacterTextSplitter`. The name of the provider is the value of the `provider` field of a text splitter.\n\n**Permissions.** Read on the text splitter provider.\n\n[Providers and models](../../reference/01-providers-and-models.md) describes each provider and the provider's parameters.",
        "x-position": 61,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl \"$FOUNDATION4_URL/providers/text-splitters/$TEXT_SPLITTER_PROVIDER_ID\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/providers/text-splitters/{os.environ['TEXT_SPLITTER_PROVIDER_ID']}\",\n    method=\"GET\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/providers/text-splitters/${process.env.TEXT_SPLITTER_PROVIDER_ID}`, {\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/providers/text-splitters/#{ENV.fetch(\"TEXT_SPLITTER_PROVIDER_ID\")}\")\nrequest = Net::HTTP::Get.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/taxonomies": {
      "get": {
        "tags": [
          "Taxonomies"
        ],
        "summary": "List taxonomies",
        "operationId": "list_taxonomies",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "uuid"
            },
            "description": "Returns only the taxonomy with this identifier."
          },
          {
            "name": "name",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Returns only taxonomies whose name equals this value, case-sensitive."
          },
          {
            "name": "name$contains",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "Matches objects whose `name` contains the value, case-sensitive. Repeat the parameter to require several values."
          },
          {
            "name": "name$startswith",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Matches objects whose `name` starts with the value."
          },
          {
            "name": "name$gt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Matches objects whose `name` is greater than the value."
          },
          {
            "name": "name$ge",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Matches objects whose `name` is greater than or equal to the value."
          },
          {
            "name": "name$lt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Matches objects whose `name` is less than the value."
          },
          {
            "name": "name$le",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Matches objects whose `name` is less than or equal to the value."
          },
          {
            "name": "description",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Returns only taxonomies whose description equals this value, case-sensitive."
          },
          {
            "name": "description$contains",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "Matches objects whose `description` contains the value, case-sensitive. Repeat the parameter to require several values."
          },
          {
            "name": "created_at",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` equals the value."
          },
          {
            "name": "created_at$gt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` is greater than the value."
          },
          {
            "name": "created_at$lt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` is less than the value."
          },
          {
            "name": "created_at$ge",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` is greater than or equal to the value."
          },
          {
            "name": "created_at$le",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` is less than or equal to the value."
          },
          {
            "name": "updated_at",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` equals the value."
          },
          {
            "name": "updated_at$gt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` is greater than the value."
          },
          {
            "name": "updated_at$lt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` is less than the value."
          },
          {
            "name": "updated_at$ge",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` is greater than or equal to the value."
          },
          {
            "name": "updated_at$le",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` is less than or equal to the value."
          },
          {
            "name": "first",
            "in": "query",
            "description": "Cursor mode: the number of objects to return from the start of the list, or after the `after` cursor.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "after",
            "in": "query",
            "description": "Cursor mode: the cursor after which the page starts, taken from `page_info.after` of the previous page.",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "name": "last",
            "in": "query",
            "description": "Cursor mode: the number of objects to return before the `before` cursor.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "before",
            "in": "query",
            "description": "Cursor mode: the cursor before which the page ends, taken from `page_info.before`.",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Offset mode: the number of objects to return. The default page size is 25.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Offset mode: the number of objects to skip.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "count",
            "in": "query",
            "description": "When `true`, adds `page_info.count`, the total number of matching objects.",
            "required": false,
            "schema": {
              "type": [
                "boolean",
                "null"
              ]
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Sort fields: `id`, `created_at`, `updated_at`, `name`. A `-` prefix sorts in descending order. A field name alone sorts in ascending order, as does a `+` prefix sent encoded as `%2B`. Repeat the parameter to sort by several fields. The default order is `id` ascending.",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The body is a paginated envelope whose `data` array holds the taxonomies the key can read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Paginated_TaxonomyResponse"
                }
              }
            }
          },
          "400": {
            "description": "A pagination or `order_by` parameter is invalid (`Pagination error` or `Invalid order_by parameter`)."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Returns a page of taxonomies that the key can read. The response is a paginated envelope. Results can be filtered by field and ordered, as described in [API conventions](../01-api-conventions.md).\n\n**Permissions.** Read on a taxonomy includes that taxonomy in the list. The list returns only the taxonomies the key can read.",
        "x-position": 62,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl \"$FOUNDATION4_URL/taxonomies\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/taxonomies\",\n    method=\"GET\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/taxonomies`, {\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/taxonomies\")\nrequest = Net::HTTP::Get.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      },
      "post": {
        "tags": [
          "Taxonomies"
        ],
        "summary": "Create a taxonomy",
        "operationId": "create_taxonomy",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTaxonomyRequest"
              },
              "example": {
                "name": "regions",
                "description": "Regions, countries and cities"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "The taxonomy was created. The body is the new taxonomy.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaxonomyResponse"
                }
              }
            }
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "403": {
            "description": "The key lacks write permission on the `taxonomies` object type, or the license does not allow another taxonomy (`Invalid license` or `License limits exceeded for Taxonomy`)."
          },
          "409": {
            "description": "A taxonomy with this name already exists (`Conflict unique error`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Creates a taxonomy. A taxonomy is independent of any pipeline, so one taxonomy can serve several pipelines. Entries are added with a separate operation. The response body is the new taxonomy.\n\n**Permissions.** Write on the `taxonomies` object type.\n\nSee [Metadata, filters and taxonomies](../../concepts/05-metadata-filters-taxonomies.md).",
        "x-position": 63,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X POST \"$FOUNDATION4_URL/taxonomies\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"name\": \"regions\",\n  \"description\": \"Regions, countries and cities\"\n}'"
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import json\nimport os\nimport urllib.error\nimport urllib.request\n\nbody = {\n    \"name\": \"regions\",\n    \"description\": \"Regions, countries and cities\",\n}\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/taxonomies\",\n    method=\"POST\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n        \"Content-Type\": \"application/json\",\n    },\n    data=json.dumps(body).encode(),\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/taxonomies`, {\n  method: \"POST\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    name: \"regions\",\n    description: \"Regions, countries and cities\",\n  }),\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"json\"\nrequire \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/taxonomies\")\nrequest = Net::HTTP::Post.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nrequest[\"Content-Type\"] = \"application/json\"\nrequest.body = JSON.generate({\n  \"name\" => \"regions\",\n  \"description\" => \"Regions, countries and cities\",\n})\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/taxonomies/{taxonomy_id}": {
      "get": {
        "tags": [
          "Taxonomies"
        ],
        "summary": "Get a taxonomy",
        "operationId": "get_taxonomy",
        "parameters": [
          {
            "name": "taxonomy_id",
            "in": "path",
            "description": "Identifier of the taxonomy.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The body is the taxonomy.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaxonomyResponse"
                }
              }
            }
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "404": {
            "description": "No taxonomy with this identifier exists, or the key lacks read permission on the taxonomy (`Taxonomy not found`). `details.id` holds the identifier."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Returns a taxonomy by identifier. The response body is the taxonomy.\n\n**Permissions.** Read on the taxonomy.\n\nSee [Metadata, filters and taxonomies](../../concepts/05-metadata-filters-taxonomies.md).",
        "x-position": 64,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl \"$FOUNDATION4_URL/taxonomies/$TAXONOMY_ID\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/taxonomies/{os.environ['TAXONOMY_ID']}\",\n    method=\"GET\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/taxonomies/${process.env.TAXONOMY_ID}`, {\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/taxonomies/#{ENV.fetch(\"TAXONOMY_ID\")}\")\nrequest = Net::HTTP::Get.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      },
      "delete": {
        "tags": [
          "Taxonomies"
        ],
        "summary": "Delete a taxonomy",
        "operationId": "delete_taxonomy",
        "parameters": [
          {
            "name": "taxonomy_id",
            "in": "path",
            "description": "Identifier of the taxonomy.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "The taxonomy was deleted. The response has no body."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "403": {
            "description": "The key lacks write permission on the taxonomy (`Unauthorized`)."
          },
          "404": {
            "description": "No taxonomy with this identifier exists (`Taxonomy with id <id> not found`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Deletes a taxonomy and every entry in the taxonomy. The response has no body.\n\n**Permissions.** Write on the taxonomy.\n\nSee [Metadata, filters and taxonomies](../../concepts/05-metadata-filters-taxonomies.md).",
        "x-position": 66,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X DELETE \"$FOUNDATION4_URL/taxonomies/$TAXONOMY_ID\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/taxonomies/{os.environ['TAXONOMY_ID']}\",\n    method=\"DELETE\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/taxonomies/${process.env.TAXONOMY_ID}`, {\n  method: \"DELETE\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/taxonomies/#{ENV.fetch(\"TAXONOMY_ID\")}\")\nrequest = Net::HTTP::Delete.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      },
      "patch": {
        "tags": [
          "Taxonomies"
        ],
        "summary": "Update a taxonomy",
        "operationId": "update_taxonomy",
        "parameters": [
          {
            "name": "taxonomy_id",
            "in": "path",
            "description": "Identifier of the taxonomy.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateTaxonomyRequest"
              },
              "example": {
                "description": "Sales regions, countries and cities"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "The taxonomy was updated. The body is the updated taxonomy.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaxonomyResponse"
                }
              }
            }
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "403": {
            "description": "The license does not allow the change (`Invalid license`)."
          },
          "404": {
            "description": "No taxonomy with this identifier exists, or the key lacks write permission on the taxonomy (`Taxonomy with id <id> not found`)."
          },
          "409": {
            "description": "The new name is already in use by another taxonomy (`Conflict unique error`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Changes the name or description of a taxonomy. The response body is the updated taxonomy.\n\n**Permissions.** Write on the taxonomy.\n\nSee [Metadata, filters and taxonomies](../../concepts/05-metadata-filters-taxonomies.md).",
        "x-position": 65,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X PATCH \"$FOUNDATION4_URL/taxonomies/$TAXONOMY_ID\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"description\": \"Sales regions, countries and cities\"\n}'"
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import json\nimport os\nimport urllib.error\nimport urllib.request\n\nbody = {\n    \"description\": \"Sales regions, countries and cities\",\n}\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/taxonomies/{os.environ['TAXONOMY_ID']}\",\n    method=\"PATCH\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n        \"Content-Type\": \"application/json\",\n    },\n    data=json.dumps(body).encode(),\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/taxonomies/${process.env.TAXONOMY_ID}`, {\n  method: \"PATCH\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    description: \"Sales regions, countries and cities\",\n  }),\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"json\"\nrequire \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/taxonomies/#{ENV.fetch(\"TAXONOMY_ID\")}\")\nrequest = Net::HTTP::Patch.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nrequest[\"Content-Type\"] = \"application/json\"\nrequest.body = JSON.generate({\n  \"description\" => \"Sales regions, countries and cities\",\n})\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/taxonomies/{taxonomy_id}/entries": {
      "get": {
        "tags": [
          "Taxonomies"
        ],
        "summary": "List taxonomy entries",
        "operationId": "list_taxonomy_entries",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "uuid"
            },
            "description": "Matches objects whose `id` equals the value."
          },
          {
            "name": "parent",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Returns only entries whose parent field has this name."
          },
          {
            "name": "parent$contains",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "Matches objects whose `parent` contains the value, case-sensitive. Repeat the parameter to require several values."
          },
          {
            "name": "parent$startswith",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Matches objects whose `parent` starts with the value."
          },
          {
            "name": "child",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Returns only entries whose child field has this name."
          },
          {
            "name": "child$contains",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "Matches objects whose `child` contains the value, case-sensitive. Repeat the parameter to require several values."
          },
          {
            "name": "child$startswith",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Matches objects whose `child` starts with the value."
          },
          {
            "name": "created_at",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` equals the value."
          },
          {
            "name": "created_at$gt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` is greater than the value."
          },
          {
            "name": "created_at$lt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` is less than the value."
          },
          {
            "name": "created_at$ge",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` is greater than or equal to the value."
          },
          {
            "name": "created_at$le",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` is less than or equal to the value."
          },
          {
            "name": "updated_at",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` equals the value."
          },
          {
            "name": "updated_at$gt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` is greater than the value."
          },
          {
            "name": "updated_at$lt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` is less than the value."
          },
          {
            "name": "updated_at$ge",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` is greater than or equal to the value."
          },
          {
            "name": "updated_at$le",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` is less than or equal to the value."
          },
          {
            "name": "first",
            "in": "query",
            "description": "Cursor mode: the number of objects to return from the start of the list, or after the `after` cursor.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "after",
            "in": "query",
            "description": "Cursor mode: the cursor after which the page starts, taken from `page_info.after` of the previous page.",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "name": "last",
            "in": "query",
            "description": "Cursor mode: the number of objects to return before the `before` cursor.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "before",
            "in": "query",
            "description": "Cursor mode: the cursor before which the page ends, taken from `page_info.before`.",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Offset mode: the number of objects to return. The default page size is 25.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Offset mode: the number of objects to skip.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "count",
            "in": "query",
            "description": "When `true`, adds `page_info.count`, the total number of matching objects.",
            "required": false,
            "schema": {
              "type": [
                "boolean",
                "null"
              ]
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Sort fields: `id`, `created_at`, `updated_at`. A `-` prefix sorts in descending order. A field name alone sorts in ascending order, as does a `+` prefix sent encoded as `%2B`. Repeat the parameter to sort by several fields. The default order is `id` ascending.",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "taxonomy_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Identifier of the taxonomy."
          }
        ],
        "responses": {
          "200": {
            "description": "The body is a paginated envelope whose `data` array holds the taxonomy entries.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Paginated_TaxonomyEntry"
                }
              }
            }
          },
          "400": {
            "description": "A pagination or `order_by` parameter is invalid (`Pagination error` or `Invalid order_by parameter`)."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "404": {
            "description": "No taxonomy with this identifier exists, or the key lacks read permission on the taxonomy (`Taxonomy with id <id> not found`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Returns a page of the entries of a taxonomy. Each entry links a parent field and value to a child field and value. The response is a paginated envelope. Results can be filtered by field and ordered, as described in [API conventions](../01-api-conventions.md).\n\n**Permissions.** Read on the taxonomy.\n\nSee [Metadata, filters and taxonomies](../../concepts/05-metadata-filters-taxonomies.md).",
        "x-position": 67,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl \"$FOUNDATION4_URL/taxonomies/$TAXONOMY_ID/entries\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/taxonomies/{os.environ['TAXONOMY_ID']}/entries\",\n    method=\"GET\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/taxonomies/${process.env.TAXONOMY_ID}/entries`, {\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/taxonomies/#{ENV.fetch(\"TAXONOMY_ID\")}/entries\")\nrequest = Net::HTTP::Get.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      },
      "post": {
        "tags": [
          "Taxonomies"
        ],
        "summary": "Create taxonomy entries",
        "operationId": "create_taxonomy_entries",
        "parameters": [
          {
            "name": "taxonomy_id",
            "in": "path",
            "description": "Identifier of the taxonomy.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/CreateTaxonomyEntryRequest"
                }
              },
              "example": [
                {
                  "parent": "region",
                  "parent_value": "Europe",
                  "child": "country",
                  "child_value": "France"
                },
                {
                  "parent": "region",
                  "parent_value": "Europe",
                  "child": "country",
                  "child_value": "Germany"
                },
                {
                  "parent": "country",
                  "parent_value": "France",
                  "child": "city",
                  "child_value": "Paris"
                }
              ]
            }
          },
          "required": true,
          "description": "A JSON array of entries. Each entry names a parent field and value and a child field and value."
        },
        "responses": {
          "201": {
            "description": "The entries were created. The body is the array of created entries.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/TaxonomyEntry"
                  }
                }
              }
            }
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "403": {
            "description": "The license does not allow the change (`Invalid license`)."
          },
          "404": {
            "description": "No taxonomy with this identifier exists, or the key lacks write permission on the taxonomy (`Taxonomy with id <id> not found`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Adds entries to a taxonomy. The request body is a JSON array of entries, each linking a parent field and value to a child field and value. The response body is the array of entries that were created. Changes take effect in the next search, without reprocessing any document.\n\n**Permissions.** Write on the taxonomy.\n\nSee [Metadata, filters and taxonomies](../../concepts/05-metadata-filters-taxonomies.md).",
        "x-position": 68,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X POST \"$FOUNDATION4_URL/taxonomies/$TAXONOMY_ID/entries\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '[\n  {\n    \"parent\": \"region\",\n    \"parent_value\": \"Europe\",\n    \"child\": \"country\",\n    \"child_value\": \"France\"\n  },\n  {\n    \"parent\": \"region\",\n    \"parent_value\": \"Europe\",\n    \"child\": \"country\",\n    \"child_value\": \"Germany\"\n  },\n  {\n    \"parent\": \"country\",\n    \"parent_value\": \"France\",\n    \"child\": \"city\",\n    \"child_value\": \"Paris\"\n  }\n]'"
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import json\nimport os\nimport urllib.error\nimport urllib.request\n\nbody = [\n    {\n        \"parent\": \"region\",\n        \"parent_value\": \"Europe\",\n        \"child\": \"country\",\n        \"child_value\": \"France\",\n    },\n    {\n        \"parent\": \"region\",\n        \"parent_value\": \"Europe\",\n        \"child\": \"country\",\n        \"child_value\": \"Germany\",\n    },\n    {\n        \"parent\": \"country\",\n        \"parent_value\": \"France\",\n        \"child\": \"city\",\n        \"child_value\": \"Paris\",\n    },\n]\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/taxonomies/{os.environ['TAXONOMY_ID']}/entries\",\n    method=\"POST\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n        \"Content-Type\": \"application/json\",\n    },\n    data=json.dumps(body).encode(),\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/taxonomies/${process.env.TAXONOMY_ID}/entries`, {\n  method: \"POST\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify([\n    {\n      parent: \"region\",\n      parent_value: \"Europe\",\n      child: \"country\",\n      child_value: \"France\",\n    },\n    {\n      parent: \"region\",\n      parent_value: \"Europe\",\n      child: \"country\",\n      child_value: \"Germany\",\n    },\n    {\n      parent: \"country\",\n      parent_value: \"France\",\n      child: \"city\",\n      child_value: \"Paris\",\n    },\n  ]),\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"json\"\nrequire \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/taxonomies/#{ENV.fetch(\"TAXONOMY_ID\")}/entries\")\nrequest = Net::HTTP::Post.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nrequest[\"Content-Type\"] = \"application/json\"\nrequest.body = JSON.generate([\n  {\n    \"parent\" => \"region\",\n    \"parent_value\" => \"Europe\",\n    \"child\" => \"country\",\n    \"child_value\" => \"France\",\n  },\n  {\n    \"parent\" => \"region\",\n    \"parent_value\" => \"Europe\",\n    \"child\" => \"country\",\n    \"child_value\" => \"Germany\",\n  },\n  {\n    \"parent\" => \"country\",\n    \"parent_value\" => \"France\",\n    \"child\" => \"city\",\n    \"child_value\" => \"Paris\",\n  },\n])\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      },
      "delete": {
        "tags": [
          "Taxonomies"
        ],
        "summary": "Delete taxonomy entries",
        "operationId": "delete_taxonomy_entries",
        "parameters": [
          {
            "name": "taxonomy_id",
            "in": "path",
            "description": "Identifier of the taxonomy.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "entry_id",
            "in": "query",
            "description": "Identifier of a taxonomy entry to delete. The parameter is repeated once for each entry, and at least one value is required.",
            "required": true,
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "format": "uuid"
              }
            }
          }
        ],
        "responses": {
          "204": {
            "description": "The entries were deleted. The response has no body."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "403": {
            "description": "The license does not allow the change (`Invalid license`)."
          },
          "404": {
            "description": "No taxonomy with this identifier exists, or the key lacks write permission on the taxonomy (`Taxonomy with id <id> not found`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Deletes taxonomy entries by identifier. The identifiers are given in the `entry_id` query parameter, repeated once for each entry. The response has no body.\n\n**Permissions.** Write on the taxonomy.\n\nSee [Metadata, filters and taxonomies](../../concepts/05-metadata-filters-taxonomies.md).",
        "x-position": 69,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X DELETE \"$FOUNDATION4_URL/taxonomies/$TAXONOMY_ID/entries?entry_id=$ENTRY_ID\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/taxonomies/{os.environ['TAXONOMY_ID']}/entries?entry_id={os.environ['ENTRY_ID']}\",\n    method=\"DELETE\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/taxonomies/${process.env.TAXONOMY_ID}/entries?entry_id=${process.env.ENTRY_ID}`, {\n  method: \"DELETE\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/taxonomies/#{ENV.fetch(\"TAXONOMY_ID\")}/entries?entry_id=#{ENV.fetch(\"ENTRY_ID\")}\")\nrequest = Net::HTTP::Delete.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/text-splitters": {
      "get": {
        "tags": [
          "Text Splitters"
        ],
        "summary": "List text splitters",
        "operationId": "list_text_splitters",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "uuid"
            },
            "description": "Returns only the text splitter with this identifier."
          },
          {
            "name": "provider",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Returns only text splitters whose provider name equals this value, such as `RecursiveCharacterTextSplitter`. The match is case-sensitive."
          },
          {
            "name": "provider$contains",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "Matches objects whose `provider` contains the value, case-sensitive. Repeat the parameter to require several values."
          },
          {
            "name": "provider$startswith",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Matches objects whose `provider` starts with the value."
          },
          {
            "name": "description",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Returns only text splitters whose description equals this value, case-sensitive."
          },
          {
            "name": "description$contains",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "Matches objects whose `description` contains the value, case-sensitive. Repeat the parameter to require several values."
          },
          {
            "name": "created_at",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Returns only text splitters created at exactly this time, in RFC 3339 format."
          },
          {
            "name": "created_at$gt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` is greater than the value."
          },
          {
            "name": "created_at$lt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` is less than the value."
          },
          {
            "name": "created_at$ge",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` is greater than or equal to the value."
          },
          {
            "name": "created_at$le",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `created_at` is less than or equal to the value."
          },
          {
            "name": "updated_at",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Returns only text splitters last changed at exactly this time, in RFC 3339 format."
          },
          {
            "name": "updated_at$gt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` is greater than the value."
          },
          {
            "name": "updated_at$lt",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` is less than the value."
          },
          {
            "name": "updated_at$ge",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` is greater than or equal to the value."
          },
          {
            "name": "updated_at$le",
            "in": "query",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            },
            "description": "Matches objects whose `updated_at` is less than or equal to the value."
          },
          {
            "name": "first",
            "in": "query",
            "description": "Cursor mode: the number of objects to return from the start of the list, or after the `after` cursor.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "after",
            "in": "query",
            "description": "Cursor mode: the cursor after which the page starts, taken from `page_info.after` of the previous page.",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "name": "last",
            "in": "query",
            "description": "Cursor mode: the number of objects to return before the `before` cursor.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "before",
            "in": "query",
            "description": "Cursor mode: the cursor before which the page ends, taken from `page_info.before`.",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Offset mode: the number of objects to return. The default page size is 25.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Offset mode: the number of objects to skip.",
            "required": false,
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0
            }
          },
          {
            "name": "count",
            "in": "query",
            "description": "When `true`, adds `page_info.count`, the total number of matching objects.",
            "required": false,
            "schema": {
              "type": [
                "boolean",
                "null"
              ]
            }
          },
          {
            "name": "order_by",
            "in": "query",
            "description": "Sort fields: `id`, `created_at`, `updated_at`, `provider`. A `-` prefix sorts in descending order. A field name alone sorts in ascending order, as does a `+` prefix sent encoded as `%2B`. Repeat the parameter to sort by several fields. The default order is `id` ascending.",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of text splitters. The body is the pagination envelope, with the text splitters in `data`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Paginated_TextSplitterResponse"
                }
              }
            }
          },
          "400": {
            "description": "The pagination parameters are invalid, such as cursor and offset parameters in one request (`Pagination error`), or `order_by` names a field that the operation cannot sort by (`Invalid order_by parameter`)."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Returns a page of the text splitters that the key can read. Filters apply to the provider, the description and the timestamps. `order_by` accepts `id`, `created_at`, `updated_at` and `provider`. [API conventions](../01-api-conventions.md) describes pagination, filters and ordering.\n\n**Permissions.** Read on the text splitters. The list contains only the text splitters that the key can read.",
        "x-position": 70,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl \"$FOUNDATION4_URL/text-splitters\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/text-splitters\",\n    method=\"GET\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/text-splitters`, {\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/text-splitters\")\nrequest = Net::HTTP::Get.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      },
      "post": {
        "tags": [
          "Text Splitters"
        ],
        "summary": "Create a text splitter",
        "operationId": "create_text_splitter",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTextSplitterRequest"
              },
              "example": {
                "provider": "RecursiveCharacterTextSplitter",
                "description": "1,000-character fragments with 200 characters of overlap",
                "parameters": {
                  "chunk_size": 1000,
                  "chunk_overlap": 200
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "The text splitter was created. The body is the new text splitter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TextSplitterResponse"
                }
              }
            }
          },
          "400": {
            "description": "The request is invalid (`Invalid parameter`), and `details.error` names the cause: an unknown provider name or a parameter that the provider does not accept."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "403": {
            "description": "The key lacks write permission on the `text-splitters` object type (`Unauthorized: access level AccessLevel(WRITE) required for Text Splitter with id None`). The same status reports a license that is not valid (`Invalid license: <reason>`) and a reached license limit (`License limits exceeded for Text Splitter`)."
          },
          "404": {
            "description": "The key lacks write permission on the text splitter provider that `provider` names (`Text Splitter not found`)."
          },
          "500": {
            "description": "The provider failed while splitting the test string, for example because a parameter value is invalid or the gRPC service is unreachable (`Internal error`). `details.error` holds the cause."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Creates a text splitter: a configured instance of a text splitter provider, with parameters. A text splitter has no name, and a deployment can hold several text splitters of the same provider. Before storing the text splitter, Foundation4 splits a test string with the provider, so the request fails when the provider does not accept the parameters. After creation, only `description` can change.\n\n**Permissions.** Write on the `text-splitters` object type and write on the text splitter provider that `provider` names.\n\n[Embedding models and text splitters](../../concepts/06-embedding-models-text-splitters.md) shows example requests, and [Providers and models](../../reference/01-providers-and-models.md) lists the parameters of each provider.",
        "x-position": 71,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X POST \"$FOUNDATION4_URL/text-splitters\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"provider\": \"RecursiveCharacterTextSplitter\",\n  \"description\": \"1,000-character fragments with 200 characters of overlap\",\n  \"parameters\": {\n    \"chunk_size\": 1000,\n    \"chunk_overlap\": 200\n  }\n}'"
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import json\nimport os\nimport urllib.error\nimport urllib.request\n\nbody = {\n    \"provider\": \"RecursiveCharacterTextSplitter\",\n    \"description\": \"1,000-character fragments with 200 characters of overlap\",\n    \"parameters\": {\n        \"chunk_size\": 1000,\n        \"chunk_overlap\": 200,\n    },\n}\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/text-splitters\",\n    method=\"POST\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n        \"Content-Type\": \"application/json\",\n    },\n    data=json.dumps(body).encode(),\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/text-splitters`, {\n  method: \"POST\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    provider: \"RecursiveCharacterTextSplitter\",\n    description: \"1,000-character fragments with 200 characters of overlap\",\n    parameters: {\n      chunk_size: 1000,\n      chunk_overlap: 200,\n    },\n  }),\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"json\"\nrequire \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/text-splitters\")\nrequest = Net::HTTP::Post.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nrequest[\"Content-Type\"] = \"application/json\"\nrequest.body = JSON.generate({\n  \"provider\" => \"RecursiveCharacterTextSplitter\",\n  \"description\" => \"1,000-character fragments with 200 characters of overlap\",\n  \"parameters\" => {\n    \"chunk_size\" => 1000,\n    \"chunk_overlap\" => 200,\n  },\n})\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/text-splitters/{text_splitter_id}": {
      "get": {
        "tags": [
          "Text Splitters"
        ],
        "summary": "Get a text splitter",
        "operationId": "get_text_splitter",
        "parameters": [
          {
            "name": "text_splitter_id",
            "in": "path",
            "description": "Identifier of the text splitter.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The text splitter was found. The body is the text splitter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TextSplitterResponse"
                }
              }
            }
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "404": {
            "description": "No text splitter with this identifier exists, or the key lacks read permission on the text splitter (`Text Splitter not found`). `details.id` holds the identifier."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Returns one text splitter: the provider and the parameters that Foundation4 passes to the provider.\n\n**Permissions.** Read on the text splitter.",
        "x-position": 72,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl \"$FOUNDATION4_URL/text-splitters/$TEXT_SPLITTER_ID\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/text-splitters/{os.environ['TEXT_SPLITTER_ID']}\",\n    method=\"GET\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/text-splitters/${process.env.TEXT_SPLITTER_ID}`, {\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/text-splitters/#{ENV.fetch(\"TEXT_SPLITTER_ID\")}\")\nrequest = Net::HTTP::Get.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      },
      "delete": {
        "tags": [
          "Text Splitters"
        ],
        "summary": "Delete a text splitter",
        "operationId": "delete_text_splitter",
        "parameters": [
          {
            "name": "text_splitter_id",
            "in": "path",
            "description": "Identifier of the text splitter.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "The text splitter was deleted. The response has no body."
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "403": {
            "description": "The key lacks write permission on the text splitter (`Unauthorized: access level AccessLevel(WRITE) required for Text Splitter with id Some(<id>)`)."
          },
          "404": {
            "description": "No text splitter with this identifier exists (`Text Splitter with id <id> not found`)."
          },
          "409": {
            "description": "A pipeline uses the text splitter as the default text splitter (`Conflict related error`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Deletes a text splitter. A text splitter that is the default text splitter of a pipeline cannot be deleted: the request returns HTTP 409 until each such pipeline uses another default text splitter or is deleted.\n\n**Permissions.** Write on the text splitter.",
        "x-position": 74,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X DELETE \"$FOUNDATION4_URL/text-splitters/$TEXT_SPLITTER_ID\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/text-splitters/{os.environ['TEXT_SPLITTER_ID']}\",\n    method=\"DELETE\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/text-splitters/${process.env.TEXT_SPLITTER_ID}`, {\n  method: \"DELETE\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/text-splitters/#{ENV.fetch(\"TEXT_SPLITTER_ID\")}\")\nrequest = Net::HTTP::Delete.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      },
      "patch": {
        "tags": [
          "Text Splitters"
        ],
        "summary": "Update a text splitter",
        "operationId": "update_text_splitter",
        "parameters": [
          {
            "name": "text_splitter_id",
            "in": "path",
            "description": "Identifier of the text splitter.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateTextSplitterRequest"
              },
              "example": {
                "description": "Support articles: 1,000-character fragments with 200 characters of overlap"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "The text splitter was updated. The body is the updated text splitter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TextSplitterResponse"
                }
              }
            }
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "403": {
            "description": "The license is not valid (`Invalid license: <reason>`)."
          },
          "404": {
            "description": "No text splitter with this identifier exists, or the key lacks write permission on the text splitter."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Changes the `description` of a text splitter. `\"description\": null` removes the description, and an omitted field keeps the current description. The provider and the parameters cannot change, and Foundation4 ignores these fields in the request. Different parameters require a new text splitter.\n\n**Permissions.** Write on the text splitter.",
        "x-position": 73,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl -X PATCH \"$FOUNDATION4_URL/text-splitters/$TEXT_SPLITTER_ID\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"description\": \"Support articles: 1,000-character fragments with 200 characters of overlap\"\n}'"
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import json\nimport os\nimport urllib.error\nimport urllib.request\n\nbody = {\n    \"description\": \"Support articles: 1,000-character fragments with 200 characters of overlap\",\n}\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/text-splitters/{os.environ['TEXT_SPLITTER_ID']}\",\n    method=\"PATCH\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n        \"Content-Type\": \"application/json\",\n    },\n    data=json.dumps(body).encode(),\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/text-splitters/${process.env.TEXT_SPLITTER_ID}`, {\n  method: \"PATCH\",\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    description: \"Support articles: 1,000-character fragments with 200 characters of overlap\",\n  }),\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"json\"\nrequire \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/text-splitters/#{ENV.fetch(\"TEXT_SPLITTER_ID\")}\")\nrequest = Net::HTTP::Patch.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nrequest[\"Content-Type\"] = \"application/json\"\nrequest.body = JSON.generate({\n  \"description\" => \"Support articles: 1,000-character fragments with 200 characters of overlap\",\n})\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    },
    "/tracing/{execution_id}": {
      "get": {
        "tags": [
          "Agents"
        ],
        "summary": "Get an execution trace",
        "operationId": "get_trace",
        "parameters": [
          {
            "name": "execution_id",
            "in": "path",
            "description": "Identifier of the trace, from the `x-foundation4ai-tracing-id` header of the execution response.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The trace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CacheTracingInformation"
                }
              }
            }
          },
          "401": {
            "description": "The authentication headers are missing or invalid, or the API key is inactive or expired. [Errors](../04-errors.md#http-401) lists the messages."
          },
          "404": {
            "description": "No trace with this identifier exists for the key: the trace expired, a different API key ran the execution or the identifier is wrong (`Trace with id <id> not found`)."
          }
        },
        "security": [
          {
            "api_key": [],
            "api_key_secret": []
          }
        ],
        "description": "Returns the trace of an agent execution that ran with `tracing` set to `true`: the input values, the fragments that each retrieval placeholder retrieved and the messages as sent to the LLM. The trace does not contain the answer, and Foundation4 keeps a trace for 60 minutes after the execution.\n\n**Permissions.** None on an object. Only the API key that ran the execution can read the trace.\n\n[Agents and prompt templates](../../concepts/08-agents-prompt-templates.md) describes tracing.",
        "x-position": 75,
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "Example",
            "source": "curl \"$FOUNDATION4_URL/tracing/$EXECUTION_ID\" \\\n  -H \"x-api-key: $FOUNDATION4_API_KEY\" \\\n  -H \"x-api-key-secret: $FOUNDATION4_API_SECRET\""
          },
          {
            "lang": "Python",
            "label": "Example",
            "source": "import os\nimport urllib.error\nimport urllib.request\n\nrequest = urllib.request.Request(\n    f\"{os.environ['FOUNDATION4_URL']}/tracing/{os.environ['EXECUTION_ID']}\",\n    method=\"GET\",\n    headers={\n        \"x-api-key\": os.environ[\"FOUNDATION4_API_KEY\"],\n        \"x-api-key-secret\": os.environ[\"FOUNDATION4_API_SECRET\"],\n    },\n)\ntry:\n    with urllib.request.urlopen(request) as response:\n        print(response.status, response.read().decode())\nexcept urllib.error.HTTPError as error:\n    print(error.code, error.read().decode())"
          },
          {
            "lang": "TypeScript",
            "label": "Example",
            "source": "const response = await fetch(`${process.env.FOUNDATION4_URL}/tracing/${process.env.EXECUTION_ID}`, {\n  headers: {\n    \"x-api-key\": process.env.FOUNDATION4_API_KEY!,\n    \"x-api-key-secret\": process.env.FOUNDATION4_API_SECRET!,\n  },\n});\nconsole.log(response.status, await response.text());"
          },
          {
            "lang": "Ruby",
            "label": "Example",
            "source": "require \"net/http\"\n\nuri = URI(\"#{ENV.fetch(\"FOUNDATION4_URL\")}/tracing/#{ENV.fetch(\"EXECUTION_ID\")}\")\nrequest = Net::HTTP::Get.new(uri)\nrequest[\"x-api-key\"] = ENV.fetch(\"FOUNDATION4_API_KEY\")\nrequest[\"x-api-key-secret\"] = ENV.fetch(\"FOUNDATION4_API_SECRET\")\nresponse = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == \"https\") do |http|\n  http.request(request)\nend\nputs \"#{response.code} #{response.body}\""
          }
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "AccessLevel": {
        "type": "integer",
        "description": "Permission as the sum of the permission bits: read 4, write 2 and execute 1. The value 0 grants no permission and 7 grants all three.",
        "minimum": 0,
        "maximum": 7
      },
      "Agent": {
        "type": "object",
        "required": [
          "id",
          "created_at",
          "updated_at",
          "name",
          "prompt",
          "placeholders"
        ],
        "properties": {
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Creation time of the agent, as an RFC 3339 timestamp."
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "Free text for administrators, or `null`."
          },
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Identifier of the agent."
          },
          "metadata": {
            "$ref": "#/components/schemas/JsonMap2",
            "description": "Descriptive data for the client application. Each top-level value is a JSON object. Foundation4 stores metadata and does not use metadata during execution."
          },
          "name": {
            "type": "string",
            "description": "Name of the agent, unique across the deployment."
          },
          "placeholders": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Placeholder"
            },
            "description": "Named values that the templates insert: request values and retrieval results."
          },
          "prompt": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Prompt"
            },
            "description": "Prompt template: the messages in the order that the LLM receives them."
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Time of the last change to the agent, as an RFC 3339 timestamp."
          }
        },
        "description": "An agent: a stored prompt template with the placeholders that the template uses."
      },
      "AgentPromptResponse": {
        "type": "object",
        "description": "Stored prompt template, placeholders and input variables of an agent.",
        "required": [
          "prompt",
          "placeholders",
          "input_variables"
        ],
        "properties": {
          "input_variables": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Names of the `query` placeholders, whose values each execution supplies in `prompt`. The order is not specified.",
            "uniqueItems": true
          },
          "placeholders": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Placeholder"
            },
            "description": "Placeholders of the agent as stored."
          },
          "prompt": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Prompt"
            },
            "description": "Messages of the prompt template as stored, without substitution."
          }
        }
      },
      "AgentQueryExecuteRequest": {
        "type": "object",
        "required": [
          "prompt",
          "classification"
        ],
        "properties": {
          "classification": {
            "$ref": "#/components/schemas/ClassificationSearchParametersVariants",
            "description": "Classifications that the reader holds: a string, an array of strings or an object with `classifications` and `search_type`, in the forms that a search request accepts."
          },
          "filters": {
            "type": "object",
            "description": "Metadata filters keyed by the name of a retrieval placeholder. Each filter applies to the retrieval of that placeholder only. The default is no filter.",
            "additionalProperties": {
              "$ref": "#/components/schemas/Filter"
            },
            "propertyNames": {
              "type": "string"
            }
          },
          "prompt": {
            "type": "object",
            "description": "Values of the agent's `query` placeholders, keyed by placeholder name, such as `{\"question\": \"How do I rotate the database credentials?\"}`. Every `query` placeholder of the agent requires a value.",
            "additionalProperties": {
              "type": "string"
            },
            "propertyNames": {
              "type": "string"
            }
          },
          "stream": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/StreamTypeOption"
              }
            ],
            "description": "Response format: `true`, `\"stream\"`, `null` or an omitted field for newline-delimited JSON (NDJSON), `\"sse\"` for server-sent events, `false` for the complete answer as plain text."
          },
          "temperature": {
            "type": [
              "number",
              "null"
            ],
            "format": "double",
            "description": "Sampling temperature that Foundation4 sends to the model server. When omitted, the model server's default applies."
          },
          "tracing": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "When `true`, Foundation4 records a trace of the execution for 60 minutes and returns the trace identifier in the `x-foundation4ai-tracing-id` response header. The default is `false`."
          }
        },
        "description": "Body of an agent execution."
      },
      "AgentQuerySearchRequest": {
        "type": "object",
        "required": [
          "prompt",
          "classification"
        ],
        "properties": {
          "classification": {
            "$ref": "#/components/schemas/ClassificationSearchParametersVariants",
            "description": "Classifications that the reader holds: a string, an array of strings or an object with `classifications` and `search_type`, in the forms that a search request accepts."
          },
          "filters": {
            "type": "object",
            "description": "Metadata filters keyed by the name of a retrieval placeholder. Each filter applies to the retrieval of that placeholder only. The default is no filter.",
            "additionalProperties": {
              "$ref": "#/components/schemas/Filter"
            },
            "propertyNames": {
              "type": "string"
            }
          },
          "prompt": {
            "type": "object",
            "description": "Values of the agent's `query` placeholders, keyed by placeholder name, such as `{\"question\": \"How do I rotate the database credentials?\"}`.",
            "additionalProperties": {
              "type": "string"
            },
            "propertyNames": {
              "type": "string"
            }
          }
        },
        "description": "Body of an agent retrieval dry run."
      },
      "AgentResponse": {
        "$ref": "#/components/schemas/Agent",
        "description": "An agent: a stored prompt template with the placeholders that the template uses."
      },
      "ApiKeyPermission": {
        "type": "object",
        "required": [
          "object_type",
          "object_id",
          "permission"
        ],
        "properties": {
          "classifications": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Classification allow-list of a `pipelines` entry, or `null` when the entry has no allow-list.",
            "nullable": true
          },
          "object_id": {
            "type": "string",
            "format": "uuid",
            "description": "Identifier of the object, or `00000000-0000-0000-0000-000000000000` for an entry on the whole object type."
          },
          "object_type": {
            "$ref": "#/components/schemas/ObjectTypes",
            "description": "Object type of the entry."
          },
          "permission": {
            "$ref": "#/components/schemas/AccessLevel",
            "description": "Permission of the entry, as the sum of the permission bits: read 4, write 2 and execute 1."
          }
        },
        "description": "A permission entry of an API key, on an object type or on one object."
      },
      "ApiKeyPermissionRequest": {
        "type": "object",
        "required": [
          "object_type",
          "object_id",
          "permission"
        ],
        "properties": {
          "object_id": {
            "type": "string",
            "format": "uuid",
            "description": "Identifier of the object, or `00000000-0000-0000-0000-000000000000` for an entry on the whole object type."
          },
          "object_type": {
            "$ref": "#/components/schemas/ObjectTypes",
            "description": "Object type of the entry."
          },
          "permission": {
            "$ref": "#/components/schemas/AccessLevel",
            "description": "Permission to set, as the sum of the permission bits: read 4, write 2 and execute 1. The value 0 removes the entry."
          }
        },
        "description": "A permission entry to set on an API key."
      },
      "ApiKeyResponse": {
        "type": "object",
        "description": "An API key, without the key's secret.",
        "required": [
          "id",
          "created_at",
          "updated_at",
          "name",
          "active"
        ],
        "properties": {
          "active": {
            "type": "boolean",
            "description": "`true` when the key can authenticate requests, and `false` after the key is deactivated."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Time the key was created, in RFC 3339 format."
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "Description of the API key, or `null`."
          },
          "expiration": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Time after which the key no longer authenticates, in RFC 3339 format, or `null` for a key that does not expire."
          },
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Identifier of the API key. Requests send the identifier in the `x-api-key` header."
          },
          "name": {
            "type": "string",
            "description": "Name of the API key, unique across the deployment."
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Time the key was last changed, in RFC 3339 format."
          }
        }
      },
      "ApiLlmResponse": {
        "type": "object",
        "description": "One part of a streamed answer: one line of an NDJSON response, or the data of one server-sent event.",
        "required": [
          "content"
        ],
        "properties": {
          "content": {
            "type": "string",
            "description": "Next part of the generated answer. The value can be an empty string, which client applications skip."
          }
        }
      },
      "AuthResponse": {
        "type": "object",
        "description": "Result of an API key check: the name and description of the key and the key's permissions on object types.",
        "required": [
          "message",
          "key",
          "permissions"
        ],
        "properties": {
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "Description of the API key, or `null`.",
            "examples": [
              "Description for key 1"
            ]
          },
          "key": {
            "type": "string",
            "description": "Name of the API key. The field holds the name, not the identifier.",
            "examples": [
              "Api Key 1"
            ]
          },
          "message": {
            "type": "string",
            "description": "Result of the check. The value is always `OK`.",
            "examples": [
              "OK"
            ],
            "enum": [
              "OK"
            ]
          },
          "permissions": {
            "type": "object",
            "description": "Permissions of the API key on object types, keyed by object type. Each value holds the permission and the classification allow-list. Permissions on individual objects are not included.",
            "additionalProperties": {
              "$ref": "#/components/schemas/PermissionEntry"
            },
            "propertyNames": {
              "type": "string",
              "description": "Object type, such as `pipelines`.",
              "enum": [
                "agents",
                "api-keys",
                "contexts",
                "context-messages",
                "documents",
                "embedding-models",
                "embedding-providers",
                "llms",
                "pipelines",
                "taxonomies",
                "text-splitter-providers",
                "text-splitters",
                "permissions",
                "fragments"
              ]
            }
          }
        }
      },
      "BodyDataIds": {
        "type": "object",
        "description": "Body of the deprecated request that reads fragments by identifier.",
        "properties": {
          "ids": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Identifiers of the fragments to return."
          }
        }
      },
      "CacheTracingInformation": {
        "type": "object",
        "required": [
          "traces",
          "prompt",
          "inputs"
        ],
        "properties": {
          "inputs": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "propertyNames": {
              "type": "string"
            },
            "description": "Values of the `query` placeholders from the execution request, keyed by placeholder name."
          },
          "prompt": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "role",
                "template"
              ],
              "properties": {
                "role": {
                  "$ref": "#/components/schemas/PromptType"
                },
                "template": {
                  "type": "string",
                  "description": "The text of the message after placeholder substitution."
                }
              }
            },
            "description": "Messages sent to the LLM after substitution, in order, each with `role` and `template`. Messages with `include` set to `false` do not appear."
          },
          "traces": {
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": {
                "$ref": "#/components/schemas/Fragment"
              }
            },
            "propertyNames": {
              "type": "string"
            },
            "description": "Fragments that each retrieval placeholder retrieved, keyed by placeholder name, including the fragment text."
          }
        },
        "description": "Trace of an agent execution: the input values, the retrieved fragments and the messages sent to the LLM."
      },
      "Classification": {
        "description": "A classification, given as either a name or an inheritance pair. A string is a classification with no inheritance. A two-element array `[name, inherited]` records that `name` inherits `inherited`; the second element may be null, which is equivalent to the name alone.",
        "title": "Classification",
        "oneOf": [
          {
            "title": "Name",
            "type": "string",
            "description": "A classification with no inheritance.",
            "example": "public"
          },
          {
            "title": "Inheritance pair",
            "type": "array",
            "description": "A two-element array `[name, inherited]`. The classification `name` inherits the classification `inherited`. A null second element is equivalent to the name alone.",
            "minItems": 2,
            "maxItems": 2,
            "items": {
              "type": [
                "string",
                "null"
              ]
            },
            "example": [
              "internal",
              "public"
            ]
          }
        ]
      },
      "ClassificationSearch": {
        "type": "object",
        "description": "Classification names with a matching mode.",
        "required": [
          "classifications"
        ],
        "properties": {
          "classifications": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The classification names. The field name is plural."
          },
          "search_type": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/ClassificationSearchType"
              }
            ],
            "description": "The matching mode: `2` (default) matches hierarchically and ignores undefined names, `1` matches the named classifications only, and `3` matches hierarchically and returns HTTP 404 for an undefined name."
          }
        }
      },
      "ClassificationSearchParametersVariants": {
        "oneOf": [
          {
            "type": "string",
            "description": "One classification name, matched hierarchically.",
            "title": "String"
          },
          {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Classification names, matched hierarchically.",
            "title": "Array"
          },
          {
            "$ref": "#/components/schemas/ClassificationSearch",
            "description": "Classification names with a matching mode.",
            "title": "Object"
          }
        ],
        "description": "The classifications that the reader holds. [Search requests](../02-search-requests.md#classification) describes the forms and the matching modes.",
        "title": "Classification"
      },
      "ClassificationSearchType": {
        "type": "integer",
        "enum": [
          1,
          2,
          3
        ],
        "description": "The classification matching mode: `1` exact, `2` hierarchical (default), `3` hierarchical with validation."
      },
      "CreateAgentRequest": {
        "type": "object",
        "description": "Fields of a new agent.",
        "required": [
          "name",
          "prompt",
          "placeholders"
        ],
        "properties": {
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "Free text for administrators."
          },
          "metadata": {
            "$ref": "#/components/schemas/JsonMap2",
            "description": "Descriptive data for the client application. Each top-level value is a JSON object, such as `{\"owner\": {\"team\": \"support\"}}`. The default is an empty object."
          },
          "name": {
            "type": "string",
            "description": "Name of the agent, unique across the deployment."
          },
          "placeholders": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Placeholder"
            },
            "description": "Named values that the templates insert. Every name in braces in a template is the name of a placeholder. The array is empty when no template contains a placeholder."
          },
          "prompt": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Prompt"
            },
            "description": "Prompt template: the messages in the order that the LLM receives them. The prompt contains at least one `system` message and one `user` message, and the last message is a `user` message."
          }
        }
      },
      "CreateApiKeyRequest": {
        "type": "object",
        "description": "Request body that creates an API key.",
        "required": [
          "name"
        ],
        "properties": {
          "classifications": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Classification allow-list of the `pipelines` permission. Foundation4 stores the list only when `permissions` includes `pipelines`. The value `*` permits every classification.",
            "uniqueItems": true,
            "nullable": true
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "Free-text description of the API key."
          },
          "expiration": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Time after which the key no longer authenticates, in RFC 3339 format. A key without an expiration time does not expire."
          },
          "name": {
            "type": "string",
            "description": "Name of the API key, unique across the deployment."
          },
          "permissions": {
            "type": "object",
            "description": "Permissions of the new key on object types, as an object that maps each object type to a permission from 0 to 7, such as `{\"pipelines\": 5}`. Permissions on individual objects are granted with `POST /api-keys/{api_key_id}/permissions`.",
            "additionalProperties": {
              "$ref": "#/components/schemas/AccessLevel"
            },
            "propertyNames": {
              "type": "string",
              "description": "Object type, such as `pipelines`.",
              "enum": [
                "agents",
                "api-keys",
                "contexts",
                "context-messages",
                "documents",
                "embedding-models",
                "embedding-providers",
                "llms",
                "pipelines",
                "taxonomies",
                "text-splitter-providers",
                "text-splitters",
                "permissions",
                "fragments"
              ]
            },
            "nullable": true
          }
        }
      },
      "CreateDocumentRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CreatePipelineDocumentRequest",
            "description": "The fields of a document, as in `CreatePipelineDocumentRequest`."
          },
          {
            "type": "object",
            "required": [
              "pipeline_id"
            ],
            "properties": {
              "pipeline_id": {
                "type": "string",
                "format": "uuid",
                "description": "Identifier of the pipeline that receives the document."
              }
            }
          }
        ],
        "description": "Body of a request that adds a document, or a new version of a document, to the pipeline named in `pipeline_id`. The other fields are those of `CreatePipelineDocumentRequest`."
      },
      "CreateEmbeddingModelRequest": {
        "type": "object",
        "description": "Request body that creates an embedding model.",
        "required": [
          "name",
          "provider",
          "size"
        ],
        "properties": {
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "Free-text description of the embedding model."
          },
          "model": {
            "type": "string",
            "description": "Model name that the provider loads, such as `Qdrant/all-MiniLM-L6-v2-onnx` for `FastEmbedEmbeddings`. Every provider requires a model name."
          },
          "name": {
            "type": "string",
            "description": "Name of the embedding model, unique across the deployment."
          },
          "parameters": {
            "$ref": "#/components/schemas/JsonMap",
            "description": "Provider-specific settings, such as `endpoint` and `api_key` for `OpenAIEmbeddings`. The default is an empty object."
          },
          "provider": {
            "type": "string",
            "description": "Name of the embedding provider, case-sensitive. `GET /providers/embeddings` lists the providers.",
            "enum": [
              "FastEmbedEmbeddings",
              "OpenAIEmbeddings",
              "GPT4AllEmbeddings",
              "HuggingFaceEmbeddings",
              "HuggingFaceEndpointEmbeddings"
            ]
          },
          "size": {
            "type": "integer",
            "format": "int32",
            "description": "Number of dimensions of the vectors that the model produces. `0` stores the number that Foundation4 measures when the model is created. A nonzero value must equal the measured number.",
            "minimum": 0,
            "maximum": 65535
          }
        }
      },
      "CreateLLMRequest": {
        "type": "object",
        "description": "Fields of a new LLM registration.",
        "required": [
          "name",
          "endpoint"
        ],
        "properties": {
          "api_key": {
            "type": [
              "string",
              "null"
            ],
            "description": "API key that Foundation4 sends to the model server as a bearer token. Agent executions and direct queries require a key, even when the model server does not check keys; the OpenAI-compatible endpoint does not. Foundation4 stores the key encrypted and never returns the key."
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "Free text for administrators."
          },
          "endpoint": {
            "type": "string",
            "description": "Base URL of the model server's OpenAI-compatible API, without a trailing slash, such as `http://llm.internal:8000/v1`. Foundation4 appends the path of each API to this URL."
          },
          "model": {
            "type": "string",
            "description": "Model name that Foundation4 sends to the model server. When omitted, Foundation4 sends an empty model name."
          },
          "name": {
            "type": "string",
            "description": "Name of the LLM, unique across the deployment."
          }
        }
      },
      "CreatePipelineDocumentRequest": {
        "type": "object",
        "description": "Body of a request that adds a document, or a new version of a document, to a pipeline.",
        "required": [
          "classification",
          "contents"
        ],
        "properties": {
          "classification": {
            "type": "string",
            "description": "One classification defined in the pipeline. A new version carries the classification of the existing document."
          },
          "contents": {
            "type": "string",
            "description": "Plain text of the document."
          },
          "expire_older_versions": {
            "type": "boolean",
            "description": "Whether the new version expires the previous versions of the document. The default is `true`.",
            "default": true
          },
          "external_identifier": {
            "type": [
              "string",
              "null"
            ],
            "description": "Identifier of the content in the client application's own system. A submission with an external identifier that already exists in the pipeline creates a new version of that document."
          },
          "metadata": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/JsonMap"
              }
            ],
            "description": "Metadata as a JSON object, validated against the pipeline's metadata schema."
          },
          "text_splitter_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "Identifier of a text splitter to use instead of the pipeline's default text splitter."
          }
        }
      },
      "CreatePipelineIndexRequest": {
        "type": "object",
        "description": "Request body that creates a metadata index.",
        "required": [
          "columns"
        ],
        "properties": {
          "columns": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Top-level metadata fields that the index covers. Each field must be declared in the pipeline's metadata schema with a scalar type."
          }
        }
      },
      "CreatePipelineRequest": {
        "type": "object",
        "description": "Request body that creates a pipeline.",
        "required": [
          "name",
          "default_text_splitter_id",
          "classifications"
        ],
        "properties": {
          "classifications": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Classification"
            },
            "description": "Classifications that the pipeline defines. Each item is a classification name, or an inheritance pair `[name, inherited]` in which `name` inherits `inherited`."
          },
          "default_text_splitter_id": {
            "type": "string",
            "format": "uuid",
            "description": "Identifier of the text splitter that processes the documents of the pipeline, unless a document names another text splitter."
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "Free-text description of the pipeline."
          },
          "embedding_model_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "Identifier of the embedding model that converts fragments and queries into vectors. Optional, but required for similarity and maximal marginal relevance search. This setting is fixed at creation."
          },
          "has_full_text_search": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Whether to enable full-text search on the pipeline. The default is false. This setting is fixed at creation and cannot be changed afterwards."
          },
          "name": {
            "type": "string",
            "description": "Name of the pipeline, unique across the deployment."
          },
          "schema": {
            "$ref": "#/components/schemas/Schema",
            "description": "JSON Schema that the metadata of every document must satisfy. The default is an empty schema, which accepts any metadata."
          }
        }
      },
      "CreateTaxonomyEntryRequest": {
        "type": "object",
        "description": "A taxonomy entry, which links a parent field and value to a child field and value.",
        "required": [
          "parent",
          "parent_value",
          "child",
          "child_value"
        ],
        "properties": {
          "child": {
            "type": "string",
            "description": "Name of the child metadata field."
          },
          "child_value": {
            "type": "string",
            "description": "Value of the child metadata field."
          },
          "parent": {
            "type": "string",
            "description": "Name of the parent metadata field."
          },
          "parent_value": {
            "type": "string",
            "description": "Value of the parent metadata field."
          }
        }
      },
      "CreateTaxonomyRequest": {
        "type": "object",
        "description": "Request body that creates a taxonomy.",
        "required": [
          "name"
        ],
        "properties": {
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "Free-text description of the taxonomy."
          },
          "name": {
            "type": "string",
            "description": "Name of the taxonomy, unique across the deployment."
          }
        }
      },
      "CreateTextSplitterRequest": {
        "type": "object",
        "description": "Request body that creates a text splitter. A text splitter has no name.",
        "required": [
          "provider"
        ],
        "properties": {
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "Free-text description of the text splitter."
          },
          "parameters": {
            "$ref": "#/components/schemas/JsonMap",
            "description": "Keyword arguments for the LangChain class of the provider, such as `chunk_size` and `chunk_overlap`. The default is an empty object, which applies the defaults of the class."
          },
          "provider": {
            "type": "string",
            "description": "Name of the text splitter provider, case-sensitive. `GET /providers/text-splitters` lists the providers. The provider `RecursiveJsonSplitter` is listed but cannot be created in the current release.",
            "enum": [
              "RecursiveCharacterTextSplitter",
              "CharacterTextSplitter",
              "CodeTextSplitter",
              "MarkdownHeaderTextSplitter",
              "TokenTextSplitter",
              "NLTKTextSplitter"
            ]
          }
        }
      },
      "Document": {
        "type": "object",
        "required": [
          "id",
          "created_at",
          "updated_at",
          "metadata",
          "classification",
          "pipeline_id",
          "status"
        ],
        "properties": {
          "classification": {
            "type": "string",
            "description": "Classification of the document."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Creation time of the version, in RFC 3339 format. The `version` field holds the same time in microseconds since the Unix epoch."
          },
          "expired_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Time at which the version expired, or `null` for a current version."
          },
          "external_identifier": {
            "type": [
              "string",
              "null"
            ],
            "description": "Identifier of the content in the client application's own system, or `null`. Submissions with the same external identifier in the same pipeline create versions of one document."
          },
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Identifier of the document. All versions of the document share the identifier."
          },
          "message": {
            "type": [
              "string",
              "null"
            ],
            "description": "Additional information about the processing status, or `null`."
          },
          "metadata": {
            "$ref": "#/components/schemas/JsonMap",
            "description": "Metadata of the document, validated against the pipeline's metadata schema."
          },
          "pipeline_id": {
            "type": "string",
            "format": "uuid",
            "description": "Identifier of the pipeline that contains the document."
          },
          "status": {
            "$ref": "#/components/schemas/DocumentStatus",
            "description": "Processing status of the version: `pending`, `success` or `failed`."
          },
          "text_splitter_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "Identifier of the text splitter named in the request, or `null` when the pipeline's default text splitter processes the document."
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Time of the last change to the version, such as a status change, in RFC 3339 format."
          }
        },
        "description": "Fields of a document version. All versions of a document share the document identifier."
      },
      "DocumentResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Document"
          },
          {
            "type": "object",
            "properties": {
              "version": {
                "type": [
                  "integer",
                  "null"
                ],
                "format": "int64",
                "description": "Version of the document: the creation time of the version, in microseconds since the Unix epoch."
              }
            }
          }
        ],
        "description": "One version of a document, with the processing status of the version."
      },
      "DocumentStatus": {
        "type": "string",
        "description": "Processing status of a document version. `pending`: the version is waiting for processing or is being retried. `success`: the fragments are stored and the version is searchable. `failed`: the processing job could not be queued.",
        "enum": [
          "pending",
          "success",
          "failed",
          "canceled"
        ]
      },
      "EmbeddingModel": {
        "type": "object",
        "required": [
          "id",
          "created_at",
          "updated_at",
          "name",
          "provider",
          "model",
          "size",
          "parameters"
        ],
        "properties": {
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Time at which the record was created, in RFC 3339 format."
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "Free-text description of the embedding model."
          },
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Unique identifier of the embedding model."
          },
          "model": {
            "type": "string",
            "description": "Model name that the provider loads, such as `Qdrant/all-MiniLM-L6-v2-onnx`."
          },
          "name": {
            "type": "string",
            "description": "Name of the embedding model, unique across the deployment."
          },
          "parameters": {
            "$ref": "#/components/schemas/JsonMap",
            "description": "Provider-specific settings of the embedding model. Foundation4 returns the parameters as stored, including any API key or token, to every key with read permission on the embedding model."
          },
          "provider": {
            "type": "string",
            "description": "Name of the embedding provider, such as `FastEmbedEmbeddings`.",
            "enum": [
              "FastEmbedEmbeddings",
              "OpenAIEmbeddings",
              "GPT4AllEmbeddings",
              "HuggingFaceEmbeddings",
              "HuggingFaceEndpointEmbeddings"
            ]
          },
          "size": {
            "type": "integer",
            "format": "int32",
            "description": "Number of dimensions of the vectors that the embedding model produces."
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Time of the last change to the record, in RFC 3339 format."
          }
        },
        "description": "An embedding model."
      },
      "EmbeddingModelResponse": {
        "$ref": "#/components/schemas/EmbeddingModel",
        "description": "An embedding model: a configured instance of an embedding provider, with a model name, a number of dimensions and provider parameters."
      },
      "EmbeddingProvider": {
        "type": "object",
        "required": [
          "id",
          "created_at",
          "updated_at",
          "provider"
        ],
        "properties": {
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Time at which the record was created, in RFC 3339 format."
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "Description of the embedding provider."
          },
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Unique identifier of the embedding provider."
          },
          "provider": {
            "type": "string",
            "description": "Name of the embedding provider, used as the `provider` value of an embedding model.",
            "enum": [
              "FastEmbedEmbeddings",
              "OpenAIEmbeddings",
              "GPT4AllEmbeddings",
              "HuggingFaceEmbeddings",
              "HuggingFaceEndpointEmbeddings"
            ]
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Time of the last change to the record, in RFC 3339 format."
          }
        },
        "description": "An embedding provider."
      },
      "EmbeddingProviderResponse": {
        "$ref": "#/components/schemas/EmbeddingProvider",
        "description": "An embedding provider: an engine that Foundation4 supports for converting text into vectors."
      },
      "ExecutePipelineRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/PromptPlaceholder",
            "description": "The search type in `type` and the parameters of the search type in `params`."
          },
          {
            "type": "object",
            "required": [
              "query",
              "classification"
            ],
            "properties": {
              "classification": {
                "$ref": "#/components/schemas/ClassificationSearchParametersVariants",
                "description": "The classifications that the reader holds, as a string, an array of strings or an object. [Search requests](../02-search-requests.md#classification) describes the forms and the matching modes."
              },
              "filters": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/Filter"
                  }
                ],
                "description": "A metadata filter, or `null` for no filter. [Filter operators](../03-filter-operators.md) describes the filter language."
              },
              "query": {
                "type": "string",
                "description": "The search text. Similarity and MMR search convert the text into a vector. Full-text search matches the words of the text."
              },
              "distance_strategy": {
                "type": [
                  "string",
                  "null"
                ],
                "enum": [
                  "cosine",
                  "euclidean-distance",
                  "dot-product",
                  null
                ],
                "default": "cosine",
                "description": "The distance function for similarity and MMR search. Full-text search ignores the field. The API also defines `max-inner-product`, which is not supported and fails. [Search requests](../02-search-requests.md#distance-strategies) describes each strategy."
              }
            }
          }
        ],
        "description": "The body of a search request. [Search requests](../02-search-requests.md) describes every field, the defaults and the errors.",
        "title": "Search request"
      },
      "ExprOrValueExpr": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/LogicalOperator"
          },
          {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/ValueExpr"
            },
            "title": "Field conditions",
            "description": "Maps each top-level metadata field name to one comparison. Every comparison must be satisfied. An empty object applies no restriction.",
            "propertyNames": {
              "type": "string",
              "pattern": "^[a-zA-Z_][a-zA-Z0-9_]*$"
            }
          }
        ],
        "title": "Filter",
        "description": "A metadata filter: either one logical operator, or an object that maps each metadata field name to one comparison. Filter operators describes the language."
      },
      "Filter": {
        "$ref": "#/components/schemas/ExprOrValueExpr"
      },
      "Fragment": {
        "type": "object",
        "required": [
          "id",
          "classification",
          "metadata",
          "document_id",
          "version",
          "order_id"
        ],
        "properties": {
          "classification": {
            "type": "string",
            "description": "Classification of the source document."
          },
          "document_id": {
            "type": "string",
            "format": "uuid",
            "description": "Identifier of the source document."
          },
          "embedding": {
            "type": "array",
            "items": {
              "type": "number",
              "format": "double"
            },
            "description": "Vector of the fragment. Search results and fragment lists do not include the field.",
            "nullable": true
          },
          "expired_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Expiry time of the fragment, or `null` for a current fragment."
          },
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Identifier of the fragment."
          },
          "metadata": {
            "$ref": "#/components/schemas/JsonMap",
            "description": "Metadata of the source document, copied to each fragment."
          },
          "order_id": {
            "type": "integer",
            "format": "int64",
            "description": "Position of the fragment within the document version, starting at 0."
          },
          "page_content": {
            "type": "string",
            "description": "Decrypted text of the fragment. The field is absent when the operation does not return text or the text is empty."
          },
          "score": {
            "type": [
              "number",
              "null"
            ],
            "format": "double",
            "description": "The score of the fragment in a search or retrieval result, or `null` in other responses. For similarity and MMR search, the score is the distance from the query, where lower is closer. For full-text search, the score is the rank, where higher is better."
          },
          "version": {
            "type": "integer",
            "format": "int64",
            "description": "Version of the source document, in microseconds since the Unix epoch."
          }
        },
        "description": "A section of a document version produced by the text splitter."
      },
      "GenericObject": {
        "type": "object",
        "additionalProperties": {},
        "propertyNames": {
          "type": "string"
        },
        "description": "A chat completion request in the OpenAI format, such as `{\"messages\": [{\"role\": \"user\", \"content\": \"...\"}]}`. Foundation4 forwards every field to the model server."
      },
      "HealthResponse": {
        "type": "object",
        "required": [
          "status",
          "database",
          "message_queue",
          "cache",
          "llm_service"
        ],
        "properties": {
          "cache": {
            "type": "string",
            "description": "Status reported for the Redis-compatible cache.",
            "examples": [
              "ok",
              "error"
            ],
            "enum": [
              "ok",
              "error"
            ]
          },
          "database": {
            "type": "string",
            "description": "Status reported for PostgreSQL.",
            "examples": [
              "ok",
              "error"
            ],
            "enum": [
              "ok",
              "error"
            ]
          },
          "llm_service": {
            "type": "string",
            "description": "Status reported for the gRPC service.",
            "examples": [
              "ok",
              "error"
            ],
            "enum": [
              "ok",
              "error"
            ]
          },
          "message_queue": {
            "type": "string",
            "description": "Status reported for NATS JetStream.",
            "examples": [
              "ok",
              "error"
            ],
            "enum": [
              "ok",
              "error"
            ]
          },
          "status": {
            "type": "string",
            "description": "Overall status reported by the API server.",
            "examples": [
              "ok",
              "error"
            ],
            "enum": [
              "ok",
              "error"
            ]
          }
        },
        "description": "Health report of the API server."
      },
      "JsonMap": {
        "type": "object",
        "description": "A JSON object with string keys and values of any JSON type.",
        "additionalProperties": {},
        "propertyNames": {
          "type": "string"
        }
      },
      "JsonMap2": {
        "type": "object",
        "description": "A JSON object whose values are JSON objects.",
        "additionalProperties": {
          "type": "object",
          "additionalProperties": {},
          "propertyNames": {
            "type": "string"
          }
        },
        "propertyNames": {
          "type": "string"
        }
      },
      "LlmResponse": {
        "type": "object",
        "description": "An LLM registration: a connection to a model server with an OpenAI-compatible API. The API key of the registration is never returned.",
        "required": [
          "id",
          "name",
          "endpoint",
          "model"
        ],
        "properties": {
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "Free text for administrators, or `null`."
          },
          "endpoint": {
            "type": "string",
            "description": "Base URL of the model server's OpenAI-compatible API, such as `http://llm.internal:8000/v1`."
          },
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Identifier of the LLM."
          },
          "model": {
            "type": "string",
            "description": "Model name that Foundation4 sends to the model server. An empty string when the registration sets no model name."
          },
          "name": {
            "type": "string",
            "description": "Name of the LLM, unique across the deployment."
          }
        }
      },
      "ObjectTypes": {
        "type": "string",
        "description": "Object type that a permission applies to, written in kebab case.",
        "enum": [
          "agents",
          "api-keys",
          "contexts",
          "context-messages",
          "documents",
          "embedding-models",
          "embedding-providers",
          "llms",
          "pipelines",
          "taxonomies",
          "text-splitter-providers",
          "text-splitters",
          "permissions",
          "fragments"
        ]
      },
      "Paginated_AgentResponse": {
        "type": "object",
        "required": [
          "data",
          "page_info",
          "query_info"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Agent"
            },
            "description": "Agents on the page."
          },
          "page_info": {
            "$ref": "#/components/schemas/PageInfo",
            "description": "Description of the page: the cursors `before` and `after`, `has_next`, `has_prev`, `order_by` and, with `count=true`, `count`."
          },
          "query_info": {
            "$ref": "#/components/schemas/QueryInfo",
            "description": "Filters that the server recognized in the query string. A filter missing from `query_info` was not applied."
          }
        },
        "description": "One page of agents in the list envelope."
      },
      "Paginated_ApiKeyResponse": {
        "type": "object",
        "required": [
          "data",
          "page_info",
          "query_info"
        ],
        "properties": {
          "data": {
            "type": "array",
            "description": "API keys on the page, without secrets.",
            "items": {
              "$ref": "#/components/schemas/ApiKeyResponse"
            }
          },
          "page_info": {
            "$ref": "#/components/schemas/PageInfo",
            "description": "Pagination state of the page: the cursors or the offset and limit, `has_next`, `has_prev`, `order_by` and, when requested, the total `count`."
          },
          "query_info": {
            "$ref": "#/components/schemas/QueryInfo",
            "description": "Filters that the server applied to the list, as an object of parameter names and values."
          }
        },
        "description": "A page of API keys in the pagination envelope."
      },
      "Paginated_DocumentResponse": {
        "type": "object",
        "required": [
          "data",
          "page_info",
          "query_info"
        ],
        "properties": {
          "data": {
            "type": "array",
            "description": "Document versions on the page.",
            "items": {
              "$ref": "#/components/schemas/DocumentResponse"
            }
          },
          "page_info": {
            "$ref": "#/components/schemas/PageInfo",
            "description": "Information about the page: `has_next`, `has_prev` and `order_by`, the cursors `before` and `after` in cursor mode, and `count` when the request sets `count=true`."
          },
          "query_info": {
            "$ref": "#/components/schemas/QueryInfo",
            "description": "Filters that the server recognized in the request. A filter missing from `query_info` was not applied."
          }
        },
        "description": "One page of document versions in the list envelope."
      },
      "Paginated_EmbeddingModelResponse": {
        "type": "object",
        "required": [
          "data",
          "page_info",
          "query_info"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmbeddingModel"
            },
            "description": "The embedding models on the page."
          },
          "page_info": {
            "$ref": "#/components/schemas/PageInfo",
            "description": "Position of the page: `limit` and `offset` in offset mode, or the cursors `after` and `before` with `has_next` and `has_prev` in cursor mode. `count` holds the total number of matching objects when the request sets `count=true`, and `order_by` holds the sort order that the request set, or `null`."
          },
          "query_info": {
            "$ref": "#/components/schemas/QueryInfo",
            "description": "The filter parameters that the server read from the request."
          }
        },
        "description": "A page of embedding models, in the pagination envelope described in API conventions."
      },
      "Paginated_EmbeddingProviderResponse": {
        "type": "object",
        "required": [
          "data",
          "page_info",
          "query_info"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmbeddingProvider"
            },
            "description": "The embedding providers on the page."
          },
          "page_info": {
            "$ref": "#/components/schemas/PageInfo",
            "description": "Position of the page: `limit` and `offset` in offset mode, or the cursors `after` and `before` with `has_next` and `has_prev` in cursor mode. `count` holds the total number of matching objects when the request sets `count=true`, and `order_by` holds the sort order that the request set, or `null`."
          },
          "query_info": {
            "$ref": "#/components/schemas/QueryInfo",
            "description": "The filter parameters that the server read from the request."
          }
        },
        "description": "A page of embedding providers, in the pagination envelope described in API conventions."
      },
      "Paginated_Fragment": {
        "type": "object",
        "required": [
          "data",
          "page_info",
          "query_info"
        ],
        "properties": {
          "data": {
            "type": "array",
            "description": "Fragments on the page, in the order of the fragments within the document version.",
            "items": {
              "$ref": "#/components/schemas/Fragment"
            }
          },
          "page_info": {
            "$ref": "#/components/schemas/PageInfo",
            "description": "Information about the page: `has_next`, `has_prev` and `order_by`, the cursors `before` and `after` in cursor mode, and `count` when the request sets `count=true`."
          },
          "query_info": {
            "$ref": "#/components/schemas/QueryInfo",
            "description": "Always an empty object for this list, which accepts no filters."
          }
        },
        "description": "One page of fragments in the list envelope."
      },
      "Paginated_LlmResponse": {
        "type": "object",
        "required": [
          "data",
          "page_info",
          "query_info"
        ],
        "properties": {
          "data": {
            "type": "array",
            "description": "LLM registrations on the page.",
            "items": {
              "$ref": "#/components/schemas/LlmResponse"
            }
          },
          "page_info": {
            "$ref": "#/components/schemas/PageInfo",
            "description": "Description of the page: the cursors `before` and `after`, `has_next`, `has_prev`, `order_by` and, with `count=true`, `count`."
          },
          "query_info": {
            "$ref": "#/components/schemas/QueryInfo",
            "description": "Filters that the server recognized in the query string. A filter missing from `query_info` was not applied."
          }
        },
        "description": "One page of LLM registrations in the list envelope."
      },
      "Paginated_PipelineResponse": {
        "type": "object",
        "required": [
          "data",
          "page_info",
          "query_info"
        ],
        "properties": {
          "data": {
            "type": "array",
            "description": "The objects on the page.",
            "items": {
              "$ref": "#/components/schemas/PipelineResponse"
            }
          },
          "page_info": {
            "$ref": "#/components/schemas/PageInfo"
          },
          "query_info": {
            "$ref": "#/components/schemas/QueryInfo"
          }
        }
      },
      "Paginated_TaxonomyEntry": {
        "type": "object",
        "required": [
          "data",
          "page_info",
          "query_info"
        ],
        "properties": {
          "data": {
            "type": "array",
            "description": "The objects on the page.",
            "items": {
              "$ref": "#/components/schemas/TaxonomyEntry"
            }
          },
          "page_info": {
            "$ref": "#/components/schemas/PageInfo"
          },
          "query_info": {
            "$ref": "#/components/schemas/QueryInfo"
          }
        }
      },
      "Paginated_TaxonomyResponse": {
        "type": "object",
        "required": [
          "data",
          "page_info",
          "query_info"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Taxonomy"
            },
            "description": "The objects on the page."
          },
          "page_info": {
            "$ref": "#/components/schemas/PageInfo"
          },
          "query_info": {
            "$ref": "#/components/schemas/QueryInfo"
          }
        }
      },
      "Paginated_TextSplitterProviderResponse": {
        "type": "object",
        "required": [
          "data",
          "page_info",
          "query_info"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TextSplitterProvider"
            },
            "description": "The text splitter providers on the page."
          },
          "page_info": {
            "$ref": "#/components/schemas/PageInfo",
            "description": "Position of the page: `limit` and `offset` in offset mode, or the cursors `after` and `before` with `has_next` and `has_prev` in cursor mode. `count` holds the total number of matching objects when the request sets `count=true`, and `order_by` holds the sort order that the request set, or `null`."
          },
          "query_info": {
            "$ref": "#/components/schemas/QueryInfo",
            "description": "The filter parameters that the server read from the request."
          }
        },
        "description": "A page of text splitter providers, in the pagination envelope described in API conventions."
      },
      "Paginated_TextSplitterResponse": {
        "type": "object",
        "required": [
          "data",
          "page_info",
          "query_info"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TextSplitter"
            },
            "description": "The text splitters on the page."
          },
          "page_info": {
            "$ref": "#/components/schemas/PageInfo",
            "description": "Position of the page: `limit` and `offset` in offset mode, or the cursors `after` and `before` with `has_next` and `has_prev` in cursor mode. `count` holds the total number of matching objects when the request sets `count=true`, and `order_by` holds the sort order that the request set, or `null`."
          },
          "query_info": {
            "$ref": "#/components/schemas/QueryInfo",
            "description": "The filter parameters that the server read from the request."
          }
        },
        "description": "A page of text splitters, in the pagination envelope described in API conventions."
      },
      "Params_PlaceholderParameterHistory": {
        "type": "object",
        "properties": {
          "params": {
            "type": "object",
            "properties": {
              "k": {
                "type": "integer",
                "format": "int32",
                "minimum": 0
              }
            }
          }
        },
        "description": "Reserved for conversation history."
      },
      "Params_PlaceholderParameterHybrid": {
        "type": "object",
        "properties": {
          "params": {
            "type": "object",
            "properties": {
              "embedding": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "uuid"
              },
              "k": {
                "type": "integer",
                "format": "int32",
                "minimum": 0
              }
            }
          }
        },
        "description": "Reserved for hybrid search."
      },
      "Params_PlaceholderParameterMmr": {
        "type": "object",
        "properties": {
          "params": {
            "type": "object",
            "properties": {
              "embedding": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "uuid",
                "description": "The identifier of the embedding model to search with. The model must belong to the pipeline. The default is the embedding model of the pipeline."
              },
              "fetch_k": {
                "type": "integer",
                "format": "int32",
                "minimum": 0,
                "maximum": 65535,
                "description": "The number of closest fragments from which MMR selection chooses `k` fragments, from 1 to 65535. Set to at least `k`."
              },
              "k": {
                "type": "integer",
                "format": "int32",
                "minimum": 0,
                "maximum": 65535,
                "description": "The number of fragments that MMR selection returns, from 1 to 65535."
              },
              "lambda_mult": {
                "type": [
                  "number",
                  "null"
                ],
                "format": "double",
                "description": "The balance between relevance and diversity, from 0 to 1. A value of 1 selects by relevance alone, and a value of 0 maximizes diversity. Without `params`, the value is 0.5."
              },
              "threshold": {
                "type": [
                  "number",
                  "null"
                ],
                "format": "double",
                "description": "The maximum distance from the query. Fragments at a greater distance are excluded before MMR selection."
              }
            },
            "description": "The parameters of MMR search. Without `params`, `k` is 5, `fetch_k` is 10 and `lambda_mult` is 0.5. A `params` object that omits `k` or `fetch_k` returns no fragments."
          }
        }
      },
      "Params_PlaceholderParameterSearch": {
        "type": "object",
        "properties": {
          "params": {
            "type": "object",
            "properties": {
              "k": {
                "type": "integer",
                "format": "int32",
                "minimum": 0,
                "maximum": 65535,
                "description": "The number of fragments to return, from 1 to 65535."
              },
              "threshold": {
                "type": [
                  "number",
                  "null"
                ],
                "format": "double",
                "description": "The minimum rank. Fragments with a lower rank are excluded before `k` applies."
              }
            },
            "description": "The parameters of full-text search. Without `params`, `k` is 5. A `params` object that omits `k` returns no fragments."
          }
        }
      },
      "Params_PlaceholderParameterSimilarity": {
        "type": "object",
        "properties": {
          "params": {
            "type": "object",
            "properties": {
              "embedding": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "uuid",
                "description": "The identifier of the embedding model to search with. The model must belong to the pipeline. The default is the embedding model of the pipeline."
              },
              "k": {
                "type": "integer",
                "format": "int32",
                "minimum": 0,
                "maximum": 65535,
                "description": "The number of fragments to return, from 1 to 65535."
              },
              "threshold": {
                "type": [
                  "number",
                  "null"
                ],
                "format": "double",
                "description": "The maximum distance from the query. Fragments at a greater distance are excluded before `k` applies."
              }
            },
            "description": "The parameters of similarity search. Without `params`, `k` is 5. A `params` object that omits `k` returns no fragments."
          }
        }
      },
      "PermissionEntry": {
        "type": "object",
        "description": "Permission of an API key on an object type, with the classification allow-list.",
        "required": [
          "access_level",
          "classifications"
        ],
        "properties": {
          "access_level": {
            "$ref": "#/components/schemas/AccessLevel",
            "description": "Permission as the sum of the permission bits: read 4, write 2 and execute 1."
          },
          "classifications": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Classification allow-list of the permission. The list applies to the `pipelines` object type and is empty for other object types. The value `*` permits every classification.",
            "uniqueItems": true
          }
        }
      },
      "Pipeline": {
        "type": "object",
        "required": [
          "id",
          "created_at",
          "updated_at",
          "name",
          "default_text_splitter_id",
          "schema",
          "has_full_text_search"
        ],
        "properties": {
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Creation time, in RFC 3339 format."
          },
          "default_text_splitter_id": {
            "type": "string",
            "format": "uuid",
            "description": "Identifier of the text splitter that processes the documents of the pipeline, unless a document names another text splitter."
          },
          "default_vector_embedding_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "Identifier of the pipeline's default vector embedding, or null when the pipeline has no embedding model. This value is a key into the `embedding_models` map of the pipeline response, not an embedding model identifier."
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "Free-text description of the pipeline."
          },
          "has_full_text_search": {
            "type": "boolean",
            "description": "Whether full-text search is enabled on the pipeline. The setting is fixed at creation."
          },
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Unique identifier of the pipeline."
          },
          "name": {
            "type": "string",
            "description": "Name of the pipeline, unique across the deployment."
          },
          "schema": {
            "$ref": "#/components/schemas/Schema",
            "description": "JSON Schema that the metadata of every document must satisfy."
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Time of the last change, in RFC 3339 format."
          }
        }
      },
      "PipelineClassificationsResponse": {
        "type": "object",
        "required": [
          "classifications",
          "hierarchy"
        ],
        "properties": {
          "classifications": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Names of the classifications that the pipeline defines."
          },
          "hierarchy": {
            "type": "array",
            "items": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "Inheritance relationships as a list of pairs. Each pair is `[classification, inherited classification]`, meaning the first classification inherits the second."
          }
        }
      },
      "PipelineIndexResponse": {
        "type": "object",
        "description": "A metadata index of a pipeline.",
        "required": [
          "id",
          "columns"
        ],
        "properties": {
          "columns": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Metadata fields that the index covers."
          },
          "id": {
            "type": "string",
            "description": "Identifier of the metadata index."
          }
        }
      },
      "PipelineResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Pipeline"
          },
          {
            "type": "object",
            "required": [
              "embedding_models"
            ],
            "properties": {
              "embedding_models": {
                "type": "object",
                "additionalProperties": {
                  "$ref": "#/components/schemas/EmbeddingModel"
                },
                "propertyNames": {
                  "type": "string",
                  "format": "uuid"
                },
                "description": "The embedding models the pipeline uses, keyed by vector embedding identifier. The `default_vector_embedding_id` of the pipeline selects the default entry."
              }
            }
          }
        ],
        "description": "A pipeline, with the embedding models that the pipeline uses."
      },
      "Placeholder": {
        "allOf": [
          {
            "$ref": "#/components/schemas/PromptPlaceholder"
          },
          {
            "type": "object",
            "required": [
              "name"
            ],
            "properties": {
              "name": {
                "type": "string",
                "description": "Name of the placeholder, as written in braces in the templates."
              },
              "target": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "For a retrieval placeholder (`similarity` or `mmr`), the name of the `query` placeholder whose value is the search text. A `query` placeholder has no target."
              }
            }
          }
        ],
        "description": "A named value that Foundation4 inserts into the templates of an agent at execution time. `type` selects the kind of value, and `params` holds the parameters of a retrieval placeholder."
      },
      "Prompt": {
        "type": "object",
        "required": [
          "role",
          "template"
        ],
        "properties": {
          "include": {
            "type": "boolean",
            "description": "Whether Foundation4 sends the message to the LLM. A message with `false` stays in the stored agent but is never sent. The default is `true`."
          },
          "role": {
            "$ref": "#/components/schemas/PromptType",
            "description": "Role of the message: `system` for instructions to the LLM, `user` for the request that the LLM answers, `assistant` for an example answer."
          },
          "template": {
            "type": "string",
            "description": "Text of the message. A placeholder is written as the placeholder name in braces, such as `{question}`. Placeholder names consist of ASCII letters and digits and start with a letter."
          }
        },
        "description": "One message of a prompt template."
      },
      "PromptPlaceholder": {
        "oneOf": [
          {
            "type": "object",
            "description": "A placeholder that receives a value from each agent execution request, such as the question of the end user. A search request with this type returns HTTP 400 (`Invalid search type or parameters`).",
            "required": [
              "type"
            ],
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "query"
                ]
              }
            },
            "title": "query"
          },
          {
            "allOf": [
              {
                "$ref": "#/components/schemas/Params_PlaceholderParameterSimilarity",
                "description": "The parameters of similarity search."
              },
              {
                "type": "object",
                "required": [
                  "type"
                ],
                "properties": {
                  "type": {
                    "type": "string",
                    "enum": [
                      "similarity"
                    ]
                  }
                }
              }
            ],
            "description": "Similarity search: the `k` fragments whose vectors are closest to the query vector.",
            "title": "similarity"
          },
          {
            "allOf": [
              {
                "$ref": "#/components/schemas/Params_PlaceholderParameterSearch",
                "description": "The parameters of full-text search."
              },
              {
                "type": "object",
                "required": [
                  "type"
                ],
                "properties": {
                  "type": {
                    "type": "string",
                    "enum": [
                      "search"
                    ]
                  }
                }
              }
            ],
            "description": "Full-text search: the `k` fragments that contain every word of the query, ranked by relevance. The pipeline must have full-text search enabled.",
            "title": "search"
          },
          {
            "allOf": [
              {
                "$ref": "#/components/schemas/Params_PlaceholderParameterHybrid",
                "description": "Reserved."
              },
              {
                "type": "object",
                "required": [
                  "type"
                ],
                "properties": {
                  "type": {
                    "type": "string",
                    "enum": [
                      "hybrid"
                    ]
                  }
                }
              }
            ],
            "description": "Reserved for hybrid search. A request with this type returns HTTP 501 in the current release.",
            "title": "hybrid"
          },
          {
            "allOf": [
              {
                "$ref": "#/components/schemas/Params_PlaceholderParameterMmr",
                "description": "The parameters of MMR search."
              },
              {
                "type": "object",
                "required": [
                  "type"
                ],
                "properties": {
                  "type": {
                    "type": "string",
                    "enum": [
                      "mmr"
                    ]
                  }
                }
              }
            ],
            "description": "Maximal marginal relevance (MMR) search: `k` fragments selected from the `fetch_k` closest fragments for relevance and diversity.",
            "title": "mmr"
          },
          {
            "allOf": [
              {
                "$ref": "#/components/schemas/Params_PlaceholderParameterHistory",
                "description": "Reserved."
              },
              {
                "type": "object",
                "required": [
                  "type"
                ],
                "properties": {
                  "type": {
                    "type": "string",
                    "enum": [
                      "history"
                    ]
                  }
                }
              }
            ],
            "description": "Reserved for conversation history. A request with this type returns HTTP 501 in the current release.",
            "title": "history"
          }
        ],
        "description": "The search type, in `type`, with the parameters of the type in `params`. In an agent, the same object defines a placeholder. A search request accepts `similarity`, `mmr` and `search`.",
        "title": "Search type"
      },
      "PromptType": {
        "type": "string",
        "enum": [
          "user",
          "system",
          "assistant"
        ],
        "description": "Role of a prompt message."
      },
      "QueryEmbeddingRequest": {
        "type": "object",
        "required": [
          "query"
        ],
        "properties": {
          "query": {
            "type": "string",
            "description": "Text to convert into a vector."
          }
        },
        "description": "Request body that converts one text into a vector."
      },
      "QueryLlmRequest": {
        "type": "object",
        "description": "Body of a direct LLM query.",
        "required": [
          "query"
        ],
        "properties": {
          "query": {
            "type": "string",
            "description": "Text that Foundation4 sends to the LLM as a single user message."
          },
          "stream": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/StreamTypeOption"
              }
            ],
            "description": "Response format: `true`, `\"stream\"`, `null` or an omitted field for newline-delimited JSON (NDJSON), `\"sse\"` for server-sent events, `false` for the complete answer as plain text."
          },
          "temperature": {
            "type": [
              "number",
              "null"
            ],
            "format": "double",
            "description": "Sampling temperature that Foundation4 sends to the model server. When omitted, the model server's default applies."
          }
        }
      },
      "Schema": {
        "description": "A JSON Schema that validates the metadata of documents. [Metadata, filters and taxonomies](../../concepts/05-metadata-filters-taxonomies.md) describes the supported keywords."
      },
      "SetApiKeyPermissionRequest": {
        "type": "object",
        "description": "Request body that sets permission entries of an API key.",
        "required": [
          "permissions"
        ],
        "properties": {
          "classifications": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Classification allow-list for every `pipelines` entry in the request. The value `*` permits every classification of the pipeline. The list does not apply to other object types.",
            "uniqueItems": true,
            "nullable": true
          },
          "permissions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApiKeyPermissionRequest"
            },
            "description": "Permission entries to add, change or remove."
          }
        }
      },
      "StatisticsResponse": {
        "type": "object",
        "required": [
          "documents_added",
          "documents_processed",
          "documents_processed_latency",
          "documents_failed",
          "agent_executions",
          "agent_execution_latency",
          "agent_execution_latencies",
          "document_queue",
          "document_queue_processed_latencies"
        ],
        "properties": {
          "agent_execution_latencies": {
            "type": "array",
            "items": {
              "type": "array",
              "items": false,
              "prefixItems": [
                {
                  "type": "string"
                },
                {
                  "type": "number",
                  "format": "double"
                }
              ]
            },
            "description": "Distribution of agent execution durations during the interval. Each item is a pair of an upper bound in seconds, as a string, and the number of executions that took at most that long. The bounds are in ascending order, and the last bound is `+Inf`."
          },
          "agent_execution_latency": {
            "type": "number",
            "format": "double",
            "description": "Average duration of an agent execution during the interval, in seconds."
          },
          "agent_executions": {
            "type": "number",
            "format": "double",
            "description": "Number of agent executions during the interval."
          },
          "document_queue": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Number of documents in the processing queue when the request runs, including documents that a worker is processing."
          },
          "document_queue_processed_latencies": {
            "type": "array",
            "items": {
              "type": "array",
              "items": false,
              "prefixItems": [
                {
                  "type": "string"
                },
                {
                  "type": "number",
                  "format": "double"
                }
              ]
            },
            "description": "Distribution of batch processing times during the interval. Each item is a pair of an upper bound in seconds, as a string, and the number of batches that took at most that long. The bounds are in ascending order, and the last bound is `+Inf`."
          },
          "documents_added": {
            "type": "number",
            "format": "double",
            "description": "Number of documents added to the processing queue during the interval."
          },
          "documents_failed": {
            "type": "number",
            "format": "double",
            "description": "Number of documents whose processing failed during the interval."
          },
          "documents_processed": {
            "type": "number",
            "format": "double",
            "description": "Number of documents that the workers processed during the interval."
          },
          "documents_processed_latency": {
            "type": "number",
            "format": "double",
            "description": "Average time, in seconds, that a worker took to process one batch of documents during the interval."
          }
        },
        "description": "Document processing and agent execution statistics for the requested interval."
      },
      "StreamType": {
        "type": "string",
        "description": "Streamed response format: `stream` for newline-delimited JSON (NDJSON), `sse` for server-sent events.",
        "enum": [
          "sse",
          "stream"
        ]
      },
      "StreamTypeOption": {
        "oneOf": [
          {
            "type": "boolean"
          },
          {
            "$ref": "#/components/schemas/StreamType"
          }
        ],
        "description": "Response format of an answer, as a boolean or a format name. `true` and `\"stream\"` select newline-delimited JSON (NDJSON), `\"sse\"` selects server-sent events and `false` selects plain text."
      },
      "Taxonomy": {
        "type": "object",
        "required": [
          "id",
          "created_at",
          "updated_at",
          "name"
        ],
        "properties": {
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Creation time, in RFC 3339 format."
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "Free-text description of the taxonomy."
          },
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Unique identifier of the taxonomy."
          },
          "name": {
            "type": "string",
            "description": "Name of the taxonomy, unique across the deployment."
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Time of the last change, in RFC 3339 format."
          }
        }
      },
      "TaxonomyEntry": {
        "type": "object",
        "required": [
          "id",
          "created_at",
          "updated_at",
          "taxonomy_id",
          "parent",
          "parent_value",
          "child",
          "child_value"
        ],
        "properties": {
          "child": {
            "type": "string",
            "description": "Name of the child metadata field."
          },
          "child_value": {
            "type": "string",
            "description": "Value of the child metadata field."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Creation time, in RFC 3339 format."
          },
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Unique identifier of the taxonomy entry."
          },
          "parent": {
            "type": "string",
            "description": "Name of the parent metadata field."
          },
          "parent_value": {
            "type": "string",
            "description": "Value of the parent metadata field."
          },
          "taxonomy_id": {
            "type": "string",
            "format": "uuid",
            "description": "Identifier of the taxonomy that contains the entry."
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Time of the last change, in RFC 3339 format."
          }
        }
      },
      "TaxonomyResponse": {
        "$ref": "#/components/schemas/Taxonomy",
        "description": "A taxonomy."
      },
      "TextSplitter": {
        "type": "object",
        "required": [
          "id",
          "created_at",
          "updated_at",
          "provider",
          "parameters"
        ],
        "properties": {
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Time at which the record was created, in RFC 3339 format."
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "Description of the text splitter."
          },
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Identifier of the text splitter."
          },
          "parameters": {
            "$ref": "#/components/schemas/JsonMap",
            "description": "Keyword arguments that Foundation4 passes to the LangChain class of the provider, such as `chunk_size` and `chunk_overlap`."
          },
          "provider": {
            "type": "string",
            "description": "Name of the text splitter provider, such as `RecursiveCharacterTextSplitter`.",
            "enum": [
              "RecursiveCharacterTextSplitter",
              "CharacterTextSplitter",
              "CodeTextSplitter",
              "MarkdownHeaderTextSplitter",
              "RecursiveJsonSplitter",
              "TokenTextSplitter",
              "NLTKTextSplitter"
            ]
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Time of the last change to the record, in RFC 3339 format."
          }
        },
        "description": "A text splitter."
      },
      "TextSplitterProvider": {
        "type": "object",
        "required": [
          "id",
          "created_at",
          "updated_at",
          "provider"
        ],
        "properties": {
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Time at which the record was created, in RFC 3339 format."
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "Description of the text splitter provider."
          },
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Unique identifier of the text splitter provider."
          },
          "provider": {
            "type": "string",
            "description": "Name of the text splitter provider, used as the `provider` value of a text splitter.",
            "enum": [
              "RecursiveCharacterTextSplitter",
              "CharacterTextSplitter",
              "CodeTextSplitter",
              "MarkdownHeaderTextSplitter",
              "RecursiveJsonSplitter",
              "TokenTextSplitter",
              "NLTKTextSplitter"
            ]
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Time of the last change to the record, in RFC 3339 format."
          }
        },
        "description": "A text splitter provider."
      },
      "TextSplitterProviderResponse": {
        "$ref": "#/components/schemas/TextSplitterProvider",
        "description": "A text splitter provider: a splitting method that Foundation4 supports."
      },
      "TextSplitterResponse": {
        "$ref": "#/components/schemas/TextSplitter",
        "description": "A text splitter: a configured instance of a text splitter provider, with parameters."
      },
      "UpdateAgentRequest": {
        "type": "object",
        "description": "Fields to change in an agent. Omitted fields keep the stored values.",
        "properties": {
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "New description. `null` clears the description.",
            "default": null
          },
          "metadata": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/JsonMap2"
              }
            ],
            "default": null,
            "description": "New metadata, which replaces the stored metadata whole."
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "description": "New name of the agent, unique across the deployment. `null` leaves the name unchanged.",
            "default": null
          },
          "placeholders": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Placeholder"
            },
            "description": "New placeholders, which replace the stored placeholders whole.",
            "default": null,
            "nullable": true
          },
          "prompt": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Prompt"
            },
            "description": "New prompt template, which replaces the stored messages whole.",
            "default": null,
            "nullable": true
          }
        }
      },
      "UpdateApiKeyRequest": {
        "type": "object",
        "description": "Request body that changes an API key. Fields that the request omits keep their values. The secret cannot be changed.",
        "properties": {
          "active": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "`false` deactivates the key and `true` reactivates the key.",
            "default": null
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "New description of the API key. `null` removes the description.",
            "default": null
          },
          "expiration": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "New expiration time in RFC 3339 format. `null` removes the expiration time, so the key does not expire.",
            "default": null
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "description": "New name of the API key, unique across the deployment.",
            "default": null
          }
        }
      },
      "UpdateEmbeddingModelRequest": {
        "type": "object",
        "properties": {
          "description": {
            "type": [
              "string",
              "null"
            ],
            "default": null,
            "description": "New description of the embedding model. `null` removes the description."
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "default": null,
            "description": "New name of the embedding model, unique across the deployment. `null` keeps the current name."
          }
        },
        "description": "Request body that changes the name or the description of an embedding model. Fields that the request omits keep their values."
      },
      "UpdateLLMRequest": {
        "type": "object",
        "description": "Fields to change in an LLM registration. Omitted fields keep the stored values.",
        "properties": {
          "api_key": {
            "type": [
              "string",
              "null"
            ],
            "description": "New API key, which replaces the stored key. `null` removes the key.",
            "default": null
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "New description. `null` clears the description.",
            "default": null
          },
          "endpoint": {
            "type": [
              "string",
              "null"
            ],
            "description": "New base URL of the model server's OpenAI-compatible API, without a trailing slash. `null` leaves the endpoint unchanged.",
            "default": null
          },
          "model": {
            "type": [
              "string",
              "null"
            ],
            "description": "New model name. `null` leaves the model name unchanged.",
            "default": null
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "description": "New name of the LLM, unique across the deployment. `null` leaves the name unchanged.",
            "default": null
          }
        }
      },
      "UpdatePipelineClassificationsRequest": {
        "type": "object",
        "properties": {
          "add": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Classification"
            },
            "description": "Classifications and inheritance pairs to add, in the forms of the create request. Additions are processed before removals."
          },
          "remove": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Classification"
            },
            "description": "Classifications and inheritance pairs to remove. Removing a classification permanently deletes every document that carries the classification."
          }
        }
      },
      "UpdatePipelineRequest": {
        "type": "object",
        "description": "Fields to change in a pipeline. Omitted fields keep the stored values.",
        "properties": {
          "default_text_splitter_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "Identifier of the new default text splitter. `null` keeps the stored value.",
            "default": null
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "New description. `null` clears the description.",
            "default": null
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "description": "New name of the pipeline, unique across the deployment. `null` keeps the stored value.",
            "default": null
          },
          "schema": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/Schema",
                "description": "New JSON Schema for the metadata of documents. `null` keeps the stored schema."
              }
            ],
            "default": null
          }
        }
      },
      "UpdateTaxonomyRequest": {
        "type": "object",
        "description": "Fields to change in a taxonomy. Omitted fields keep the stored values.",
        "properties": {
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "New description of the taxonomy.",
            "default": null
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "description": "New name of the taxonomy, unique across the deployment.",
            "default": null
          }
        }
      },
      "UpdateTextSplitterRequest": {
        "type": "object",
        "properties": {
          "description": {
            "type": [
              "string",
              "null"
            ],
            "default": null,
            "description": "New description of the text splitter. `null` removes the description; an omitted field keeps the current description."
          }
        },
        "description": "Request body that changes the description of a text splitter."
      },
      "LogicalOperator": {
        "title": "Logical operator",
        "description": "An object with exactly one key, `$and`, `$or` or `$not`, that combines other filters.",
        "oneOf": [
          {
            "title": "$and",
            "type": "object",
            "required": [
              "$and"
            ],
            "additionalProperties": false,
            "properties": {
              "$and": {
                "type": "array",
                "description": "Filters that must all be satisfied. An empty array is always satisfied.",
                "items": {
                  "$ref": "#/components/schemas/ExprOrValueExpr"
                }
              }
            }
          },
          {
            "title": "$or",
            "type": "object",
            "required": [
              "$or"
            ],
            "additionalProperties": false,
            "properties": {
              "$or": {
                "type": "array",
                "description": "Filters of which at least one must be satisfied. An empty array is never satisfied.",
                "items": {
                  "$ref": "#/components/schemas/ExprOrValueExpr"
                }
              }
            }
          },
          {
            "title": "$not",
            "type": "object",
            "required": [
              "$not"
            ],
            "additionalProperties": false,
            "properties": {
              "$not": {
                "$ref": "#/components/schemas/ExprOrValueExpr"
              }
            }
          }
        ]
      },
      "ValueExpr": {
        "title": "Comparison",
        "description": "A comparison on one metadata field, as an object with exactly one operator key. The value must have the type that the metadata schema of the pipeline declares for the field.",
        "type": "object",
        "minProperties": 1,
        "maxProperties": 1,
        "additionalProperties": false,
        "properties": {
          "$eq": {
            "$ref": "#/components/schemas/FilterValue"
          },
          "$neq": {
            "$ref": "#/components/schemas/FilterValue"
          },
          "$gt": {
            "$ref": "#/components/schemas/FilterValue"
          },
          "$ge": {
            "$ref": "#/components/schemas/FilterValue"
          },
          "$lt": {
            "$ref": "#/components/schemas/FilterValue"
          },
          "$le": {
            "$ref": "#/components/schemas/FilterValue"
          },
          "$like": {
            "type": "string",
            "description": "A SQL `LIKE` pattern, case-sensitive. `%` matches any sequence of characters and `_` matches one character."
          },
          "$ilike": {
            "type": "string",
            "description": "A SQL `LIKE` pattern, case-insensitive."
          },
          "$in": {
            "$ref": "#/components/schemas/FilterArrayValue"
          },
          "$not-in": {
            "$ref": "#/components/schemas/FilterArrayValue"
          },
          "$teq": {
            "type": "array",
            "description": "The value and the identifier of a taxonomy. Matches the value and every value beneath the value in the taxonomy.",
            "minItems": 2,
            "maxItems": 2,
            "items": {
              "type": "string"
            }
          }
        }
      },
      "FilterValue": {
        "title": "Value",
        "description": "A string, number or boolean. `null`, arrays and objects are not valid.",
        "oneOf": [
          {
            "type": "string"
          },
          {
            "type": "number"
          },
          {
            "type": "boolean"
          }
        ]
      },
      "FilterArrayValue": {
        "title": "Values",
        "description": "A non-empty array of values of one type.",
        "oneOf": [
          {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          {
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          {
            "type": "array",
            "items": {
              "type": "boolean"
            }
          }
        ]
      },
      "PageInfo": {
        "title": "Page information",
        "type": "object",
        "description": "Describes the page. Fields that do not apply to the pagination mode of the request are omitted.",
        "properties": {
          "has_next": {
            "type": "boolean",
            "description": "`true` when more objects follow this page."
          },
          "has_prev": {
            "type": "boolean",
            "description": "`true` when objects precede this page. A request with `after` on a non-empty list always reports `true`."
          },
          "after": {
            "type": "string",
            "description": "Cursor mode: the cursor of the last object on the page. The next page is requested with `after` set to this value."
          },
          "before": {
            "type": "string",
            "description": "Cursor mode: the cursor of the first object on the page. The previous page is requested with `last` and `before` set to this value."
          },
          "limit": {
            "type": "integer",
            "description": "Offset mode: the page size of the request."
          },
          "offset": {
            "type": "integer",
            "description": "Offset mode: the offset of the request."
          },
          "count": {
            "type": "integer",
            "description": "The total number of matching objects. Present only when the request sets `count=true`."
          },
          "order_by": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The sort fields of the page, with a `-` prefix for descending order.",
            "nullable": true
          }
        },
        "nullable": true
      },
      "QueryInfo": {
        "title": "Query information",
        "type": "object",
        "additionalProperties": true,
        "description": "The list filters that the server recognized, repeated from the request. A filter that is missing from `query_info` was not applied."
      },
      "ApiKeyWithSecret": {
        "title": "API key with secret",
        "type": "object",
        "description": "An API key with the key's secret. Foundation4 returns this form only in the response that creates the key.",
        "required": [
          "id",
          "created_at",
          "updated_at",
          "name",
          "description",
          "secret",
          "active",
          "expiration"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Identifier of the API key. Requests send the identifier in the `x-api-key` header."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Time the key was created, in RFC 3339 format."
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Time the key was last changed, in RFC 3339 format."
          },
          "name": {
            "type": "string",
            "description": "Name of the API key, unique across the deployment."
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "Description of the API key, or `null`."
          },
          "secret": {
            "type": "string",
            "description": "Secret of the API key, a generated 48-character string. Requests send the secret in the `x-api-key-secret` header. Foundation4 returns the secret only in the response that creates the key and stores only a hash of the secret."
          },
          "active": {
            "type": "boolean",
            "description": "`true` when the key can authenticate requests, and `false` after the key is deactivated."
          },
          "expiration": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Time after which the key no longer authenticates, in RFC 3339 format, or `null` for a key that does not expire."
          }
        }
      }
    },
    "securitySchemes": {
      "api_key": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "Identifier of the API key, sent in the x-api-key header."
      },
      "api_key_secret": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key-secret",
        "description": "Secret of the API key, sent in the x-api-key-secret header."
      }
    }
  },
  "tags": [
    {
      "name": "Core",
      "description": "The welcome message and the health check of the API server. Neither operation requires an API key."
    },
    {
      "name": "Authentication",
      "x-displayName": "Authentication",
      "description": "API keys, the permissions that each key holds, and the permissions of the calling key on objects. [Access control](../../concepts/09-access-control.md) describes the permission model."
    },
    {
      "name": "Pipelines",
      "description": "Pipelines, the classifications of a pipeline and the metadata indexes of a pipeline. [Pipelines](../../concepts/01-pipelines.md) describes the settings of a pipeline."
    },
    {
      "name": "Documents",
      "description": "Documents, document versions and fragments. [Documents, versions and fragments](../../concepts/02-documents-versions-fragments.md) describes the lifecycle of a document."
    },
    {
      "name": "Search",
      "description": "Similarity, maximal marginal relevance (MMR) and full-text search of a pipeline. [Search requests](../02-search-requests.md) describes every field of the request."
    },
    {
      "name": "Taxonomies",
      "description": "Taxonomies and taxonomy entries, which extend metadata filters across a hierarchy of values. [Metadata, filters and taxonomies](../../concepts/05-metadata-filters-taxonomies.md) describes taxonomy filters."
    },
    {
      "name": "Providers",
      "description": "The embedding providers and text splitter providers that the deployment supports. [Providers and models](../../reference/01-providers-and-models.md) lists every provider with the parameters that the provider accepts."
    },
    {
      "name": "Embedding Models",
      "x-displayName": "Embedding models",
      "description": "Embedding models, which convert fragments and queries into vectors. [Embedding models and text splitters](../../concepts/06-embedding-models-text-splitters.md) describes the object type."
    },
    {
      "name": "Text Splitters",
      "x-displayName": "Text splitters",
      "description": "Text splitters, which divide documents into fragments. [Embedding models and text splitters](../../concepts/06-embedding-models-text-splitters.md) describes the object type."
    },
    {
      "name": "Llms",
      "x-displayName": "LLMs",
      "description": "Language models (LLMs) registered with Foundation4, direct queries to a model and the OpenAI-compatible chat completions endpoint. [LLMs](../../concepts/07-llms.md) describes the object type and the response formats."
    },
    {
      "name": "Agents",
      "description": "Agents, the prompts that agents build, retrieval without generation, execution and execution traces. [Agents and prompt templates](../../concepts/08-agents-prompt-templates.md) describes agents."
    }
  ]
}
