{
    "openapi": "3.1.0",
    "info": {
        "title": "SheetDB API",
        "version": "1",
        "summary": "Google Sheets as a JSON REST API",
        "description": "SheetDB turns a Google Sheets spreadsheet into a REST API. Each **API** is bound\nto one spreadsheet and identified by a 13-character **API ID** that appears in\nevery URL: `https://sheetdb.io/api/v1/{api_id}`.\n\n## Data model\n\n- The first row of a tab is the **header row**; its cells are the column names.\n- Every row below it is a **record**, returned as a JSON object keyed by the\n  column names. Values are strings (see `cast_numbers` for numbers).\n- An API works on the first tab unless the `sheet` query parameter selects\n  another tab by name. The parameter is called `sheet` for historical reasons.\n- A **row index** is the 0-based position of a record among the data rows:\n  0 is the first row below the header.\n\n## Reading and writing\n\n- Reads: `GET /{api_id}` (all records), `/search` and `/search_or` (filtered),\n  `/keys`, `/count`, `/name`, `/sheets`, `/cells/{cells}`, `/csv`.\n- Writes: `POST /{api_id}` appends records; `PATCH /{api_id}/{column}/{value}`\n  updates every record whose column matches the value; `DELETE\n  /{api_id}/{column}/{value}` deletes them. Batch update, row-index delete,\n  JSON import and tab management are separate operations.\n- **Write only what the task needs.** Read before updating or deleting when\n  the number of matching records is not obvious, because `{value}` supports\n  wildcards and comparisons that can match many records.\n- Every write purges the cache of the API, so the next read returns fresh data.\n\n## Search values\n\nThe same matching rules apply to search conditions, to `{value}` in update\nand delete URLs and to `query` in batch updates:\n\n- plain text matches the whole cell, case-insensitively unless\n  `casesensitive=true`; surrounding whitespace is ignored;\n- `*` matches any string (`J*`), `?` one character, `[abc]` a character set;\n  in search, wildcards need both the read and the search permission;\n- `!` in front negates (`!Tom` means not Tom);\n- `>`, `<`, `>=`, `<=` compare as integers (`>18`, `<=30`);\n- several values for one column: `id[]=>1&id[]=<3` (conditions combined\n  the same way as the endpoint: AND on `/search`, OR on `/search_or`);\n- spaces and `&` inside values must be URL-encoded (`%20`, `%26`).\n\n## Authentication\n\nAn API is public unless its owner enables **API authentication** in the\nAPI settings: either a Bearer token or HTTP Basic credentials, both specific\nto that API. Send them in the `Authorization` header; a wrong or missing\ncredential returns `401 {\"error\": \"Unauthorized.\"}`. The owner can also\nswitch individual operations off (**API permissions**: read, search, create,\nupdate, delete, create tabs, delete tabs); a switched-off operation returns\n`403` with a message naming the permission. CORS origins and client IP\naddresses can be restricted as well.\n\n## Requests, caching and limits\n\n- Every call to an operation on `/{api_id}` counts as one **request** of the\n  owner's plan, no matter how many records it touches and whether it was\n  served from cache. Over the monthly quota every call returns\n  `429 {\"error\": \"Request limit exceeded. Upgrade your plan.\"}` until the\n  plan is upgraded or the month ends.\n- Read responses are cached (15 seconds by default, longer when the owner\n  sets it). `ignore_cache=1` reads straight from Google.\n- Rate limit: 90 calls per minute per API, shared by all\n  clients of that API. Over it, calls return `429 {\"error\": \"Too many\n  requests\"}` and the `Retry-After` header says how many seconds to wait.\n- Google limits a spreadsheet to 10 million cells and a cell to 50,000\n  characters.\n\n## Demo API\n\n`58f61be4dda40` is a public demo API (columns `id`, `name`, `age`, `comment`,\nfive records: Tom, Alex, John, Steve, James). It resets every 15 minutes, so\nit is safe to try writes on it. All examples below use it.\n\n## Routing note\n\nConcrete path segments win over parameters, as in the server's router:\n`GET /{api_id}/search` is the search operation, never a cell range, and\n`/{app_id}/{api_key}/list` is a global endpoint, never an update.\n",
        "termsOfService": "https://sheetdb.io/rules-and-regulations",
        "contact": {
            "name": "SheetDB support",
            "url": "https://sheetdb.io",
            "email": "support@sheetdb.io"
        }
    },
    "externalDocs": {
        "description": "SheetDB documentation",
        "url": "https://docs.sheetdb.io/"
    },
    "servers": [
        {
            "url": "https://sheetdb.io/api/v1",
            "description": "SheetDB"
        }
    ],
    "tags": [
        {
            "name": "Read",
            "description": "Read records, column names, counts and single cells. Served from cache; each call counts as one request."
        },
        {
            "name": "Search",
            "description": "Read only the records matching conditions on columns, combined with AND (`/search`) or OR (`/search_or`)."
        },
        {
            "name": "Create",
            "description": "Append records to a tab."
        },
        {
            "name": "Update",
            "description": "Change the values of existing records."
        },
        {
            "name": "Delete",
            "description": "Remove records. Deletes are immediate and cannot be undone through the API."
        },
        {
            "name": "Tabs",
            "description": "Create and delete tabs of the spreadsheet (Premium plan and above)."
        },
        {
            "name": "Import",
            "description": "Append records from a JSON document sent in the body or fetched from a URL."
        },
        {
            "name": "Global endpoints",
            "description": "Manage the APIs of an account instead of the records of one spreadsheet: list, create and delete APIs.\nAvailable on the Premium plan and above.\n\n**Warning: the account's API key is part of the URL** (`/{app_id}/{api_key}/...`), so it ends up in\nserver logs, proxies and the `Referer` header. Only call these endpoints from a server, never from a\nbrowser, and treat the URL as a secret. The App ID and API keys are in the panel under API keys, where\neach key can also require a second factor (a Bearer token or Basic credentials in the `Authorization`\nheader) and can be limited to listing, creating or deleting.\n"
        },
        {
            "name": "Service",
            "description": "Operations without data."
        }
    ],
    "security": [
        [],
        {
            "bearerAuth": []
        },
        {
            "basicAuth": []
        }
    ],
    "paths": {
        "/": {
            "get": {
                "tags": [
                    "Service"
                ],
                "operationId": "ping",
                "summary": "API root",
                "description": "Returns a welcome message. Useful to check connectivity; it does not count as a request.",
                "security": [
                    []
                ],
                "responses": {
                    "200": {
                        "description": "Welcome message",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "message": {
                                            "type": "string"
                                        }
                                    }
                                },
                                "example": {
                                    "message": "Welcome to SheetDB API."
                                }
                            }
                        }
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/{api_id}": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/ApiId"
                }
            ],
            "get": {
                "tags": [
                    "Read"
                ],
                "operationId": "readRecords",
                "summary": "Read all records",
                "description": "Returns every record of the tab as an array of objects keyed by the column names, in sheet order.\nUse `limit` and `offset` to page through a large tab, `sort_by` and `sort_order` to sort,\n`cast_numbers` to get numbers instead of strings and `single_object=true` to get the first record\nas an object. To read only matching records, use `/search` instead of reading everything.\n\nExample: `GET https://sheetdb.io/api/v1/58f61be4dda40?sort_by=age&sort_order=desc&limit=2&cast_numbers=age`\n",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Sheet"
                    },
                    {
                        "$ref": "#/components/parameters/Limit"
                    },
                    {
                        "$ref": "#/components/parameters/Offset"
                    },
                    {
                        "$ref": "#/components/parameters/SortBy"
                    },
                    {
                        "$ref": "#/components/parameters/SortOrder"
                    },
                    {
                        "$ref": "#/components/parameters/SortMethod"
                    },
                    {
                        "$ref": "#/components/parameters/SortDateFormat"
                    },
                    {
                        "$ref": "#/components/parameters/CastNumbers"
                    },
                    {
                        "$ref": "#/components/parameters/SingleObject"
                    },
                    {
                        "$ref": "#/components/parameters/GroupBy"
                    },
                    {
                        "$ref": "#/components/parameters/GroupByWithCount"
                    },
                    {
                        "$ref": "#/components/parameters/ReadMode"
                    },
                    {
                        "$ref": "#/components/parameters/IgnoreCache"
                    }
                ],
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/Records"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            },
            "post": {
                "tags": [
                    "Create"
                ],
                "operationId": "createRecords",
                "summary": "Append records",
                "description": "Appends one or more records at the end of the tab. Send `{\"data\": [ {...}, {...} ]}` with the column\nnames as keys; a single object in `data` is also accepted, and so are form fields without `data`\n(then every field is treated as a column). Columns missing from a record are left empty; keys that are\nnot column names are ignored, and a record with no known column at all gives `400 Bad data format`.\n\nSpecial values, replaced by SheetDB before writing: `INCREMENT` (largest number in that column plus\none, useful for an `id` column), `TIMESTAMP` (current Unix time), `DATETIME` (current date and time,\n`2016-06-23 09:07:21`).\n\nValues are interpreted as if typed into Google Sheets (`mode=USER_ENTERED`, the default): `1,5` may\nbecome a number and `=SUM(A1)` a formula. Send `mode=RAW` to store the text exactly as sent.\n\nExample: `POST https://sheetdb.io/api/v1/58f61be4dda40` with\n`{\"data\": [{\"id\": \"INCREMENT\", \"name\": \"Mark\", \"age\": \"35\", \"comment\": \"\"}]}`.\n",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Sheet"
                    },
                    {
                        "$ref": "#/components/parameters/WriteMode"
                    },
                    {
                        "$ref": "#/components/parameters/ReturnValues"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/CreateBody"
                            },
                            "example": {
                                "data": [
                                    {
                                        "id": "INCREMENT",
                                        "name": "Mark",
                                        "age": "35",
                                        "comment": ""
                                    }
                                ]
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "$ref": "#/components/schemas/CreateBody"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Records appended",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Created"
                                },
                                "example": {
                                    "created": 1
                                }
                            }
                        }
                    },
                    "200": {
                        "description": "Records appended, with the written records (`return_values=true`)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "created",
                                        "data"
                                    ],
                                    "properties": {
                                        "created": {
                                            "type": "integer"
                                        },
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Record"
                                            }
                                        }
                                    }
                                },
                                "example": {
                                    "created": 1,
                                    "data": [
                                        {
                                            "id": "6",
                                            "name": "Mark",
                                            "age": "35",
                                            "comment": ""
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            },
            "delete": {
                "tags": [
                    "Delete"
                ],
                "operationId": "deleteRecordsByQuery",
                "summary": "Delete records (condition in query parameters)",
                "description": "Alternative form of `DELETE /{api_id}/{column}/{value}` and `DELETE /{api_id}/row_index/{row}` for\nclients that cannot put the condition in the path: pass `column` and `value`, or `row_index`, as\nquery parameters. Without them the call returns `400`. Behaviour and responses are those of the\npath forms.\n",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Sheet"
                    },
                    {
                        "name": "column",
                        "in": "query",
                        "description": "Column name of the condition (with `value`).",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "value",
                        "in": "query",
                        "description": "Value to match, with the search value syntax (with `column`).",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "row_index",
                        "in": "query",
                        "description": "0-based row index of the record to delete, or a JSON array of indexes.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/DeleteLimit"
                    },
                    {
                        "$ref": "#/components/parameters/CaseSensitive"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Records deleted",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Deleted"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/{api_id}/keys": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/ApiId"
                }
            ],
            "get": {
                "tags": [
                    "Read"
                ],
                "operationId": "getColumnNames",
                "summary": "Column names",
                "description": "Returns the header row of the tab as an array of column names, in sheet order. Call it first when\nthe columns are unknown, then use the names as keys in search conditions and write bodies.\nAn empty tab gives `400 Spreadsheet is empty...`.\n",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Sheet"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Column names",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "array",
                                    "items": {
                                        "type": "string"
                                    }
                                },
                                "example": [
                                    "id",
                                    "name",
                                    "age",
                                    "comment"
                                ]
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/{api_id}/count": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/ApiId"
                }
            ],
            "get": {
                "tags": [
                    "Read"
                ],
                "operationId": "countRecords",
                "summary": "Number of records",
                "description": "Returns the number of records (rows below the header) of the tab, from the same cache as the read operation. `mode` has no effect here.",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Sheet"
                    },
                    {
                        "$ref": "#/components/parameters/IgnoreCache"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Record count",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "rows"
                                    ],
                                    "properties": {
                                        "rows": {
                                            "type": "integer"
                                        }
                                    }
                                },
                                "example": {
                                    "rows": 5
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/{api_id}/name": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/ApiId"
                }
            ],
            "get": {
                "tags": [
                    "Read"
                ],
                "operationId": "getSpreadsheetName",
                "summary": "Spreadsheet name",
                "description": "Returns the title of the Google Sheets document behind the API.",
                "responses": {
                    "200": {
                        "description": "Spreadsheet title",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "name"
                                    ],
                                    "properties": {
                                        "name": {
                                            "type": "string"
                                        }
                                    }
                                },
                                "example": {
                                    "name": "SheetDB test document"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/{api_id}/sheets": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/ApiId"
                }
            ],
            "get": {
                "tags": [
                    "Read"
                ],
                "operationId": "listTabs",
                "summary": "Tab names",
                "description": "Returns the names of all tabs of the spreadsheet, in order. The first one is the tab used when no `sheet` parameter is given.",
                "responses": {
                    "200": {
                        "description": "Tab names",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "sheets"
                                    ],
                                    "properties": {
                                        "sheets": {
                                            "type": "array",
                                            "items": {
                                                "type": "string"
                                            }
                                        }
                                    }
                                },
                                "example": {
                                    "sheets": [
                                        "Sheet1",
                                        "Sheet2"
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/{api_id}/search": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/ApiId"
                }
            ],
            "get": {
                "tags": [
                    "Search"
                ],
                "operationId": "searchRecords",
                "summary": "Search records (all conditions must match)",
                "description": "Returns the records matching **every** condition. A condition is a query parameter named after a\ncolumn with the value to match (see \"Search values\" above for wildcards, negation and comparisons).\nColumn names with spaces are written with `%20` or `_`. Any query parameter that is not one of the\nreserved parameters listed here is treated as a column condition; an unknown column gives\n`404 Undefined column: ...`. Without any condition the result is an empty array.\n\nPaging, sorting and casting work as on the read operation. Set `row_index=true` to get each record's\n0-based row index in a `row_index` field, for a later `DELETE /{api_id}/row_index/{row}`.\n\nExamples: `/search?name=tom` (case-insensitive), `/search?age=>18&comment=special`,\n`/search?name=J*`, `/search?id[]=>1&id[]=<4`, `/search?name=!Tom`.\n",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/SearchConditions"
                    },
                    {
                        "$ref": "#/components/parameters/Sheet"
                    },
                    {
                        "$ref": "#/components/parameters/CaseSensitive"
                    },
                    {
                        "$ref": "#/components/parameters/SearchRowIndex"
                    },
                    {
                        "$ref": "#/components/parameters/Limit"
                    },
                    {
                        "$ref": "#/components/parameters/Offset"
                    },
                    {
                        "$ref": "#/components/parameters/SortBy"
                    },
                    {
                        "$ref": "#/components/parameters/SortOrder"
                    },
                    {
                        "$ref": "#/components/parameters/SortMethod"
                    },
                    {
                        "$ref": "#/components/parameters/SortDateFormat"
                    },
                    {
                        "$ref": "#/components/parameters/CastNumbers"
                    },
                    {
                        "$ref": "#/components/parameters/SingleObject"
                    },
                    {
                        "$ref": "#/components/parameters/GroupBy"
                    },
                    {
                        "$ref": "#/components/parameters/GroupByWithCount"
                    },
                    {
                        "$ref": "#/components/parameters/ReadMode"
                    },
                    {
                        "$ref": "#/components/parameters/IgnoreCache"
                    }
                ],
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/Records"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/{api_id}/search_or": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/ApiId"
                }
            ],
            "get": {
                "tags": [
                    "Search"
                ],
                "operationId": "searchRecordsOr",
                "summary": "Search records (any condition may match)",
                "description": "Like `/search`, but returns the records matching **at least one** condition. Each record appears once\neven when several conditions match it.\n\nExample: `/search_or?name=Tom&age=22` returns Tom and Steve.\n",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/SearchConditions"
                    },
                    {
                        "$ref": "#/components/parameters/Sheet"
                    },
                    {
                        "$ref": "#/components/parameters/CaseSensitive"
                    },
                    {
                        "$ref": "#/components/parameters/SearchRowIndex"
                    },
                    {
                        "$ref": "#/components/parameters/Limit"
                    },
                    {
                        "$ref": "#/components/parameters/Offset"
                    },
                    {
                        "$ref": "#/components/parameters/SortBy"
                    },
                    {
                        "$ref": "#/components/parameters/SortOrder"
                    },
                    {
                        "$ref": "#/components/parameters/SortMethod"
                    },
                    {
                        "$ref": "#/components/parameters/SortDateFormat"
                    },
                    {
                        "$ref": "#/components/parameters/CastNumbers"
                    },
                    {
                        "$ref": "#/components/parameters/SingleObject"
                    },
                    {
                        "$ref": "#/components/parameters/GroupBy"
                    },
                    {
                        "$ref": "#/components/parameters/GroupByWithCount"
                    },
                    {
                        "$ref": "#/components/parameters/ReadMode"
                    },
                    {
                        "$ref": "#/components/parameters/IgnoreCache"
                    }
                ],
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/Records"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/{api_id}/csv": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/ApiId"
                }
            ],
            "get": {
                "tags": [
                    "Read"
                ],
                "operationId": "exportCsv",
                "summary": "Export the tab as CSV",
                "description": "Returns the whole tab (header row and records) as a CSV file download, from the same cache as the read operation. No paging or sorting.",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Sheet"
                    },
                    {
                        "$ref": "#/components/parameters/ReadMode"
                    },
                    {
                        "$ref": "#/components/parameters/IgnoreCache"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "CSV content, sent as an attachment (`Content-Disposition` header)",
                        "content": {
                            "text/csv": {
                                "schema": {
                                    "type": "string"
                                },
                                "example": "id,name,age,comment\n1,Tom,15,\n2,Alex,24,\n"
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/{api_id}/cells/{cells}": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/ApiId"
                },
                {
                    "name": "cells",
                    "in": "path",
                    "required": true,
                    "description": "One or more cell addresses in A1 notation, separated by commas, for example `A1,B2,C5`.",
                    "schema": {
                        "type": "string"
                    },
                    "example": "A1,A2,B5"
                }
            ],
            "get": {
                "tags": [
                    "Read"
                ],
                "operationId": "getCells",
                "summary": "Values of single cells",
                "description": "Returns the value of each requested cell keyed by its address, including header cells. Reads straight\nfrom Google (not cached). A cell outside the sheet gives `400 One of the selected cells does not exist`.\n",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Sheet"
                    },
                    {
                        "$ref": "#/components/parameters/ReadMode"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Cell values keyed by address",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "additionalProperties": {
                                        "type": "string"
                                    }
                                },
                                "example": {
                                    "A1": "id",
                                    "A2": "1",
                                    "B5": "Steve"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/{api_id}/{column}/{value}": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/ApiId"
                },
                {
                    "$ref": "#/components/parameters/Column"
                },
                {
                    "$ref": "#/components/parameters/Value"
                }
            ],
            "patch": {
                "tags": [
                    "Update"
                ],
                "operationId": "updateRecords",
                "summary": "Update matching records",
                "description": "Writes the fields of `data` into **every** record whose `{column}` matches `{value}`; the other\ncolumns of those records stay unchanged. `{value}` uses the search value syntax, so `PATCH\n/{api_id}/name/J*` updates every record whose name starts with J (wildcards work here regardless of\nthe read permission). Keys of `data` that are not column names are ignored. Special values\n`INCREMENT`, `TIMESTAMP` and `DATETIME` and the `mode` parameter work as on create.\n\nResponds with the number of updated records; `404 No results found` when nothing matched.\n\nExample: `PATCH https://sheetdb.io/api/v1/58f61be4dda40/id/4` with `{\"data\": {\"comment\": \"renewed\"}}`.\n",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Sheet"
                    },
                    {
                        "$ref": "#/components/parameters/WriteMode"
                    },
                    {
                        "$ref": "#/components/parameters/CaseSensitive"
                    }
                ],
                "requestBody": {
                    "$ref": "#/components/requestBodies/Update"
                },
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/Updated"
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            },
            "put": {
                "tags": [
                    "Update"
                ],
                "operationId": "updateRecordsPut",
                "summary": "Update matching records (PUT)",
                "description": "Accepted for compatibility and currently behaves exactly like `PATCH`: only the columns present in\n`data` are written, the others are not cleared. Prefer `PATCH`.\n",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Sheet"
                    },
                    {
                        "$ref": "#/components/parameters/WriteMode"
                    },
                    {
                        "$ref": "#/components/parameters/CaseSensitive"
                    }
                ],
                "requestBody": {
                    "$ref": "#/components/requestBodies/Update"
                },
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/Updated"
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            },
            "delete": {
                "tags": [
                    "Delete"
                ],
                "operationId": "deleteRecords",
                "summary": "Delete matching records",
                "description": "Deletes **every** record whose `{column}` matches `{value}` and responds with the number of deleted\nrecords. `{value}` uses the search value syntax, so `DELETE /{api_id}/age/>60` deletes every record\nwith age above 60; check the count with `/search` first when in doubt. `limit` caps the number of\ndeleted records, counted from the top of the tab. `404 No results found` when nothing matched.\n\nExample: `DELETE https://sheetdb.io/api/v1/58f61be4dda40/name/Tom`.\n",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Sheet"
                    },
                    {
                        "$ref": "#/components/parameters/DeleteLimit"
                    },
                    {
                        "$ref": "#/components/parameters/CaseSensitive"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Records deleted",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Deleted"
                                },
                                "example": {
                                    "deleted": 1
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/{api_id}/batch_update": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/ApiId"
                }
            ],
            "patch": {
                "tags": [
                    "Update"
                ],
                "operationId": "batchUpdateRecords",
                "summary": "Update many records in one request",
                "description": "Applies several updates in one call and one request of the plan. `data` is an array; each item has a\n`query` of the form `column=value` (search value syntax, so `id=>5` or `name=J*` work) and the fields\nto write into every record matching that query. Keys that are not column names are ignored.\nResponds with the total number of updated records; `404 No results found` when no item matched.\n\nPaid plans only (`402` on the free plan). At most 10,000 items per request.\n\nExample: `{\"data\": [{\"query\": \"id=1\", \"name\": \"Sophia\", \"age\": \"20\"}, {\"query\": \"id=2\", \"age\": \"25\"}]}`.\n",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Sheet"
                    },
                    {
                        "$ref": "#/components/parameters/WriteMode"
                    },
                    {
                        "$ref": "#/components/parameters/CaseSensitive"
                    }
                ],
                "requestBody": {
                    "$ref": "#/components/requestBodies/BatchUpdate"
                },
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/Updated"
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            },
            "put": {
                "tags": [
                    "Update"
                ],
                "operationId": "batchUpdateRecordsPut",
                "summary": "Update many records in one request (PUT)",
                "description": "Accepted for compatibility and currently behaves exactly like the `PATCH` form. Prefer `PATCH`.",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Sheet"
                    },
                    {
                        "$ref": "#/components/parameters/WriteMode"
                    },
                    {
                        "$ref": "#/components/parameters/CaseSensitive"
                    }
                ],
                "requestBody": {
                    "$ref": "#/components/requestBodies/BatchUpdate"
                },
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/Updated"
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/{api_id}/row_index/{row}": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/ApiId"
                },
                {
                    "name": "row",
                    "in": "path",
                    "required": true,
                    "description": "0-based row index of the record to delete (0 is the first row below the header), or a JSON array\nof indexes such as `[0,2,5]` to delete several records in one call. Get indexes from\n`/search?...&row_index=true`.\n",
                    "schema": {
                        "type": "string"
                    },
                    "example": "2"
                }
            ],
            "delete": {
                "tags": [
                    "Delete"
                ],
                "operationId": "deleteRecordsByRowIndex",
                "summary": "Delete records by row index",
                "description": "Deletes the record at the given row index, or every record in the given array of indexes, without\nmatching on values. Rows are removed from the bottom up, so the indexes refer to the tab as it was\nbefore the call. Responds with `{\"deleted\": true}`; it does not check that the rows existed.\n",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Sheet"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Rows deleted",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "deleted"
                                    ],
                                    "properties": {
                                        "deleted": {
                                            "type": "boolean"
                                        }
                                    }
                                },
                                "example": {
                                    "deleted": true
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/{api_id}/all": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/ApiId"
                }
            ],
            "delete": {
                "tags": [
                    "Delete"
                ],
                "operationId": "deleteAllRecords",
                "summary": "Delete all records of the tab",
                "description": "Removes every record of the tab and keeps the header row, unless `with_first_row=true` also removes\nthe header. Responds with the number of deleted rows. Irreversible: confirm with the user before\ncalling it.\n",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Sheet"
                    },
                    {
                        "name": "with_first_row",
                        "in": "query",
                        "description": "`true` also deletes the header row, leaving the tab empty.",
                        "schema": {
                            "type": "boolean",
                            "default": false
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Rows deleted",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Deleted"
                                },
                                "example": {
                                    "deleted": 5
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/{api_id}/duplicates": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/ApiId"
                }
            ],
            "delete": {
                "tags": [
                    "Delete"
                ],
                "operationId": "deleteDuplicates",
                "summary": "Delete duplicate records",
                "description": "Deletes every record that repeats an earlier record of the tab, keeping the first occurrence. Records\nare compared as whole rows, case-sensitively. Responds with the number of removed records (0 when\nthere were none).\n",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Sheet"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Duplicates removed",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "duplicates"
                                    ],
                                    "properties": {
                                        "duplicates": {
                                            "type": "integer"
                                        }
                                    }
                                },
                                "example": {
                                    "duplicates": 2
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/{api_id}/sheet": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/ApiId"
                }
            ],
            "post": {
                "tags": [
                    "Tabs"
                ],
                "operationId": "createTab",
                "summary": "Create a tab",
                "description": "Adds a tab named `name` to the spreadsheet with `first_row` as its header row. Premium plan and above\n(`402` otherwise); needs the \"create tabs\" permission. A tab with that name already existing gives\n`400`.\n",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "name",
                                    "first_row"
                                ],
                                "properties": {
                                    "name": {
                                        "type": "string",
                                        "description": "Name of the new tab."
                                    },
                                    "first_row": {
                                        "type": "array",
                                        "description": "Column names of the new tab, in order.",
                                        "items": {
                                            "type": "string"
                                        }
                                    }
                                }
                            },
                            "example": {
                                "name": "Orders",
                                "first_row": [
                                    "id",
                                    "product",
                                    "quantity"
                                ]
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "name",
                                    "first_row"
                                ],
                                "properties": {
                                    "name": {
                                        "type": "string"
                                    },
                                    "first_row": {
                                        "type": "string",
                                        "description": "JSON array of column names, for example `[\"id\",\"name\"]`."
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Tab created",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "created": {
                                            "type": "string"
                                        }
                                    }
                                },
                                "example": {
                                    "created": "1"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            },
            "delete": {
                "tags": [
                    "Tabs"
                ],
                "operationId": "deleteTab",
                "summary": "Delete a tab",
                "description": "Deletes the tab named `name` together with all its records. Premium plan and above (`402` otherwise);\nneeds the \"delete tabs\" permission. Irreversible: confirm with the user before calling it.\n",
                "parameters": [
                    {
                        "name": "name",
                        "in": "query",
                        "required": true,
                        "description": "Name of the tab to delete (may also be sent in the body).",
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "requestBody": {
                    "required": false,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "name": {
                                        "type": "string"
                                    }
                                }
                            },
                            "example": {
                                "name": "Orders"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Tab deleted",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "deleted": {
                                            "type": "string"
                                        }
                                    }
                                },
                                "example": {
                                    "deleted": "1"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/{api_id}/import/json": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/ApiId"
                }
            ],
            "post": {
                "tags": [
                    "Import"
                ],
                "operationId": "importJson",
                "summary": "Import records from JSON",
                "description": "Appends the objects of `json` to the tab, writing their values in key order; nested values are\nstored as JSON text. Meant for filling an **empty** tab: the first object's keys are written as a\nheader row, so on a tab that already has data use `POST /{api_id}` instead. Needs the create permission.\n",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Sheet"
                    },
                    {
                        "$ref": "#/components/parameters/WriteMode"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "json"
                                ],
                                "properties": {
                                    "json": {
                                        "description": "Array of objects to import (a single object is accepted too).",
                                        "oneOf": [
                                            {
                                                "type": "array",
                                                "items": {
                                                    "type": "object"
                                                }
                                            },
                                            {
                                                "type": "object"
                                            }
                                        ]
                                    }
                                }
                            },
                            "example": {
                                "json": [
                                    {
                                        "id": 1,
                                        "name": "Mark"
                                    },
                                    {
                                        "id": 2,
                                        "name": "Susan"
                                    }
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Records imported",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Created"
                                },
                                "example": {
                                    "created": 2
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/{api_id}/import/url": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/ApiId"
                }
            ],
            "post": {
                "tags": [
                    "Import"
                ],
                "operationId": "importJsonFromUrl",
                "summary": "Import records from a JSON URL",
                "description": "Like the JSON import, but SheetDB fetches the JSON document from the public `url`. Private network\naddresses are rejected with `400`.\n",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Sheet"
                    },
                    {
                        "$ref": "#/components/parameters/WriteMode"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "url"
                                ],
                                "properties": {
                                    "url": {
                                        "type": "string",
                                        "format": "uri",
                                        "description": "Public URL returning a JSON array of objects."
                                    }
                                }
                            },
                            "example": {
                                "url": "https://example.com/data.json"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Records imported",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Created"
                                },
                                "example": {
                                    "created": 2
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/TooManyRequests"
                    }
                }
            }
        },
        "/{app_id}/{api_key}/list": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/AppId"
                },
                {
                    "$ref": "#/components/parameters/ApiKey"
                }
            ],
            "get": {
                "tags": [
                    "Global endpoints"
                ],
                "operationId": "listApis",
                "summary": "List the APIs of the account",
                "description": "Returns every API of the account with its API ID, URL and spreadsheet. Needs a key allowed to list APIs. Does not count as a request.",
                "responses": {
                    "200": {
                        "description": "APIs of the account",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "array",
                                    "items": {
                                        "$ref": "#/components/schemas/ApiSummary"
                                    }
                                },
                                "example": [
                                    {
                                        "id": "58f61be4dda40",
                                        "url": "https://sheetdb.io/api/v1/58f61be4dda40",
                                        "spreadsheet_id": "1xBvN3Yg4pQ2w9ZcK7LrT0sE5mH8dFfJqA",
                                        "spreadsheet_url": "https://docs.google.com/spreadsheets/d/1xBvN3Yg4pQ2w9ZcK7LrT0sE5mH8dFfJqA/edit#gid=0",
                                        "created_at": "2024-05-12T10:21:08.000000Z"
                                    }
                                ]
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/{app_id}/{api_key}/create": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/AppId"
                },
                {
                    "$ref": "#/components/parameters/ApiKey"
                }
            ],
            "post": {
                "tags": [
                    "Global endpoints"
                ],
                "operationId": "createApi",
                "summary": "Create an API from an existing spreadsheet",
                "description": "Creates an API for the Google Sheets document at `url`, which the account's Google user must have\naccess to. Optional `permissions` lists the API permissions to enable, comma-separated; without it\nthe defaults of a new API apply. Needs a key allowed to create APIs; counts against the plan's number\nof APIs (`402` when the limit is reached). Does not count as a request.\n",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/CreateApiBody"
                            },
                            "example": {
                                "url": "https://docs.google.com/spreadsheets/d/1xBvN3Yg4pQ2w9ZcK7LrT0sE5mH8dFfJqA/edit",
                                "permissions": "read,search,create"
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "$ref": "#/components/schemas/CreateApiBody"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/ApiCreated"
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/{app_id}/{api_key}/create/json": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/AppId"
                },
                {
                    "$ref": "#/components/parameters/ApiKey"
                }
            ],
            "post": {
                "tags": [
                    "Global endpoints"
                ],
                "operationId": "createApiFromJson",
                "summary": "Create a spreadsheet and an API from a JSON URL",
                "description": "Fetches the JSON document at `url` (an array of objects), creates a new spreadsheet named `title` in\nthe account's Google Drive with the objects as records and an API on top of it. Same key, plan and\n`permissions` rules as creating from a spreadsheet.\n",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "url"
                                ],
                                "properties": {
                                    "url": {
                                        "type": "string",
                                        "format": "uri",
                                        "description": "Public URL returning a JSON array of objects."
                                    },
                                    "title": {
                                        "type": "string",
                                        "description": "Name of the new spreadsheet; \"Untitled spreadsheet\" when omitted."
                                    },
                                    "permissions": {
                                        "$ref": "#/components/schemas/PermissionsList"
                                    }
                                }
                            },
                            "example": {
                                "url": "https://example.com/products.json",
                                "title": "Products",
                                "permissions": "read,search"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/ApiCreated"
                    },
                    "400": {
                        "$ref": "#/components/responses/BadRequest"
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/{app_id}/{api_key}/delete/{api_id}": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/AppId"
                },
                {
                    "$ref": "#/components/parameters/ApiKey"
                },
                {
                    "$ref": "#/components/parameters/ApiId"
                }
            ],
            "delete": {
                "tags": [
                    "Global endpoints"
                ],
                "operationId": "deleteApi",
                "summary": "Delete an API",
                "description": "Deletes the API with the given API ID from the account. The spreadsheet in Google Drive is not touched. Needs a key allowed to delete APIs. Does not count as a request.",
                "responses": {
                    "200": {
                        "description": "API deleted",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "deleted"
                                    ],
                                    "properties": {
                                        "deleted": {
                                            "type": "integer"
                                        }
                                    }
                                },
                                "example": {
                                    "deleted": 1
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "402": {
                        "$ref": "#/components/responses/PaymentRequired"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        }
    },
    "components": {
        "securitySchemes": {
            "bearerAuth": {
                "type": "http",
                "scheme": "bearer",
                "description": "API authentication with the Bearer token of the API (API settings, \"Authentication\"). Only needed when\nthe owner enabled it for that API. For global endpoints, the optional second factor of the API key.\n"
            },
            "basicAuth": {
                "type": "http",
                "scheme": "basic",
                "description": "API authentication with the Basic login and password of the API. Only needed when the owner enabled it\nfor that API. For global endpoints, the optional second factor of the API key.\n"
            }
        },
        "parameters": {
            "ApiId": {
                "name": "api_id",
                "in": "path",
                "required": true,
                "description": "The 13-character API ID from the API's URL in the SheetDB panel.",
                "schema": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9]{13}$"
                },
                "example": "58f61be4dda40"
            },
            "AppId": {
                "name": "app_id",
                "in": "path",
                "required": true,
                "description": "App ID of the account (panel, API keys).",
                "schema": {
                    "type": "string"
                }
            },
            "ApiKey": {
                "name": "api_key",
                "in": "path",
                "required": true,
                "description": "An API key of the account (panel, API keys). A secret in the URL; see the tag description.",
                "schema": {
                    "type": "string"
                }
            },
            "Column": {
                "name": "column",
                "in": "path",
                "required": true,
                "description": "Name of the column to match, exactly as in the header row (URL-encoded).",
                "schema": {
                    "type": "string"
                },
                "example": "id"
            },
            "Value": {
                "name": "value",
                "in": "path",
                "required": true,
                "description": "Value to match in `{column}`, with the search value syntax (`Tom`, `J*`, `!Tom`, `>18`). URL-encode it.",
                "schema": {
                    "type": "string"
                },
                "example": "4"
            },
            "Sheet": {
                "name": "sheet",
                "in": "query",
                "description": "Name of the tab to work on. Without it the first tab is used. An unknown tab gives `404 Sheet not found.`",
                "schema": {
                    "type": "string"
                },
                "example": "Sheet1"
            },
            "Limit": {
                "name": "limit",
                "in": "query",
                "description": "Maximum number of records to return, applied after sorting.",
                "schema": {
                    "type": "integer",
                    "minimum": 0
                },
                "example": 10
            },
            "Offset": {
                "name": "offset",
                "in": "query",
                "description": "Number of records to skip before the first returned one, applied after sorting. Combine with `limit` to page.",
                "schema": {
                    "type": "integer",
                    "minimum": 0,
                    "default": 0
                }
            },
            "SortBy": {
                "name": "sort_by",
                "in": "query",
                "description": "Column name to sort by. Values are compared as strings unless `sort_method=date`.",
                "schema": {
                    "type": "string"
                },
                "example": "age"
            },
            "SortOrder": {
                "name": "sort_order",
                "in": "query",
                "description": "`asc` (default), `desc` or `random` (shuffles the records; `sort_by` is then ignored).",
                "schema": {
                    "type": "string",
                    "enum": [
                        "asc",
                        "desc",
                        "random"
                    ]
                }
            },
            "SortMethod": {
                "name": "sort_method",
                "in": "query",
                "description": "`date` sorts `sort_by` as dates, parsed with `sort_date_format` or detected automatically.",
                "schema": {
                    "type": "string",
                    "enum": [
                        "date"
                    ]
                }
            },
            "SortDateFormat": {
                "name": "sort_date_format",
                "in": "query",
                "description": "PHP date format of the sorted column when `sort_method=date`, for example `Y-m-d` or `d/m/Y H:i`.",
                "schema": {
                    "type": "string"
                },
                "example": "Y-m-d"
            },
            "CastNumbers": {
                "name": "cast_numbers",
                "in": "query",
                "description": "Comma-separated column names whose values are returned as numbers instead of strings.",
                "schema": {
                    "type": "string"
                },
                "example": "id,age"
            },
            "SingleObject": {
                "name": "single_object",
                "in": "query",
                "description": "`true` returns the first record as an object instead of an array (an empty array when there is none).",
                "schema": {
                    "type": "boolean"
                }
            },
            "GroupBy": {
                "name": "group_by",
                "in": "query",
                "description": "Column name; the response becomes an object whose keys are the distinct values of that column and whose values are arrays of records.",
                "schema": {
                    "type": "string"
                }
            },
            "GroupByWithCount": {
                "name": "group_by_with_count",
                "in": "query",
                "description": "Column name; returns one record per distinct value of that column (the first one) with an added `count` field.",
                "schema": {
                    "type": "string"
                }
            },
            "ReadMode": {
                "name": "mode",
                "in": "query",
                "description": "Read mode, how cell values are rendered: `FORMATTED_VALUE` (default, as displayed in the sheet, for\nexample `$1,234.50`), `UNFORMATTED_VALUE` (the underlying value, `1234.5`), `FORMULA` (the formula text\nwhen the cell has one).\n",
                "schema": {
                    "type": "string",
                    "enum": [
                        "FORMATTED_VALUE",
                        "UNFORMATTED_VALUE",
                        "FORMULA"
                    ],
                    "default": "FORMATTED_VALUE"
                }
            },
            "WriteMode": {
                "name": "mode",
                "in": "query",
                "description": "Write mode, how sent values are interpreted: `USER_ENTERED` (default, as if typed into Google Sheets:\nnumbers, dates and formulas are recognised) or `RAW` (stored exactly as sent).\n",
                "schema": {
                    "type": "string",
                    "enum": [
                        "USER_ENTERED",
                        "RAW"
                    ],
                    "default": "USER_ENTERED"
                }
            },
            "IgnoreCache": {
                "name": "ignore_cache",
                "in": "query",
                "description": "`1` bypasses the cache and reads straight from Google Sheets (still one request of the plan).",
                "schema": {
                    "type": "integer",
                    "enum": [
                        0,
                        1
                    ]
                }
            },
            "CaseSensitive": {
                "name": "casesensitive",
                "in": "query",
                "description": "`true` makes value matching case-sensitive. Matching is case-insensitive by default.",
                "schema": {
                    "type": "boolean",
                    "default": false
                }
            },
            "SearchRowIndex": {
                "name": "row_index",
                "in": "query",
                "description": "`true` adds a `row_index` field (0-based position among the data rows) to every returned record.",
                "schema": {
                    "type": "boolean"
                }
            },
            "ReturnValues": {
                "name": "return_values",
                "in": "query",
                "description": "`true` returns the written records in the response (status 200 instead of 201).",
                "schema": {
                    "type": "boolean"
                }
            },
            "DeleteLimit": {
                "name": "limit",
                "in": "query",
                "description": "Maximum number of matching records to delete, counted from the top of the tab.",
                "schema": {
                    "type": "integer",
                    "minimum": 1
                }
            },
            "SearchConditions": {
                "name": "conditions",
                "in": "query",
                "description": "The search conditions, one query parameter per column: the parameter name is the column name and the\nvalue is the value to match with the search value syntax. This parameter is a container for them\n(serialized as `column=value&column2=value2`; the name `conditions` itself never appears in the URL).\n",
                "style": "form",
                "explode": true,
                "schema": {
                    "type": "object",
                    "additionalProperties": {
                        "type": "string"
                    }
                },
                "example": {
                    "name": "Tom",
                    "age": ">18"
                }
            }
        },
        "requestBodies": {
            "Update": {
                "required": true,
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/UpdateBody"
                        },
                        "example": {
                            "data": {
                                "comment": "renewed"
                            }
                        }
                    },
                    "application/x-www-form-urlencoded": {
                        "schema": {
                            "$ref": "#/components/schemas/UpdateBody"
                        }
                    }
                }
            },
            "BatchUpdate": {
                "required": true,
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/BatchUpdateBody"
                        },
                        "example": {
                            "data": [
                                {
                                    "query": "id=1",
                                    "name": "Sophia",
                                    "age": "20"
                                },
                                {
                                    "query": "id=2",
                                    "age": "25"
                                }
                            ]
                        }
                    }
                }
            }
        },
        "responses": {
            "Records": {
                "description": "Matching records",
                "content": {
                    "application/json": {
                        "schema": {
                            "oneOf": [
                                {
                                    "type": "array",
                                    "description": "The default shape, an array of records.",
                                    "items": {
                                        "$ref": "#/components/schemas/Record"
                                    }
                                },
                                {
                                    "$ref": "#/components/schemas/Record"
                                },
                                {
                                    "type": "object",
                                    "description": "With `group_by`, records grouped by the values of that column.",
                                    "additionalProperties": {
                                        "type": "array",
                                        "items": {
                                            "$ref": "#/components/schemas/Record"
                                        }
                                    }
                                }
                            ]
                        },
                        "example": [
                            {
                                "id": "1",
                                "name": "Tom",
                                "age": "15",
                                "comment": ""
                            },
                            {
                                "id": "4",
                                "name": "Steve",
                                "age": "22",
                                "comment": "special"
                            }
                        ]
                    }
                }
            },
            "Updated": {
                "description": "Records updated",
                "content": {
                    "application/json": {
                        "schema": {
                            "type": "object",
                            "required": [
                                "updated"
                            ],
                            "properties": {
                                "updated": {
                                    "type": "integer",
                                    "description": "Number of updated records."
                                }
                            }
                        },
                        "example": {
                            "updated": 1
                        }
                    }
                }
            },
            "ApiCreated": {
                "description": "API created",
                "content": {
                    "application/json": {
                        "schema": {
                            "type": "object",
                            "required": [
                                "success",
                                "name",
                                "id",
                                "url"
                            ],
                            "properties": {
                                "success": {
                                    "type": "boolean"
                                },
                                "name": {
                                    "type": "string",
                                    "description": "Spreadsheet title."
                                },
                                "id": {
                                    "type": "string",
                                    "description": "API ID of the new API."
                                },
                                "url": {
                                    "type": "string",
                                    "description": "Base URL of the new API."
                                }
                            }
                        },
                        "example": {
                            "success": true,
                            "name": "Products",
                            "id": "9k2mf8d1qz7xa",
                            "url": "https://sheetdb.io/api/v1/9k2mf8d1qz7xa"
                        }
                    }
                }
            },
            "BadRequest": {
                "description": "Invalid input (missing or malformed body, unknown cell, empty tab) or an error reported by Google Sheets.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        },
                        "example": {
                            "error": "Bad data format"
                        }
                    }
                }
            },
            "Unauthorized": {
                "description": "API authentication is enabled for this API and the credential is missing or wrong, or the account's Google access to the spreadsheet is gone.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        },
                        "example": {
                            "error": "Unauthorized."
                        }
                    }
                }
            },
            "PaymentRequired": {
                "description": "The operation is not included in the owner's plan (batch update, tabs, global endpoints) or a plan limit is reached.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        },
                        "example": {
                            "error": "You don't have an access for that method, upgrade your plan to use batch update."
                        }
                    }
                }
            },
            "Forbidden": {
                "description": "The owner switched this operation off in the API permissions, or the account is blocked.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        },
                        "example": {
                            "error": "Permission delete is disabled for this API."
                        }
                    }
                }
            },
            "NotFound": {
                "description": "Unknown API ID, tab, column, or no record matched (updates and deletes).",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        },
                        "examples": {
                            "api": {
                                "value": {
                                    "error": "Wrong API id"
                                }
                            },
                            "sheet": {
                                "value": {
                                    "error": "Sheet not found."
                                }
                            },
                            "column": {
                                "value": {
                                    "error": "Undefined column: email"
                                }
                            },
                            "noResults": {
                                "value": {
                                    "error": "No results found"
                                }
                            }
                        }
                    }
                }
            },
            "TooManyRequests": {
                "description": "The monthly request quota of the owner's plan is used up, or the per-API rate limit is hit (then `Retry-After` says how many seconds to wait).",
                "headers": {
                    "Retry-After": {
                        "description": "Seconds to wait before retrying (rate limit only).",
                        "schema": {
                            "type": "integer"
                        }
                    }
                },
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        },
                        "examples": {
                            "quota": {
                                "value": {
                                    "error": "Request limit exceeded. Upgrade your plan."
                                }
                            },
                            "rateLimit": {
                                "value": {
                                    "error": "Too many requests"
                                }
                            }
                        }
                    }
                }
            }
        },
        "schemas": {
            "Record": {
                "type": "object",
                "description": "One row of the tab keyed by the column names. Values are strings unless `cast_numbers` was used.",
                "additionalProperties": {
                    "oneOf": [
                        {
                            "type": "string"
                        },
                        {
                            "type": "number"
                        }
                    ]
                },
                "example": {
                    "id": "1",
                    "name": "Tom",
                    "age": "15",
                    "comment": ""
                }
            },
            "RecordInput": {
                "type": "object",
                "description": "Values to write keyed by column name. Unknown keys are ignored. The special values `INCREMENT`, `TIMESTAMP` and `DATETIME` are replaced by SheetDB.",
                "additionalProperties": {
                    "oneOf": [
                        {
                            "type": "string"
                        },
                        {
                            "type": "number"
                        },
                        {
                            "type": "boolean"
                        },
                        {
                            "type": "null"
                        }
                    ]
                }
            },
            "CreateBody": {
                "type": "object",
                "required": [
                    "data"
                ],
                "properties": {
                    "data": {
                        "description": "Records to append, or a single record.",
                        "oneOf": [
                            {
                                "type": "array",
                                "items": {
                                    "$ref": "#/components/schemas/RecordInput"
                                }
                            },
                            {
                                "$ref": "#/components/schemas/RecordInput"
                            }
                        ]
                    }
                }
            },
            "UpdateBody": {
                "type": "object",
                "required": [
                    "data"
                ],
                "properties": {
                    "data": {
                        "$ref": "#/components/schemas/RecordInput",
                        "description": "Fields to write into every matching record. Columns not listed stay unchanged."
                    }
                }
            },
            "BatchUpdateBody": {
                "type": "object",
                "required": [
                    "data"
                ],
                "properties": {
                    "data": {
                        "type": "array",
                        "description": "Updates to apply; each item selects records with `query` and lists the fields to write.",
                        "maxItems": 10000,
                        "items": {
                            "type": "object",
                            "required": [
                                "query"
                            ],
                            "properties": {
                                "query": {
                                    "type": "string",
                                    "description": "`column=value` with the search value syntax, for example `id=1` or `status=open`."
                                }
                            },
                            "additionalProperties": {
                                "oneOf": [
                                    {
                                        "type": "string"
                                    },
                                    {
                                        "type": "number"
                                    },
                                    {
                                        "type": "boolean"
                                    },
                                    {
                                        "type": "null"
                                    }
                                ]
                            }
                        }
                    }
                }
            },
            "Created": {
                "type": "object",
                "required": [
                    "created"
                ],
                "properties": {
                    "created": {
                        "type": "integer",
                        "description": "Number of appended records."
                    }
                }
            },
            "Deleted": {
                "type": "object",
                "required": [
                    "deleted"
                ],
                "properties": {
                    "deleted": {
                        "type": "integer",
                        "description": "Number of deleted rows."
                    }
                }
            },
            "PermissionsList": {
                "type": "string",
                "description": "Comma-separated API permissions to enable on the new API; any of `read`, `search`, `create`, `update`, `delete`, `tabs_create`, `tabs_delete`. Permissions not listed are disabled.",
                "example": "read,search,create"
            },
            "CreateApiBody": {
                "type": "object",
                "required": [
                    "url"
                ],
                "properties": {
                    "url": {
                        "type": "string",
                        "format": "uri",
                        "description": "URL of the Google Sheets document (`https://docs.google.com/spreadsheets/d/{id}/edit`)."
                    },
                    "permissions": {
                        "$ref": "#/components/schemas/PermissionsList"
                    }
                }
            },
            "ApiSummary": {
                "type": "object",
                "required": [
                    "id",
                    "url",
                    "spreadsheet_id",
                    "spreadsheet_url",
                    "created_at"
                ],
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "API ID."
                    },
                    "url": {
                        "type": "string",
                        "description": "Base URL of the API."
                    },
                    "spreadsheet_id": {
                        "type": "string",
                        "description": "Google Sheets document id."
                    },
                    "spreadsheet_url": {
                        "type": "string",
                        "description": "Link to the document."
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time"
                    }
                }
            },
            "Error": {
                "type": "object",
                "required": [
                    "error"
                ],
                "properties": {
                    "error": {
                        "type": "string",
                        "description": "Human-readable reason. Show it to the user; do not retry a 4xx error unchanged."
                    }
                }
            }
        }
    }
}
