{
  "openapi": "3.1.0",
  "info": {
    "title": "Gototem Public API",
    "version": "1.0.0",
    "summary": "Read-only access to your own data. Live today - the key, its places, events and payments received by method; sales totals, orders and products come later (they answer 501 for now).",
    "contact": {
      "name": "Gototem integrations support",
      "email": "integracao@gototem.com.br"
    },
    "description": "Read-only API for a Gototem account to consume its own data from its own systems.\n\n**Status.** `GET /ping`, `GET /places`, `GET /events` and `GET /sales/by-payment-method` are live.\nThe other routes are part of the published contract and are marked `x-status: planned`: they\nalready validate the whole request (key, place, parameters) and answer `501 not_implemented`\nuntil their logic is delivered. Their parameters and responses are provisional (see\n\"Compatibility and changes\").\n\n**Typical flow for the payments report:** `GET /places` gives the place `id`; with it,\n`GET /events?place=<id>` gives the event `id` (optional); then\n`GET /sales/by-payment-method?place=<id>&from=...&to=...` (and `&event=<id>` to restrict to one\nevent).\n\n## Authentication\n\nSend the API key in every request: `Authorization: Bearer gtpk_<43 characters>`. The account\nowner creates the key in the Gototem panel: user menu (the avatar at the top\nright) → \"Opções da conta\" → the \"Integrações\" box → \"Chaves da API\", and hands it to the\ndeveloper. A key is shown **once**, at creation and at rotation. It belongs to the\naccount and reaches only the places chosen when it was created. Every key has an **expiry date**\n(12 months by default, 24 months at most): it works until 23:59 of the chosen day in Brasilia\ntime, and `/ping` returns that instant in UTC as `credential.expires_at`. The owner can extend\nthe date without changing the key. `bearer` in lower case and extra spaces around the key are\naccepted. A refused key answers `401` with `WWW-Authenticate: Bearer realm=\"gototem-public-api\"`\nand the same `code` and `detail` whether the key is missing, malformed, unknown, revoked, paused,\nexpired or replaced; a key that is known and no longer valid also gets `reason` (see \"Errors\").\n\nThere is **no test environment and no test key**: every example and the collection point to\nproduction. Every route is read-only.\n\n## Permissions\n\nThe owner chooses, route by route, what a key can read. Each data route that is live needs its\n**permission** on the key; without it the route answers `403 forbidden_permission`. `/ping` and\n`/places` need no permission (they describe the key itself), and routes that still answer `501`\nneed none **today**: their permission is not defined yet, and each of them will require its own\nwhen it goes live. `/ping` lists the key's permissions.\n\nThat `403` carries `required_permission`, the permission the key lacks for the route called\n(for example `event.view`): hand that value to the account owner, who ticks it on the key.\n\n| Permission | Route |\n|---|---|\n| `sale-by-payment-method.view` | `GET /sales/by-payment-method` |\n| `event.view` | `GET /events` |\n\nThe **account owner** creates, edits and rotates keys; Gototem support can list and revoke a\nkey. The owner gets an e-mail whenever a key is created or rotated, and when an edit widens\nwhat the key reaches (more permissions, more places, a later expiry date, or a paused key\nswitched back on).\n\n## Key rotation\n\nAll of this is done by the account owner, in the panel.\n\n- **Rotating** issues a new key that works immediately; the previous one keeps working for\n  **24 hours**, so the integration can switch without downtime. While a request is authenticated\n  by the previous key, `/ping` answers `credential.superseded: true` with `superseded_until`,\n  and **every** response carries `Deprecation: true` and `Sunset` (the instant that key stops):\n  switch to the new key before it.\n- The owner can instead rotate **invalidating the current key** (for example, after a leak):\n  then every earlier key stops at once, the one in use and the one still in its grace period, and\n  the integration is down until it gets the new key.\n- **Pausing** switches the key off without changing it: every request answers `401` with\n  `reason: paused`, and the same key works again when the owner switches it back on. Pausing\n  within the 24 hours of a rotation ends the period of the previous key: from the pause on, the\n  previous key answers `401` with `reason: replaced` (not `paused`), and it does not come back\n  when the key is switched on again.\n- **Revoking** stops every key of the credential for good: the current key and a previous key\n  still in its 24 hours both answer `401` with `reason: revoked`.\n\nEdits made by the owner (a permission removed, fewer places, pause, revocation) apply to the\nfollowing requests within seconds, about one minute at most.\n\nDo not combine the key with other Gototem identity headers (`Account-Token`, `Api-Token`,\n`Producer-Token`, `EventOrganizer-Token`, `EventOrganizer-Host`, `Online-Catalog-Identifier`):\nthe request is refused with `400 conflicting_credentials`, whatever the value of the header and\non any path under `/v1/api-public/`, the documentation pages included.\n\nThis API is meant for servers and apps, not browsers: there is no CORS. Every route accepts only\n`GET`; any other method (including `HEAD` and `OPTIONS`) answers `405 method_not_allowed` with `Allow: GET`,\nand does not count against the rate limit. Every response of the routes below, success or\nerror, carries `Cache-Control: no-store`,\n`X-Content-Type-Options: nosniff` and `Content-Security-Policy: default-src 'none';\nframe-ancestors 'none'`.\n\n## Versioning\n\nThe version is mandatory in the path and only `v1` exists. Any other version, a missing version,\nor a versioned `Accept` header for another version (`application/vnd.<name>.v<number>+json`, for\nexample `application/vnd.example.v2+json`) answers `404`: the version in `Accept` wins over the\none in the path.\n\n## Dates and time zones\n\n- Every input date is ISO 8601 **with an offset** (`2026-10-07T00:00:00-03:00` or\n  `2026-10-07T03:00:00Z`). A date without an offset is refused (`422`). Both ends are converted\n  to UTC, so `Z` and `-03:00` for the same instant give the same result.\n- `from` and `to` are **instants**: the same window applies to every place of the query. To get\n  an exact calendar day of a place, build the window in that place's `timezone` (IANA name,\n  returned by `/places`) and query that place.\n- Only the routes that **group by day** (`/sales/by-day`) put each sale on its own place's day.\n  This can differ from the daily totals shown in the Gototem panel, which always use\n  `America/Sao_Paulo`.\n- Every instant returned is UTC (`Z`).\n\n## Limits\n\n- Date window: at most **120 days** on `/sales/*` and **31 days** on `/orders`. Above that the\n  request is refused, never truncated. Exception: `/sales/by-payment-method` with `event` has no\n  ceiling (the event already bounds the query, as in the Gototem panel). On\n  `/sales/by-payment-method` the ceiling is checked on the window actually applied, after a\n  fraction of a second is rounded up to the whole second.\n- `limit`: 1 to 100, default 50. Above 100 is refused, never truncated.\n- Unknown query parameters are refused (`422`). The `detail` names at most 5 of them, each cut to\n  40 characters, followed by \"and N more\".\n- A parameter the route accepts may be sent **once**. Sent twice (`place=A&place=B`,\n  `limit=5&limit=6`, also with the same value, and also `place[]=A&place[]=B`), the request\n  answers `422 invalid_parameter` with `param` set to its name and `detail`\n  `Parameter \"<name>\" was sent more than once.` The list form sent **once** (`place[]=A`) is\n  refused too, with the same `param`, as an invalid value: on a route that takes one place the\n  `detail` is `\"place\" must be a place identifier.`\n- Rate limit per key, per route class: `default` 60 requests/minute, `heavy` 10 requests/minute.\n  `/ping` returns the values in force for the key (`rate_limit` is `null` when no quota is being\n  enforced). All keys of the same account share an account ceiling (`default` 180, `heavy` 30\n  per minute). During the 24 hours after a rotation, the new key and the previous one each have\n  their own per-key balance, and the account ceiling applies to the two together. The window is\n  **sliding** (the last 60 seconds), and **refused requests keep counting**: a client that\n  retries without waiting stays blocked. Errors answered after the key is recognized (`403`,\n  `404` of a place or of an event, `422`, `501`) count too, in the class of the route called.\n  `Retry-After` is `60` on quota refusals (the length of the window) and `5` when the\n  account already has 2 `heavy` requests in progress; on the `429` of a blocked IP it is the\n  real wait, from 1 to 60 seconds: always read the header.\n- `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset` come on every response\n  that got past authentication and the key's quota check (success, `403`, `404` of a place or\n  of an event, `422`, `501`, `503`, and the `429` of the key or of the account), and also on the\n  `429` of a blocked IP and of the key's absolute ceiling (a fixed cap per key and route class,\n  well above the quota, that refuses a key hammering the API before the key is even checked),\n  with the limit of that check and `0` remaining. `X-RateLimit-Remaining` is `0` on a quota\n  `429`; on the `429` for `heavy` requests in progress (`Retry-After: 5`) it is the real\n  balance of the key, that refusal already counted.\n  `X-RateLimit-Remaining` is the **smaller** of what is left for the key and for the account.\n  `X-RateLimit-Reset` is an upper bound (`now` + the window): with a sliding window, capacity\n  may come back earlier.\n- 20 requests without a key, with a malformed key or with a key that **never existed**, from the\n  same IP within a minute, block that IP until those failures leave the last minute. A revoked,\n  expired, paused or replaced key does not count; a key from two rotations ago does.\n  That `429` carries `Retry-After` with the seconds left until the block ends (1 to 60), and\n  `X-RateLimit-Reset` for the same instant. When that wait ends there is little room left: the\n  window is sliding, only the oldest failure has left it, and one more failure blocks the IP\n  again. The `404` of a path that matches no route and the `405` neither count as failures nor\n  are blocked: a blocked IP still gets them.\n- Requests from the same IP that are still being authenticated are capped too: recent failures\n  plus requests in that stage at the same moment above 40 answer `429`. Authentication takes a\n  few milliseconds, so only a large burst of simultaneous calls from one IP (or a burst of\n  guessed keys) hits it.\n- At most 2 `heavy` requests in progress per account (see `/sales/by-payment-method`), and a\n  ceiling for the whole API: when it is full, a `heavy` request answers `429` with\n  `Retry-After: 5` even if the account has none in progress. If the service that counts the\n  requests in progress is unavailable, `/sales/by-payment-method` answers\n  `503 temporarily_unavailable` with `Retry-After` instead of running unbounded; the other\n  routes keep answering.\n- Query time: a query of `/sales/by-payment-method` is cut off after 15 seconds and a query of\n  `/events` after 3 seconds. A query that does not finish in time answers\n  `503 temporarily_unavailable` with `Retry-After`, never a partial result.\n\n**The cases of `429`.** The `code` is always `rate_limited`, and in code it is enough to wait\nfor `Retry-After`; the difference is there to investigate. Every `detail` below ends with\n\"Retry after the time in the Retry-After header.\"\n\n| Refused by | `Retry-After` | `X-RateLimit-Limit`; `X-RateLimit-Remaining` | `detail` begins with |\n|---|---|---|---|\n| The key's quota for the route class | 60 (the window) | the key's limit; `0` | `Rate limit exceeded for this API key.` |\n| The account ceiling (all keys together) | 60 | the limit of **the key**, not of the account; `0` | `Rate limit exceeded for this account.` |\n| `heavy` requests in progress: 2 for the account, or the ceiling for the whole API | 5 | the key's limit; the real balance, that refusal already counted | `Too many concurrent requests for this account on this endpoint.` (the same text in both cases) |\n| IP blocked for missing, malformed or unknown keys (20 within a minute) | the real wait, 1 to 60 | `20`; `0` | `Rate limit exceeded for this client.` |\n| Requests from one IP still being authenticated (those in that stage plus the failures of the last minute, above 40) | 60 | `40`; `0` | `Rate limit exceeded for this client.` |\n| The key's absolute ceiling per route class (well above the quota), checked before the key is read | 60 | the value of that ceiling; `0` | `Rate limit exceeded for this API key.` |\n| The per-IP limit of the documentation pages (30 per minute, the three together) | 60 | absent | `Rate limit exceeded for this client.` |\n\n## Identifiers and money\n\nIdentifiers are opaque strings of letters and digits (up to 64 characters today, usually 32).\nStore them as text and send them back exactly as received; never build, parse or compare them as\nnumbers. Money is a decimal string with two places (`\"1234.50\"`) with `currency: \"BRL\"`.\nConsumer personal data is never returned.\n\nEvent dates (`starts_at`, `ends_at`) are UTC instants with `Z`, like every date returned\n(`2026-10-09T23:00:00Z` is 20:00 in São Paulo). To show the event's local time, convert them to\nthe place's `timezone`.\n\n## Date format and windows\n\n- Dates are sent as `YYYY-MM-DDThh:mm:ss`, optional fraction of up to 6 digits, then `Z` or an\n  offset `±hh:mm`, with uppercase `T` and `Z` (for example `2026-10-07T00:00:00-03:00`). Other\n  ISO 8601 spellings (`z`, a space instead of `T`, `+0300`) are refused with `422`.\n- A window is **half-open**: `from` is included and `to` is not (`from <= t < to`). To ask for\n  the whole of 7 October in São Paulo, send `from=2026-10-07T00:00:00-03:00` and\n  `to=2026-10-08T00:00:00-03:00`. `from` equal to `to` is a valid, empty window.\n- On `/orders`, `created_*` and `updated_*` may be sent together: both apply (AND).\n\n## Lists and pagination\n\nLists (`/events`, `/orders`, `/products`) answer `{\"data\": [...], \"next_cursor\": \"...\"}`.\n`next_cursor` is `null` on the last page; to read the next one, repeat the same request with\n`cursor` set to it. The cursor is opaque: do not build or change it, and keep the other parameters\nunchanged while paging (a cursor belongs to the request that produced it). On `/events`, a\ncursor used with another `place` answers `422 invalid_parameter` with `param: cursor` and\n`detail` `\"cursor\" does not belong to this query.`; a cursor that did not come from this API, or\nwhose event was deleted while paging, answers `422` with `detail` `\"cursor\" is not valid.`\n(start again from the first page); with another `search` the result is undefined. Items come in a stable\norder, so a page never repeats or skips an item when new ones arrive: `/events` from the most\nrecently registered to the oldest; `/orders` and `/products` by the filtered instant, then by\nidentifier. `/places` is not paginated: it returns every place of the key at once.\n\n## Compatibility and changes\n\n- Within `v1` we only make **additive** changes: new fields in responses, new optional\n  parameters, new routes, new values in documented enumerations. Clients must ignore fields they\n  do not know and must not fail on a new enumeration value.\n- Anything else (removing or renaming a field, changing a type or a meaning, making a parameter\n  required) goes to a new version, `v2`. The previous version stays available for a coexistence\n  period after its successor is published; during that time its responses carry the headers\n  `Deprecation` and `Sunset` (RFC 8594) with the end date. Today only `v1` exists, so these two headers mean\n  one thing: the request used a key that was replaced by a rotation (see \"Key rotation\").\n- Routes marked `x-status: planned` (the ones that answer `501`) are **outside** the additive\n  rule: their parameters and responses are provisional. When such a route goes live its shape\n  may change (for example, `place` may come to take exactly one place, as on the live routes),\n  and the change is listed in the changelog.\n- The response schemas of the live routes and the error schema list **every** field returned\n  today (they are closed with `additionalProperties: false`) and mark as `required` the fields\n  that are always present. This does not change the rule above: a new field is still an\n  additive change, and it enters this contract in the same release. Do not configure a client\n  to reject unknown fields.\n- Every change is listed in the changelog below, with its date.\n\n## Developer guide\n\nThe guide for integrators (how to get a key from the store owner, dates, limits, errors), in\nPortuguese, is published in the Gototem developer portal, next to this contract (in YAML and in\nJSON) and to a ready-to-import collection for Postman and Insomnia (Postman v2.1 format,\ngenerated from this contract, live routes only). The API itself serves no documentation:\n`/v1/api-public/docs` and every path under it answer `404` like any other unknown path.\n\n## Changelog\n\nNewest first.\n\n- **2026-10-12** — The documentation left the API and is now published only in the developer\n  portal: `/v1/api-public/docs`, `/v1/api-public/docs/openapi.yaml` and\n  `/v1/api-public/docs/postman.json` answer `404`, and the `detail` of the root `404`\n  (`/v1/api-public`) no longer names the documentation address. No data route changed.\n- **2026-10-10** — Initial version of the public API. The routes that are live and the\n  planned ones are described in this contract.\n\n## Errors\n\nEvery error is `application/problem+json`, and every error produced by this API carries a stable\n`code`. Program against `code`; `detail` is for humans and may change. `type` is always\n`about:blank`: the error is identified by `code`, not by a URI. Every response produced by\nthis API, success or error, carries `X-Request-Id`: send it to support when reporting a problem.\n\nA `422` caused by a query parameter also carries `param`, the name of the parameter to fix: the\nfirst unknown one for an unknown parameter; the parameter itself for an invalid value; the\nmissing one when `from` or `to` comes alone; `from` when `from` is later than `to`; `to` when\nthe window is above the ceiling; `search` when it is empty, longer than 100 characters or has a\ncontrol or invisible character; the parameter itself when it was sent more than once; `cursor`\nwhen the cursor is not valid or belongs to another place. `param` is absent when no single\nparameter is to blame.\n\nA `404 not_found` caused by a resource asked for in a parameter carries `param` too: `place`\nwhen the key does not reach the place, `event` when the event is not of that place. A place\nthat does not exist and a place outside the key answer exactly the same (and so do an event that\ndoes not exist, one of another account and one of another place): `param` tells which\nparameter to fix, never which of those cases happened. The `404` of a path that matches no\nroute has no `param`.\n\n`search` has two `detail` texts: `\"search\" must be a text between 1 and 100 characters.` (empty,\na list, or too long) and `\"search\" must be valid UTF-8 text without control or invisible\ncharacters.` (a control or invisible character, or bytes that are not UTF-8).\n\nA `401 invalid_token` may carry `reason`, which says why a key that **was** valid stopped:\n`revoked` (revoked by the account owner), `expired` (past its expiry date), `paused` (switched\noff by the owner; the same key works again when it is switched back on) or `replaced` (it was\nthe previous key of a rotation and its time ended: the 24 hours passed, the owner rotated again\ninvalidating it, or the key was paused meanwhile). When more than one applies the order is\n`revoked`, `expired`, `paused`, `replaced`, with one exception: the previous key of a rotation\nwhose time ended answers `replaced` even while the key is paused, because it does not come back\nwhen the key is switched on again (the current key answers `paused`). `reason` only comes when the whole key presented\nbelongs to a known credential; a missing, malformed or unknown key gets the `401` without it,\nso it reveals nothing to someone guessing. Known limit: only the current key and the previous\none are remembered, so a key from two rotations ago (for example, the one still in its 24 hours\nwhen the owner rotated again) answers without `reason` and counts as an unknown key. A key of\na deactivated account also answers without `reason`. Rarely, a known key that is no longer\nvalid answers once without `reason`, and that answer may count toward the IP block. On a `401`\nwithout `reason`: stop repeating the request (a missing, malformed or unknown key counts toward\nthe IP block), check that the key sent is the right one and complete, try **once** after a\nminute and, if it persists, contact the account owner. With `reason`, the fix is with the account owner, not in the request. For\nexample: `{\"code\":\"invalid_token\",\"reason\":\"revoked\",\"type\":\"about:blank\",\"title\":\"Unauthorized\",\"status\":401,\"detail\":\"Invalid or missing API key.\"}`.\n\nA `403 forbidden_permission` also carries `required_permission`, the permission the key lacks\nfor that route (see \"Permissions\"). It names one permission, the one of the route called, and\nis absent from every other error.\n\nA path under `/v1/api-public/` that matches no route (an unknown path, a trailing slash, `//`,\na `.json` suffix, an `order_id` outside `[A-Za-z0-9]{1,64}`) answers `404` with\n`code: not_found`, in the same format as every other error and whatever the `Accept` header.\nWith the API disabled, every path under the prefix answers that same `404`.\n\nThe data routes answer JSON whatever the `Accept` header (`application/xml`, `text/html`, none):\n`Accept` does not choose the representation, only the version (see \"Versioning\").\n\nTwo refusals still come **without** `code` and with the server's own `type`:\n\n- a `GET` sent with a body and a `Content-Type` that is not JSON answers `415`. It only happens\n  with a valid key (without one the answer is the `401`), it carries `X-Request-Id` and\n  `X-RateLimit-*`, and it counts against the rate limit. Send no body and no `Content-Type`.\n  It is not listed under the responses of the routes.\n- an unexpected error of the server in front of this API (`5xx`), which may come without\n  `X-Request-Id`.\n\nTreat a missing `code` as \"not from the API contract\": retry `5xx`, fix the request on `4xx`.\n"
  },
  "servers": [
    {
      "url": "https://api.gototem.com.br"
    }
  ],
  "security": [
    {
      "apiKey": []
    }
  ],
  "tags": [
    {
      "name": "Account",
      "description": "The key itself and what it reaches.",
      "x-pt-BR": {
        "name": "Conta e acesso",
        "description": "A própria chave e o que ela alcança."
      }
    },
    {
      "name": "Sales",
      "description": "Consolidated sales and payments for a period.",
      "x-pt-BR": {
        "name": "Vendas e recebimentos",
        "description": "Vendas e recebimentos consolidados de um período."
      }
    },
    {
      "name": "Orders",
      "description": "Orders as complete documents.",
      "x-pt-BR": {
        "name": "Pedidos",
        "description": "Os pedidos, como documentos completos."
      }
    },
    {
      "name": "Products",
      "description": "Products, to translate the identifiers in sales and orders.",
      "x-pt-BR": {
        "name": "Cardápio e produtos",
        "description": "Os produtos, para traduzir os identificadores de vendas e pedidos."
      }
    },
    {
      "name": "Events",
      "description": "Events of a place.",
      "x-pt-BR": {
        "name": "Eventos e ingressos",
        "description": "Os eventos de uma loja."
      }
    }
  ],
  "x-tagGroups": [
    {
      "name": "Account and access",
      "x-id": "ref-conta-e-acesso",
      "x-pt-BR": {
        "name": "Conta e acesso"
      },
      "tags": [
        "Account"
      ]
    },
    {
      "name": "Sales and payments",
      "x-id": "ref-vendas-e-recebimentos",
      "x-pt-BR": {
        "name": "Vendas e recebimentos"
      },
      "tags": [
        "Sales"
      ]
    },
    {
      "name": "Orders",
      "x-id": "ref-pedidos",
      "x-pt-BR": {
        "name": "Pedidos"
      },
      "tags": [
        "Orders"
      ]
    },
    {
      "name": "Menu and products",
      "x-id": "ref-cardapio-e-produtos",
      "x-pt-BR": {
        "name": "Cardápio e produtos"
      },
      "tags": [
        "Products"
      ]
    },
    {
      "name": "Events and tickets",
      "x-id": "ref-eventos-e-ingressos",
      "x-pt-BR": {
        "name": "Eventos e ingressos"
      },
      "tags": [
        "Events"
      ]
    }
  ],
  "paths": {
    "/v1/api-public/ping": {
      "get": {
        "tags": [
          "Account"
        ],
        "operationId": "ping",
        "x-route-class": "default",
        "x-permission": null,
        "x-guide": "a-primeira-chamada",
        "x-pt-BR": {
          "summary": "Quem é esta chave",
          "description": "Diz a quem a chave pertence: a credencial, as permissões e a validade dela (`expires_at`), a conta, os limites em vigor e a hora do servidor em UTC. É a chamada para testar uma chave. `superseded` vem `true` quando a chamada usou a chave anterior de uma rotação, que vale só até `superseded_until`. `rate_limit` vem `null` quando nenhum limite está sendo aplicado no momento."
        },
        "summary": "Who is this key",
        "description": "Returns the credential, its account, the quota in force and the server time in UTC. Any valid key may call it. Route class `default`. The places of the key are in `/places`. `rate_limit` is `null` when no quota is being enforced (do not read it as \"unlimited\" for planning; the quota can be switched on at any time). `credential.expires_at` is when the key expires; `superseded` and `superseded_until` tell whether this request used the previous key of a rotation, and until when that key works.",
        "responses": {
          "200": {
            "description": "The key is valid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ping"
                },
                "example": {
                  "credential": {
                    "id": "Cr3d3nc14lId00000000000000000001",
                    "name": "Aplicativo de vendas",
                    "permissions": [
                      "sale-by-payment-method.view",
                      "event.view"
                    ],
                    "expires_at": "2027-10-11T02:59:59Z",
                    "superseded": false,
                    "superseded_until": null
                  },
                  "account": {
                    "id": "C0nt4Id0000000000000000000000001",
                    "name": "Restaurante Exemplo"
                  },
                  "rate_limit": {
                    "default_per_minute": 60,
                    "heavy_per_minute": 10
                  },
                  "server_time": "2026-10-08T17:51:06Z",
                  "api_version": "v1"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ConflictingCredentials"
          },
          "401": {
            "$ref": "#/components/responses/InvalidToken"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundPath"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "422": {
            "$ref": "#/components/responses/InvalidParameter"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/api-public/sales/summary": {
      "get": {
        "tags": [
          "Sales"
        ],
        "operationId": "salesSummary",
        "x-status": "planned",
        "x-route-class": "heavy",
        "x-permission": null,
        "x-pt-BR": {
          "summary": "Totais de vendas do período",
          "description": "Os totais de vendas das lojas no período."
        },
        "summary": "Sales totals for a period",
        "description": "Route class `heavy`. Available in a future release (answers 501 today to any valid key; the permission it will require is not defined yet).",
        "parameters": [
          {
            "$ref": "#/components/parameters/from"
          },
          {
            "$ref": "#/components/parameters/to"
          },
          {
            "$ref": "#/components/parameters/place"
          }
        ],
        "responses": {
          "400": {
            "$ref": "#/components/responses/ConflictingCredentials"
          },
          "401": {
            "$ref": "#/components/responses/InvalidToken"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "422": {
            "$ref": "#/components/responses/InvalidParameter"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "$ref": "#/components/responses/NotImplemented"
          }
        }
      }
    },
    "/v1/api-public/sales/by-day": {
      "get": {
        "tags": [
          "Sales"
        ],
        "operationId": "salesByDay",
        "x-status": "planned",
        "x-route-class": "heavy",
        "x-permission": null,
        "x-pt-BR": {
          "summary": "Vendas por dia",
          "description": "As vendas do período abertas por dia, cada venda no dia do fuso da loja dela."
        },
        "summary": "Sales per day, in each place's time zone",
        "description": "Route class `heavy`. Available in a future release (answers 501 today to any valid key; the permission it will require is not defined yet).",
        "parameters": [
          {
            "$ref": "#/components/parameters/from"
          },
          {
            "$ref": "#/components/parameters/to"
          },
          {
            "$ref": "#/components/parameters/place"
          }
        ],
        "responses": {
          "400": {
            "$ref": "#/components/responses/ConflictingCredentials"
          },
          "401": {
            "$ref": "#/components/responses/InvalidToken"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "422": {
            "$ref": "#/components/responses/InvalidParameter"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "$ref": "#/components/responses/NotImplemented"
          }
        }
      }
    },
    "/v1/api-public/sales/by-product": {
      "get": {
        "tags": [
          "Sales"
        ],
        "operationId": "salesByProduct",
        "x-status": "planned",
        "x-route-class": "heavy",
        "x-permission": null,
        "x-pt-BR": {
          "summary": "Vendas por produto",
          "description": "As vendas do período abertas por produto."
        },
        "summary": "Sales per product",
        "description": "Route class `heavy`. Available in a future release (answers 501 today to any valid key; the permission it will require is not defined yet).",
        "parameters": [
          {
            "$ref": "#/components/parameters/from"
          },
          {
            "$ref": "#/components/parameters/to"
          },
          {
            "$ref": "#/components/parameters/place"
          }
        ],
        "responses": {
          "400": {
            "$ref": "#/components/responses/ConflictingCredentials"
          },
          "401": {
            "$ref": "#/components/responses/InvalidToken"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "422": {
            "$ref": "#/components/responses/InvalidParameter"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "$ref": "#/components/responses/NotImplemented"
          }
        }
      }
    },
    "/v1/api-public/sales/by-place": {
      "get": {
        "tags": [
          "Sales"
        ],
        "operationId": "salesByPlace",
        "x-status": "planned",
        "x-route-class": "heavy",
        "x-permission": null,
        "x-pt-BR": {
          "summary": "Vendas por loja",
          "description": "As vendas do período abertas por loja."
        },
        "summary": "Sales per place",
        "description": "Route class `heavy`. Available in a future release (answers 501 today to any valid key; the permission it will require is not defined yet).",
        "parameters": [
          {
            "$ref": "#/components/parameters/from"
          },
          {
            "$ref": "#/components/parameters/to"
          },
          {
            "$ref": "#/components/parameters/place"
          }
        ],
        "responses": {
          "400": {
            "$ref": "#/components/responses/ConflictingCredentials"
          },
          "401": {
            "$ref": "#/components/responses/InvalidToken"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "422": {
            "$ref": "#/components/responses/InvalidParameter"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "$ref": "#/components/responses/NotImplemented"
          }
        }
      }
    },
    "/v1/api-public/sales/by-payment-method": {
      "get": {
        "tags": [
          "Sales"
        ],
        "operationId": "salesByPaymentMethod",
        "x-route-class": "heavy",
        "x-permission": "sale-by-payment-method.view",
        "x-guide": "recebimentos-por-metodo-de-pagamento",
        "x-pt-BR": {
          "summary": "Recebimentos por método de pagamento",
          "description": "Quanto uma loja recebeu no período, por método de pagamento e com a abertura por bandeira do cartão. Uma loja por chamada; com `event`, só os recebimentos daquele evento, sem o teto de 120 dias. O total soma os recebimentos pagos e **não desconta estornos**; ficam fora recebimento não pago ou cancelado, venda de demonstração, consumo pago com saldo cashless, sangria e suprimento. Venda feita sem conexão chega depois e muda um período já consultado: reconsulte os últimos 3 dias. A conta atende duas consultas desta rota ao mesmo tempo: a terceira responde `429` com `Retry-After: 5`."
        },
        "summary": "Payments received per payment method, with the card brand breakdown",
        "description": "Permission `sale-by-payment-method.view`. Route class `heavy`. **One place per request** (`place` is required); to\nrestrict to one event of that place, send `event` with an id from `/events`. The window is at\nmost 120 days without `event`, and has no ceiling with it.\n\nAt most 2 requests of this route may be in progress\nfor the account at the same time; a third one answers `429` (`rate_limited`, `Retry-After: 5`)\nwithout running the query, and that refusal still counts against the per-minute quota. Send\nrequests one after the other.\n\nThe two payment reports of the Gototem panel in one response: each item of `data` is a line\nof \"Resumo do recebimento\", and `brands` is the card brand breakdown of \"Resumo por\nbandeira\". Same filters and same numbers. Only methods with payments in the window are\nlisted (an empty window answers `data: []` and a zero total), in the order of the table below,\nwith `other` always last.\n\n**What the total includes and excludes.** Included: paid, not cancelled payments of sales and\ntabs, and cashless card top-ups and activations (money that came in). Excluded: unpaid or\ncancelled payments, demo sales, spending a cashless balance (that money was counted at the\ntop-up), cash taken out of and added to the till (\"sangria\" and \"suprimento\"),\nrefunds (of a sale item, a product or a cashless balance) and cashless balance\nwithdrawals (the balance handed back to the customer, \"Devolver cashless\" in the panel; not a\nrefund, but money that went out). Payments stored without a transaction type are left out of the totals and of every\nrow, as in the panel reports. `count` is the number of payments, not of orders.\n\n**The total is gross of refunds.** A refund is recorded as a separate entry that this query\nneither adds nor subtracts: the original payment stays in the total after being refunded.\nDo not use this total alone to reconcile net revenue; refunds are not returned by this API\nyet. A payment may have a negative amount (rare); it is summed as it is.\n\n**Late-arriving sales.** The window filters by the time the payment happened on the store\ndevice, not by the time it reached Gototem. A device that sold while offline sends its sales\nwhen the connection is back, and they land in the window in which they happened: **a window\nalready queried can change**. The delay is usually seconds or minutes, can be hours and, in\nrare cases, days. Query the last 3 days again on every refresh and replace what you stored.\n\n**Known limitation of `event`.** With `event`, a payment counts only if the payment itself\nwas recorded with that event. In rare cases the sale belongs to the event and its payment\nwas recorded without it: that payment is left out with `event` (and appears in the same\nwindow without `event`). The panel report filters the same way.\n\n| `payment_method` | `label` | Panel report line (as the Portuguese panel shows it) |\n|---|---|---|\n| `cash` | Dinheiro | Dinheiro |\n| `tef_virtual_wallet` | TEF - Carteira digital | TEF - Carteira Virtual |\n| `tef_credit` | TEF - Crédito | TEF - Crédito |\n| `tef_debit` | TEF - Débito | TEF - Débito |\n| `tef_voucher` | TEF - Voucher | TEF - Voucher |\n| `tef_voucher_2` | TEF - Voucher 2 | TEF - Voucher 2 |\n| `tef_others` | TEF - Outros | TEF - Outros |\n| `tef_pix` | TEF - Pix | TEF - Pix |\n| `tef_unspecified` | TEF - Não informado | TEF - Não informado |\n| `pos` | POS | POS |\n| `voucher` | Voucher | Voucher |\n| `not_identified` | Não identificado | Não identificado |\n| `other` | Outros | Outros |\n\nProgram against `payment_method`. `label` is display text in Portuguese and may change (it\ncan differ from the panel's wording, as on `tef_virtual_wallet`). New codes may be added (an\nadditive change): treat an unknown code as \"another method\".\n\n`brands` is filled only on `tef_*` lines (empty on the others). `brand` is the card brand as the terminal recorded it,\ntrimmed, when it has 1 to 40 characters and only letters, digits, spaces and `. & + / _ -`:\ndifferent spellings (`MASTERCARD`, `Mastercard`) are different items, as in the panel.\nAnything recorded outside that format is grouped under `\"OTHER\"` (counts, amounts and the\ntotal are unchanged); `null` gathers payments with no brand.\n\nTo reproduce a panel screen: the panel reads dates in Brasilia time and includes the last\nsecond. The screen \"01/10/2026 00:00:00 to 07/10/2026 23:59:59\" is\n`from=2026-10-01T00:00:00-03:00&to=2026-10-08T00:00:00-03:00`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/from"
          },
          {
            "$ref": "#/components/parameters/to"
          },
          {
            "$ref": "#/components/parameters/placeOne"
          },
          {
            "name": "event",
            "in": "query",
            "x-pt-BR": {
              "description": "O `id` de **um** evento dessa loja, vindo de `/events`. Só os recebimentos gravados com esse evento entram, e o teto de 120 dias deixa de valer. Limitação conhecida: recebimento de uma venda do evento que foi gravado sem o evento fica fora. Lista (`a,b`) responde `422`; evento que não existe ou é de outra loja responde `404` com `param` igual a `event`."
            },
            "description": "Optional. One event identifier, from `/events?place=<the same place>`. Only payments\nrecorded with that event are counted (see \"Known limitation of `event`\" above), and the\n120-day ceiling of the window does not apply (ticket sales open months before the\nevent). A list (`a,b`) answers 422; an event that does not exist, belongs to another\naccount or to another place answers 404 with `param: event` (the three cases answer the\nsame) and nothing is queried.\n",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9]{1,64}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Payments received in the window.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentMethodSummary"
                },
                "example": {
                  "from": "2026-10-01T03:00:00Z",
                  "to": "2026-10-08T03:00:00Z",
                  "place": "L0j4C3ntr0Id00000000000000000000",
                  "event": null,
                  "currency": "BRL",
                  "total": {
                    "count": 1234,
                    "amount": "45678.90"
                  },
                  "data": [
                    {
                      "payment_method": "cash",
                      "label": "Dinheiro",
                      "count": 100,
                      "amount": "2500.00",
                      "share": "5.473",
                      "brands": []
                    },
                    {
                      "payment_method": "tef_credit",
                      "label": "TEF - Crédito",
                      "count": 500,
                      "amount": "25000.00",
                      "share": "54.730",
                      "brands": [
                        {
                          "brand": "MASTERCARD",
                          "count": 300,
                          "amount": "16000.00",
                          "share": "35.027"
                        },
                        {
                          "brand": "VISA",
                          "count": 200,
                          "amount": "9000.00",
                          "share": "19.703"
                        }
                      ]
                    },
                    {
                      "payment_method": "tef_pix",
                      "label": "TEF - Pix",
                      "count": 634,
                      "amount": "18178.90",
                      "share": "39.797",
                      "brands": [
                        {
                          "brand": null,
                          "count": 634,
                          "amount": "18178.90",
                          "share": "39.797"
                        }
                      ]
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ConflictingCredentials"
          },
          "401": {
            "$ref": "#/components/responses/InvalidToken"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenPermission"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "422": {
            "$ref": "#/components/responses/InvalidParameter"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/TemporarilyUnavailable"
          }
        }
      }
    },
    "/v1/api-public/orders": {
      "get": {
        "tags": [
          "Orders"
        ],
        "operationId": "listOrders",
        "x-status": "planned",
        "x-route-class": "default",
        "x-permission": null,
        "x-pt-BR": {
          "summary": "Pedidos",
          "description": "Os pedidos, cada um como um documento completo, paginados por cursor. Pede ao menos um par de datas: `created_from` e `created_to`, ou `updated_from` e `updated_to` (no máximo 31 dias cada)."
        },
        "summary": "Orders, each one as a complete document",
        "description": "Route class `default`. Send at least one date pair: `created_from` and\n`created_to`, or `updated_from` and `updated_to` (31 days at most each). Paginated by cursor.\nAvailable in a future release (answers 501 today to any valid key; the permission it will\nrequire is not defined yet).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/place"
          },
          {
            "name": "created_from",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/InputInstant"
            },
            "description": "Included.",
            "x-pt-BR": {
              "description": "Início da criação do pedido, **incluído**. Vai junto com `created_to`."
            }
          },
          {
            "name": "created_to",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/InputInstant"
            },
            "description": "NOT included.",
            "x-pt-BR": {
              "description": "Fim da criação do pedido, **não incluído**."
            }
          },
          {
            "name": "updated_from",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/InputInstant"
            },
            "description": "Included.",
            "x-pt-BR": {
              "description": "Início da última alteração do pedido, **incluído**. Vai junto com `updated_to`."
            }
          },
          {
            "name": "updated_to",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/InputInstant"
            },
            "description": "NOT included.",
            "x-pt-BR": {
              "description": "Fim da última alteração do pedido, **não incluído**."
            }
          },
          {
            "$ref": "#/components/parameters/cursor"
          },
          {
            "$ref": "#/components/parameters/limit"
          }
        ],
        "responses": {
          "400": {
            "$ref": "#/components/responses/ConflictingCredentials"
          },
          "401": {
            "$ref": "#/components/responses/InvalidToken"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "422": {
            "$ref": "#/components/responses/InvalidParameter"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "$ref": "#/components/responses/NotImplemented"
          }
        }
      }
    },
    "/v1/api-public/orders/{order_id}": {
      "get": {
        "tags": [
          "Orders"
        ],
        "operationId": "getOrder",
        "x-status": "planned",
        "x-route-class": "default",
        "x-permission": null,
        "x-pt-BR": {
          "summary": "Um pedido",
          "description": "Um pedido, como um documento completo."
        },
        "summary": "One order as a complete document",
        "description": "Route class `default`. Available in a future release (answers 501 today to any valid key; the permission it will require is not defined yet).",
        "parameters": [
          {
            "name": "order_id",
            "in": "path",
            "required": true,
            "x-pt-BR": {
              "description": "O `id` do pedido, no caminho."
            },
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9]{1,64}$"
            }
          }
        ],
        "responses": {
          "400": {
            "$ref": "#/components/responses/ConflictingCredentials"
          },
          "401": {
            "$ref": "#/components/responses/InvalidToken"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundPath"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "422": {
            "$ref": "#/components/responses/InvalidParameter"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "$ref": "#/components/responses/NotImplemented"
          }
        }
      }
    },
    "/v1/api-public/places": {
      "get": {
        "tags": [
          "Account"
        ],
        "operationId": "listPlaces",
        "x-route-class": "default",
        "x-permission": null,
        "x-guide": "as-lojas-da-chave",
        "x-pt-BR": {
          "summary": "As lojas da chave",
          "description": "Todas as lojas que a chave alcança, de uma vez (sem paginação). O `id` de cada uma é o que vai no parâmetro `place` das outras rotas, e `timezone` é o fuso para montar o dia da loja."
        },
        "summary": "The places this key reaches",
        "description": "Any valid key may call it (no permission). Route class `default`. Every place the key reaches, at\nonce (not paginated). The `id` is what goes in `place` on every other route; `timezone` is\nthe IANA zone to build a place's calendar day. No parameters.\n",
        "responses": {
          "200": {
            "description": "The places of the key.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlaceList"
                },
                "example": {
                  "all": false,
                  "data": [
                    {
                      "id": "L0j4C3ntr0Id00000000000000000000",
                      "name": "Loja Centro",
                      "timezone": "America/Sao_Paulo",
                      "active": true
                    },
                    {
                      "id": "L0j4M4n4usId00000000000000000000",
                      "name": "Loja Manaus",
                      "timezone": "America/Manaus",
                      "active": true
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ConflictingCredentials"
          },
          "401": {
            "$ref": "#/components/responses/InvalidToken"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundPath"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "422": {
            "$ref": "#/components/responses/InvalidParameter"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/api-public/events": {
      "get": {
        "tags": [
          "Events"
        ],
        "operationId": "listEvents",
        "x-route-class": "default",
        "x-permission": "event.view",
        "x-guide": "os-eventos-de-uma-loja",
        "x-pt-BR": {
          "summary": "Os eventos de uma loja",
          "description": "Os eventos de uma loja da chave, do cadastrado mais recentemente para o mais antigo, paginados por cursor. Eventos desativados também aparecem. O `id` de cada um é o que vai no parâmetro `event` dos recebimentos."
        },
        "summary": "The events of one place, to filter the payments report",
        "description": "Permission `event.view`. Route class `default`. Only events of places this key reaches: `place`\nis required and takes one place. Paginated by cursor, most recently registered first.\nActive and inactive events are listed (`active` tells which): sales of a past event can still\nbe queried.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/placeOne"
          },
          {
            "name": "search",
            "in": "query",
            "x-pt-BR": {
              "description": "Parte do nome do evento, sem diferenciar maiúsculas nem acentos (1 a 100 caracteres). `%`, `_` e `\\` são texto comum, não curingas. Caractere de controle ou invisível em qualquer posição responde `422`."
            },
            "description": "Optional. Part of the event name, case-insensitive and accent-insensitive (1 to 100\ncharacters, trimmed): `sao joao` finds \"São João\". `%`, `_` and `\\` are matched as plain\ntext, not as wildcards. A control or invisible character anywhere in the value (tab, line\nbreak, zero-width space) answers 422 with `param: search`.\n",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            }
          },
          {
            "$ref": "#/components/parameters/cursor"
          },
          {
            "$ref": "#/components/parameters/limit"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of events of the place.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventList"
                },
                "example": {
                  "place": "L0j4C3ntr0Id00000000000000000000",
                  "search": "rock",
                  "data": [
                    {
                      "id": "Ev3nt0Id000000000000000000000001",
                      "name": "Rock Night",
                      "starts_at": "2026-10-09T23:00:00Z",
                      "ends_at": "2026-10-10T07:00:00Z",
                      "active": true
                    }
                  ],
                  "next_cursor": null
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ConflictingCredentials"
          },
          "401": {
            "$ref": "#/components/responses/InvalidToken"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenPermission"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "422": {
            "$ref": "#/components/responses/InvalidParameter"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/TemporarilyUnavailable"
          }
        }
      }
    },
    "/v1/api-public/products": {
      "get": {
        "tags": [
          "Products"
        ],
        "operationId": "listProducts",
        "x-status": "planned",
        "x-route-class": "default",
        "x-permission": null,
        "x-pt-BR": {
          "summary": "Produtos",
          "description": "Os produtos das lojas, para traduzir os identificadores que aparecem em vendas e pedidos. Paginados por cursor."
        },
        "summary": "Products, to translate the ids in sales and orders",
        "description": "Route class `default`. Paginated by cursor. Available in a future release (answers 501 today to any valid key; the permission it will require is not defined yet).",
        "parameters": [
          {
            "$ref": "#/components/parameters/place"
          },
          {
            "$ref": "#/components/parameters/cursor"
          },
          {
            "$ref": "#/components/parameters/limit"
          }
        ],
        "responses": {
          "400": {
            "$ref": "#/components/responses/ConflictingCredentials"
          },
          "401": {
            "$ref": "#/components/responses/InvalidToken"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "422": {
            "$ref": "#/components/responses/InvalidParameter"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "501": {
            "$ref": "#/components/responses/NotImplemented"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "gtpk_ + 43 base64url characters",
        "description": "API key of the integration. Shown once, at creation and at rotation."
      }
    },
    "headers": {
      "X-Request-Id": {
        "description": "Identifier of this request. Send it to support when reporting a problem.",
        "schema": {
          "type": "string"
        }
      },
      "X-RateLimit-Limit": {
        "description": "Requests allowed per minute for this key and route class (on a `429` of a blocked IP or of the absolute ceiling, the limit of that check).",
        "schema": {
          "type": "integer"
        }
      },
      "X-RateLimit-Remaining": {
        "description": "Requests left in the current window; the smaller of what is left for the key and for the account.",
        "schema": {
          "type": "integer"
        }
      },
      "X-RateLimit-Reset": {
        "description": "Unix time (seconds) by which the window has certainly moved on (`now` + the window). An upper bound, since the window is sliding.",
        "schema": {
          "type": "integer"
        }
      },
      "Retry-After": {
        "description": "Seconds to wait before trying again (the window length on quota refusals, 5 for requests in progress, and the real wait, 1 to 60, on the `429` of an IP blocked for unknown keys).",
        "schema": {
          "type": "integer",
          "example": 60
        }
      },
      "Allow": {
        "description": "The methods the path accepts. Always `GET`.",
        "schema": {
          "type": "string",
          "enum": [
            "GET"
          ]
        }
      },
      "Deprecation": {
        "description": "Only when the request was authenticated by the **previous** key of a rotation, still in its\n24-hour grace period: always `true`. It comes on every response after authentication (`200`,\n`403`, `404` of a place or of an event, `422`, `429` of the quota, `501`, `503`), never with\nthe current key and never on a `401`.\n",
        "schema": {
          "type": "string",
          "enum": [
            "true"
          ]
        }
      },
      "Sunset": {
        "description": "Comes together with `Deprecation`: the instant the key used stops working, as an HTTP date\nin GMT (RFC 8594). The same instant as `credential.superseded_until` of `/ping`.\n",
        "schema": {
          "type": "string",
          "example": "Fri, 09 Oct 2026 14:20:00 GMT"
        }
      }
    },
    "parameters": {
      "from": {
        "x-pt-BR": {
          "description": "Início do período, **incluído**. Data ISO 8601 com fuso. Com `to`, no máximo 120 dias (sem teto em `/sales/by-payment-method` com `event`)."
        },
        "name": "from",
        "in": "query",
        "required": true,
        "description": "Start of the period, included. With `to`, at most 120 days (no ceiling on `/sales/by-payment-method` with `event`). See \"Date format and windows\".",
        "schema": {
          "type": "string",
          "format": "date-time",
          "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d{1,6})?(Z|[+-]\\d{2}:\\d{2})$",
          "example": "2026-10-01T00:00:00-03:00"
        }
      },
      "to": {
        "x-pt-BR": {
          "description": "Fim do período, **não incluído**. Data ISO 8601 com fuso."
        },
        "name": "to",
        "in": "query",
        "required": true,
        "description": "End of the period, NOT included (`from <= t < to`).",
        "schema": {
          "type": "string",
          "format": "date-time",
          "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d{1,6})?(Z|[+-]\\d{2}:\\d{2})$",
          "example": "2026-10-08T00:00:00-03:00"
        }
      },
      "place": {
        "x-pt-BR": {
          "description": "Um ou mais `id` de loja, vindos de `/places`, separados por vírgula (no máximo 100). Sem `place`, todas as lojas da chave. Loja fora da chave responde `404` com `param` igual a `place`."
        },
        "name": "place",
        "in": "query",
        "description": "One or more place identifiers (from `/places`), separated by commas: `place=abc123` or\n`place=abc123,def456` (at most 100; a repeated one counts once). Without `place`, every place\nof the key. If any of them is not reached by this key, the request answers 404 with\n`param: place` and nothing is queried.\n",
        "schema": {
          "type": "string",
          "pattern": "^[A-Za-z0-9]{1,64}(,[A-Za-z0-9]{1,64}){0,99}$"
        },
        "example": "abc123,def456"
      },
      "placeOne": {
        "x-pt-BR": {
          "description": "O `id` de **uma** loja, vindo de `/places`. Ausente, vazio ou em lista (`a,b`) responde `422`; loja fora da chave (ou que não existe) responde `404` com `param` igual a `place`."
        },
        "name": "place",
        "in": "query",
        "required": true,
        "description": "Required. Exactly one place identifier, from `/places`. Missing, empty or a list (`a,b`)\nanswers 422; a place this key does not reach, or that does not exist (the two answer the\nsame), answers 404 with `param: place` and nothing is queried.\n",
        "schema": {
          "type": "string",
          "pattern": "^[A-Za-z0-9]{1,64}$"
        },
        "example": "L0j4C3ntr0Id00000000000000000000"
      },
      "cursor": {
        "x-pt-BR": {
          "description": "O `next_cursor` da página anterior, da mesma consulta. Em `/events`, o cursor de outra loja responde `422` com `param` igual a `cursor`."
        },
        "name": "cursor",
        "in": "query",
        "description": "Opaque cursor returned by the previous page of the same request. On `/events`, a cursor of another place answers 422 with `param` set to `cursor` (see \"Lists and pagination\").",
        "schema": {
          "type": "string",
          "pattern": "^[A-Za-z0-9_-]{1,200}$"
        }
      },
      "limit": {
        "x-pt-BR": {
          "description": "Itens por página, de 1 a 100 (padrão 50). Acima de 100 é recusado."
        },
        "name": "limit",
        "in": "query",
        "description": "Page size, 1 to 100 (default 50). Above 100 is refused.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100,
          "default": 50
        }
      }
    },
    "schemas": {
      "InputInstant": {
        "type": "string",
        "format": "date-time",
        "description": "See \"Date format and windows\". Uppercase `T` and `Z`, offset as `±hh:mm`.",
        "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d{1,6})?(Z|[+-]\\d{2}:\\d{2})$",
        "example": "2026-10-01T00:00:00-03:00"
      },
      "Problem": {
        "type": "object",
        "required": [
          "type",
          "title",
          "status",
          "detail"
        ],
        "additionalProperties": false,
        "properties": {
          "type": {
            "type": "string",
            "description": "Always `about:blank` on errors produced by this API: the error is identified by `code`,\nnot by a URI. Refusals that happen before this API (see \"Errors\" above) carry the\nserver's own value.\n",
            "example": "about:blank"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "detail": {
            "type": "string",
            "description": "For humans; may change."
          },
          "param": {
            "type": "string",
            "x-pt-BR": {
              "description": "O nome do parâmetro a corrigir: no 422 causado por um parâmetro, e no 404 de loja (`place`) ou de evento (`event`)."
            },
            "description": "The name of the query parameter to fix. On a `422` caused by a parameter: the first\nunknown one; the invalid one; the one sent more than once; the missing one of\n`from`/`to`; `from` when it is later than `to`; `to` when the window is above the\nceiling; `cursor` when it is not valid or belongs to another place. On a `404` of a\nresource asked for in a parameter: `place` or `event`. Absent when no single parameter\nis to blame, and on the `404` of a path that matches no route.\n",
            "example": "from"
          },
          "reason": {
            "type": "string",
            "x-pt-BR": {
              "description": "Só no 401 `invalid_token` de uma chave conhecida que deixou de valer: `revoked`, `expired`, `paused` ou `replaced`."
            },
            "description": "Only on a `401` with `code: invalid_token`, and only when the whole key presented\nbelongs to a known credential that is not valid now: `revoked` (revoked by the account\nowner), `expired` (past its expiry date), `paused` (switched off by the owner; the same\nkey works again when switched back on), `replaced` (the previous key of a rotation,\nafter its time ended). Order when more than one applies: `revoked`, `expired`, `paused`,\n`replaced`; the exception is the previous key of a rotation whose time ended, which\nanswers `replaced` even while the key is paused. Absent for a missing, malformed or unknown key. New values may be added:\ntreat an unknown one as \"the key is not valid; ask the account owner\".\n",
            "x-extensible-enum": [
              "revoked",
              "expired",
              "paused",
              "replaced"
            ],
            "example": "revoked"
          },
          "required_permission": {
            "type": "string",
            "x-pt-BR": {
              "description": "Só no 403 `forbidden_permission`: a permissão que falta na chave para a rota chamada, como `event.view`."
            },
            "description": "Only on a `403` with `code: forbidden_permission`: the permission the key lacks for the\nroute called. It is the value published as the permission of that route (`x-permission`)\nand listed in `credential.permissions` of `/ping`. The account owner grants it on the\nkey. New permissions may be added: do not validate it against a fixed list.\n",
            "example": "event.view"
          },
          "code": {
            "type": "string",
            "x-pt-BR": {
              "description": "O código estável do erro: programe contra ele."
            },
            "description": "Stable error code to program against. Present on every error produced by this API;\nabsent only on the refusals that happen before it (see \"Errors\" above). New codes may be\nadded: treat an unknown code by its HTTP status.\n",
            "x-extensible-enum": [
              "conflicting_credentials",
              "invalid_token",
              "forbidden_permission",
              "not_found",
              "method_not_allowed",
              "invalid_parameter",
              "rate_limited",
              "not_implemented",
              "internal_error",
              "temporarily_unavailable"
            ]
          }
        }
      },
      "Money": {
        "type": "string",
        "description": "Decimal with a dot and two places. Parse as a decimal, never as a float.",
        "pattern": "^-?\\d+\\.\\d{2}$",
        "example": "1234.50"
      },
      "Share": {
        "type": "string",
        "description": "Share of the total amount, in percent, with three places. The shares may not add up to exactly\n`100.000` (rounding). When the window has negative-value payments, a share can be negative\nor above 100.\n",
        "pattern": "^-?\\d+\\.\\d{3}$",
        "example": "54.730"
      },
      "PaymentMethodSummary": {
        "type": "object",
        "required": [
          "from",
          "to",
          "place",
          "event",
          "currency",
          "total",
          "data"
        ],
        "additionalProperties": false,
        "properties": {
          "from": {
            "type": "string",
            "format": "date-time",
            "description": "Window start actually applied, UTC, whole seconds (included)."
          },
          "to": {
            "type": "string",
            "format": "date-time",
            "description": "Window end actually applied, UTC, whole seconds (not included)."
          },
          "place": {
            "type": "string",
            "description": "The place queried, as sent in `place`."
          },
          "event": {
            "type": [
              "string",
              "null"
            ],
            "description": "The event sent in `event`; null when every event of the place was counted."
          },
          "currency": {
            "type": "string",
            "enum": [
              "BRL"
            ]
          },
          "total": {
            "type": "object",
            "required": [
              "count",
              "amount"
            ],
            "additionalProperties": false,
            "properties": {
              "count": {
                "type": "integer",
                "description": "Number of payments (zero-value payments included)."
              },
              "amount": {
                "$ref": "#/components/schemas/Money",
                "description": "Amount received, gross of refunds (refunds are not subtracted)."
              }
            }
          },
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "payment_method",
                "label",
                "count",
                "amount",
                "share",
                "brands"
              ],
              "additionalProperties": false,
              "properties": {
                "payment_method": {
                  "type": "string",
                  "description": "Stable code. New values may be added.",
                  "x-extensible-enum": [
                    "cash",
                    "tef_virtual_wallet",
                    "tef_credit",
                    "tef_debit",
                    "tef_voucher",
                    "tef_voucher_2",
                    "tef_others",
                    "tef_pix",
                    "tef_unspecified",
                    "pos",
                    "voucher",
                    "not_identified",
                    "other"
                  ]
                },
                "label": {
                  "type": "string",
                  "description": "Display text in Portuguese. May change."
                },
                "count": {
                  "type": "integer"
                },
                "amount": {
                  "$ref": "#/components/schemas/Money"
                },
                "share": {
                  "$ref": "#/components/schemas/Share"
                },
                "brands": {
                  "type": "array",
                  "description": "Card brand breakdown; empty outside `tef_*` lines. Ordered by amount, highest first.",
                  "items": {
                    "type": "object",
                    "required": [
                      "brand",
                      "count",
                      "amount",
                      "share"
                    ],
                    "additionalProperties": false,
                    "properties": {
                      "brand": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "description": "As recorded by the terminal, trimmed, when it has 1 to 40 characters and only letters, digits, spaces and `. & + / _ -`; `OTHER` for anything recorded outside that format; null when not recorded."
                      },
                      "count": {
                        "type": "integer"
                      },
                      "amount": {
                        "$ref": "#/components/schemas/Money"
                      },
                      "share": {
                        "$ref": "#/components/schemas/Share"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "PlaceList": {
        "type": "object",
        "required": [
          "all",
          "data"
        ],
        "additionalProperties": false,
        "properties": {
          "all": {
            "type": "boolean",
            "description": "True when the key reaches every place of the account, including new ones."
          },
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "id",
                "name",
                "timezone",
                "active"
              ],
              "additionalProperties": false,
              "properties": {
                "id": {
                  "type": "string",
                  "description": "Goes in `place` on the other routes."
                },
                "name": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "example": "Loja Centro",
                  "description": "Display name of the place."
                },
                "timezone": {
                  "type": "string",
                  "example": "America/Sao_Paulo",
                  "description": "IANA time zone of the place."
                },
                "active": {
                  "type": [
                    "boolean",
                    "null"
                  ],
                  "description": "False for a place deactivated by the account."
                }
              }
            }
          }
        }
      },
      "EventList": {
        "type": "object",
        "required": [
          "place",
          "search",
          "data",
          "next_cursor"
        ],
        "additionalProperties": false,
        "properties": {
          "place": {
            "type": "string",
            "description": "The place queried."
          },
          "search": {
            "type": [
              "string",
              "null"
            ],
            "description": "The search term applied, trimmed; null without `search`."
          },
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "id",
                "name",
                "starts_at",
                "ends_at",
                "active"
              ],
              "additionalProperties": false,
              "properties": {
                "id": {
                  "type": "string",
                  "description": "Goes in `event` on `/sales/by-payment-method`."
                },
                "name": {
                  "type": "string"
                },
                "starts_at": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "format": "date-time",
                  "description": "Start, UTC with `Z` (`2026-10-09T23:00:00Z`). Convert to the place's `timezone` to show local time."
                },
                "ends_at": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "format": "date-time",
                  "description": "End for multi-day events, UTC with `Z`; null when the event has no valid end."
                },
                "active": {
                  "type": "boolean",
                  "description": "False for an event deactivated by the account."
                }
              }
            }
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Send as `cursor` to read the next page; null on the last one."
          }
        }
      },
      "Ping": {
        "type": "object",
        "required": [
          "credential",
          "account",
          "rate_limit",
          "server_time",
          "api_version"
        ],
        "additionalProperties": false,
        "properties": {
          "credential": {
            "type": "object",
            "required": [
              "id",
              "name",
              "permissions",
              "expires_at",
              "superseded",
              "superseded_until"
            ],
            "additionalProperties": false,
            "properties": {
              "id": {
                "type": "string",
                "description": "Identifier of the credential, not of the secret: it stays the same when the key is rotated and is different for a key created anew. Use it to tell \"the new key of the same credential\" from \"another credential\"."
              },
              "name": {
                "type": "string",
                "example": "Aplicativo de vendas"
              },
              "permissions": {
                "type": "array",
                "description": "What the key can read, one permission per live data route. New values may be added.",
                "items": {
                  "type": "string",
                  "x-extensible-enum": [
                    "sale-by-payment-method.view",
                    "event.view"
                  ]
                }
              },
              "expires_at": {
                "type": "string",
                "format": "date-time",
                "description": "When the key expires, UTC with `Z`. It is the end of the day chosen by the account owner, which the panel shows as 23:59 in Brasilia time. The owner can extend it without changing the key.",
                "example": "2027-10-11T02:59:59Z"
              },
              "superseded": {
                "type": "boolean",
                "description": "True when this request was authenticated by the previous key of a rotation, which keeps working for 24 hours. Switch to the new key before `superseded_until`."
              },
              "superseded_until": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time",
                "description": "When `superseded` is true, the instant the key used stops working (UTC with `Z`); null otherwise. The same instant as the `Sunset` header."
              }
            }
          },
          "account": {
            "type": "object",
            "required": [
              "id",
              "name"
            ],
            "additionalProperties": false,
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              }
            }
          },
          "rate_limit": {
            "type": [
              "object",
              "null"
            ],
            "description": "Quota in force for this key per route class; null when no quota is being enforced.",
            "required": [
              "default_per_minute",
              "heavy_per_minute"
            ],
            "additionalProperties": false,
            "properties": {
              "default_per_minute": {
                "type": "integer",
                "example": 60
              },
              "heavy_per_minute": {
                "type": "integer",
                "example": 10
              }
            }
          },
          "server_time": {
            "type": "string",
            "format": "date-time",
            "example": "2026-10-08T17:51:06Z"
          },
          "api_version": {
            "type": "string",
            "const": "v1"
          }
        }
      }
    },
    "responses": {
      "ConflictingCredentials": {
        "x-code": "conflicting_credentials",
        "description": "Another Gototem identity header came with the key.",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/X-Request-Id"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "InvalidToken": {
        "x-code": "invalid_token",
        "description": "Key missing, malformed, unknown, revoked, paused, expired or replaced: always the same status, `code`\nand `detail`. A known key that is no longer valid also carries `reason` (`revoked`,\n`expired`, `paused`, `replaced`); see \"Errors\". Never carries `Deprecation`, `Sunset` or\n`X-RateLimit-*`.\n",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/X-Request-Id"
          },
          "WWW-Authenticate": {
            "description": "The authentication scheme (RFC 6750).",
            "schema": {
              "type": "string",
              "example": "Bearer realm=\"gototem-public-api\""
            }
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "example": {
              "type": "about:blank",
              "title": "Unauthorized",
              "status": 401,
              "detail": "Invalid or missing API key.",
              "code": "invalid_token"
            }
          }
        }
      },
      "ForbiddenPermission": {
        "x-code": "forbidden_permission",
        "description": "The key is valid but lacks the permission of this route (`forbidden_permission`).\n`required_permission` names the permission to ask the account owner for.\n",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/X-Request-Id"
          },
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/X-RateLimit-Limit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/X-RateLimit-Remaining"
          },
          "X-RateLimit-Reset": {
            "$ref": "#/components/headers/X-RateLimit-Reset"
          },
          "Deprecation": {
            "$ref": "#/components/headers/Deprecation"
          },
          "Sunset": {
            "$ref": "#/components/headers/Sunset"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "example": {
              "type": "about:blank",
              "title": "Forbidden",
              "status": 403,
              "detail": "This API key does not have the permission for this route.",
              "code": "forbidden_permission",
              "required_permission": "event.view"
            }
          }
        }
      },
      "NotFound": {
        "x-code": "not_found",
        "description": "Two kinds. (1) A resource asked for in a parameter is out of reach: a place the key does not\nreach or that does not exist (`param: place`, `detail` \"Place not found.\"), or an event\nthat is not of that place or does not exist (`param: event`, `detail` \"Event not found.\").\nThis one comes after the key was checked: it carries `X-RateLimit-*` (and `Deprecation` and\n`Sunset` with a replaced key) and counts against the rate limit. (2) The address itself:\nversion missing or other than 1, a path under `/v1/api-public/` that matches no route, or\nthe API is disabled. This one has no `param` and none of those headers.\n",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/X-Request-Id"
          },
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/X-RateLimit-Limit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/X-RateLimit-Remaining"
          },
          "X-RateLimit-Reset": {
            "$ref": "#/components/headers/X-RateLimit-Reset"
          },
          "Deprecation": {
            "$ref": "#/components/headers/Deprecation"
          },
          "Sunset": {
            "$ref": "#/components/headers/Sunset"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "example": {
              "type": "about:blank",
              "title": "Not Found",
              "status": 404,
              "detail": "Place not found.",
              "code": "not_found",
              "param": "place"
            }
          }
        }
      },
      "NotFoundPath": {
        "x-code": "not_found",
        "description": "The address itself: version missing or other than 1 (also a versioned `Accept` header for\nanother version), a path under `/v1/api-public/` that matches no route, or the API is\ndisabled. No `param`, no `X-RateLimit-*`.\n",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/X-Request-Id"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "example": {
              "type": "about:blank",
              "title": "Not Found",
              "status": 404,
              "detail": "Resource not found.",
              "code": "not_found"
            }
          }
        }
      },
      "MethodNotAllowed": {
        "x-code": "method_not_allowed",
        "description": "The answer to any method other than `GET` on this path (`HEAD` and `OPTIONS` included), with\nor without a key. It is decided before the key is checked: it does not count against the\nrate limit and carries no `X-RateLimit-*`.\n",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/X-Request-Id"
          },
          "Allow": {
            "$ref": "#/components/headers/Allow"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "example": {
              "type": "about:blank",
              "title": "Method Not Allowed",
              "status": 405,
              "detail": "This endpoint only accepts GET.",
              "code": "method_not_allowed"
            }
          }
        }
      },
      "InvalidParameter": {
        "x-code": "invalid_parameter",
        "description": "Unknown parameter (the `detail` names at most 5, each cut to 40 characters), a parameter sent more than once, invalid date, date without offset, window or limit above the ceiling, a `search` with a control or invisible character, or a `cursor` that is not valid or belongs to another place. `param` names the parameter to fix.",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/X-Request-Id"
          },
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/X-RateLimit-Limit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/X-RateLimit-Remaining"
          },
          "X-RateLimit-Reset": {
            "$ref": "#/components/headers/X-RateLimit-Reset"
          },
          "Deprecation": {
            "$ref": "#/components/headers/Deprecation"
          },
          "Sunset": {
            "$ref": "#/components/headers/Sunset"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "example": {
              "type": "about:blank",
              "title": "Unprocessable Entity",
              "status": 422,
              "detail": "Unknown parameter(s): status. Accepted: from, to, place.",
              "code": "invalid_parameter",
              "param": "status"
            }
          }
        }
      },
      "RateLimited": {
        "x-code": "rate_limited",
        "description": "Quota exceeded. The `detail` says which: this API key, the account ceiling, this client\n(an IP blocked after too many missing, malformed or unknown keys, or with too many requests still being\nauthenticated), or too many `heavy` requests in progress for the account or for the whole API\n(`Retry-After: 5`). `X-RateLimit-*` come on every one of them: on the IP block and on the\nkey's absolute ceiling they carry the limit of that check and `0` remaining; on a quota\nrefusal `X-RateLimit-Remaining` is `0`; on the refusal for requests in progress it is the\nreal balance of the key. On the IP\nblocked for unknown keys, `Retry-After` is the real wait (1 to 60 seconds) and\n`X-RateLimit-Reset` the same instant. A request\nrefused for being in progress still counts against the per-minute quota.\n",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/X-Request-Id"
          },
          "Retry-After": {
            "$ref": "#/components/headers/Retry-After"
          },
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/X-RateLimit-Limit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/X-RateLimit-Remaining"
          },
          "X-RateLimit-Reset": {
            "$ref": "#/components/headers/X-RateLimit-Reset"
          },
          "Deprecation": {
            "$ref": "#/components/headers/Deprecation"
          },
          "Sunset": {
            "$ref": "#/components/headers/Sunset"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "example": {
              "type": "about:blank",
              "title": "Too Many Requests",
              "status": 429,
              "detail": "Rate limit exceeded for this API key. Retry after the time in the Retry-After header.",
              "code": "rate_limited"
            }
          }
        }
      },
      "TemporarilyUnavailable": {
        "x-code": "temporarily_unavailable",
        "description": "Two cases, with the same `code` and the same `Retry-After: 60`; only `detail` tells them\napart. (1) The query did not finish in time, or the database was briefly unavailable:\n`detail` is \"The request could not be completed in time. Retry after the time in the\nRetry-After header.\" (2) On `/sales/by-payment-method` only, the service that counts requests\nin progress is unavailable and no query was run: `detail` is \"This endpoint is temporarily\nunable to accept requests. Retry after the time in the Retry-After header.\" In both, wait\nfor `Retry-After` and repeat; if the first persists, use a shorter window.\n",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/X-Request-Id"
          },
          "Retry-After": {
            "$ref": "#/components/headers/Retry-After"
          },
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/X-RateLimit-Limit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/X-RateLimit-Remaining"
          },
          "X-RateLimit-Reset": {
            "$ref": "#/components/headers/X-RateLimit-Reset"
          },
          "Deprecation": {
            "$ref": "#/components/headers/Deprecation"
          },
          "Sunset": {
            "$ref": "#/components/headers/Sunset"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "example": {
              "type": "about:blank",
              "title": "Service Unavailable",
              "status": 503,
              "detail": "The request could not be completed in time. Retry after the time in the Retry-After header.",
              "code": "temporarily_unavailable"
            }
          }
        }
      },
      "InternalError": {
        "x-code": "internal_error",
        "description": "Unexpected failure. Retry later; if it persists, send the `X-Request-Id` to support.",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/X-Request-Id"
          },
          "Deprecation": {
            "$ref": "#/components/headers/Deprecation"
          },
          "Sunset": {
            "$ref": "#/components/headers/Sunset"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            },
            "example": {
              "type": "about:blank",
              "title": "Internal Server Error",
              "status": 500,
              "detail": "The request could not be processed.",
              "code": "internal_error"
            }
          }
        }
      },
      "NotImplemented": {
        "x-code": "not_implemented",
        "description": "The route is part of the published contract but its logic is not available yet. This answer counts against the quota of the route's class.",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/X-Request-Id"
          },
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/X-RateLimit-Limit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/X-RateLimit-Remaining"
          },
          "X-RateLimit-Reset": {
            "$ref": "#/components/headers/X-RateLimit-Reset"
          },
          "Deprecation": {
            "$ref": "#/components/headers/Deprecation"
          },
          "Sunset": {
            "$ref": "#/components/headers/Sunset"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      }
    }
  }
}
