> ## Documentation Index
> Fetch the complete documentation index at: https://tatallo-docs.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# API reference

> Every operation of the Tatallo PMS API v1, generated from its OpenAPI file.

This reference is generated from the Tatallo PMS API's OpenAPI 3.1 file, the single public contract of version 1. [Download the OpenAPI file](https://tatallo-docs.mintlify.site/openapi/tatallo-pms-v1.yaml), or copy it from the end of this page, to generate a client or import it into your API tool.

| Server | Base URL |
| - | - |
| Production | `https://api.tatallo.com` |
| Staging (synthetic properties only) | `https://staging.api.tatallo.com` |

Every operation except `GET /v1/health` needs a PMS credential, sent as `Authorization: Bearer <key>`. The property operations also need the `properties:read` scope.

Every response carries an `X-Request-Id` header, and every error has the same shape: `{ "error": { "code", "message", "request_id" } }`.

> **The OpenAPI file**
>
> ```yaml tatallo-pms-v1.yaml theme={null}
> # GENERATED by scripts/build-openapi.mjs from openapi/tatallo-pms-v1.yaml and
> # openapi/examples/*.json. Do not edit: change the source, then run `pnpm openapi:build`.
> openapi: 3.1.0
> info:
>   title: Tatallo PMS API
>   version: 1.0.0
>   summary: The server-to-server API a PMS uses to list and read the Tatallo properties its hosts have connected.
>   description: |
>     The Tatallo PMS API is a small, read-only, server-to-server API. A PMS calls it with a
>     Tatallo-issued PMS credential and sees exactly the properties its hosts have connected.
>
>     - Every response carries an `X-Request-Id` header, always a UUID. Send your own UUID in
>       `X-Request-Id` to have it echoed back.
>     - Every error has the shape `{ "error": { "code", "message", "request_id" } }`. Messages
>       are English and may change; codes never do.
>     - Each PMS credential may make 60 requests per minute (`GET /v1/health`: 60 per minute
>       per client IP). Over the limit you get `429` with `Retry-After`.
>     - Within `/v1` the contract changes only additively. A breaking change gets at least
>       6 months' notice on the changelog.
>   contact:
>     name: Tatallo developer support
>     email: developers@tatallo.com
> servers:
>   - url: https://api.tatallo.com
>     description: Production
>   - url: https://staging.api.tatallo.com
>     description: Staging (synthetic properties only)
> tags:
>   - name: System
>     description: Connectivity and the identity of your PMS credential.
>   - name: Properties
>     description: The Tatallo properties your hosts have connected to your PMS.
> security:
>   - PmsCredential: []
> paths:
>   /v1/health:
>     get:
>       operationId: getHealth
>       tags:
>         - System
>       summary: Check that Tatallo is reachable
>       description: |
>         Answers `200` whenever the Tatallo PMS API is up. Needs no key, so it tells a network
>         problem from an authentication problem. Rate-limited per client IP.
>       security: []
>       responses:
>         "200":
>           description: Tatallo is reachable.
>           headers:
>             X-Request-Id:
>               $ref: "#/components/headers/XRequestId"
>           content:
>             application/json:
>               schema:
>                 $ref: "#/components/schemas/Health"
>               examples:
>                 ok:
>                   summary: Tatallo is reachable
>                   value:
>                     status: ok
>         "429":
>           $ref: "#/components/responses/RateLimited"
>   /v1/me:
>     get:
>       operationId: getMe
>       tags:
>         - System
>       summary: See which PMS credential you are using
>       description: |
>         Names the PMS credential that made the call: its public ID, your PMS, the environment
>         it belongs to and its scopes. Any valid key may call it, whatever its scopes. It never
>         returns a secret, so logging the response is safe.
>       responses:
>         "200":
>           description: The calling PMS credential.
>           headers:
>             X-Request-Id:
>               $ref: "#/components/headers/XRequestId"
>           content:
>             application/json:
>               schema:
>                 $ref: "#/components/schemas/Me"
>               examples:
>                 staging:
>                   summary: The staging Test PMS credential
>                   value:
>                     credential_id: 5d4e040b-61c1-44a4-a4ca-9a751dc05133
>                     pms_name: Test PMS
>                     environment: staging
>                     scopes:
>                       - properties:read
>         "401":
>           $ref: "#/components/responses/Unauthorized"
>         "429":
>           $ref: "#/components/responses/RateLimited"
>   /v1/properties:
>     get:
>       operationId: listProperties
>       tags:
>         - Properties
>       summary: List the properties connected to your PMS
>       description: |
>         Lists every property your hosts have connected to your PMS, a page at a time, in a
>         stable order. Follow `page.next_cursor` until it is `null` to see them all; each
>         property appears exactly once. Needs the `properties:read` scope.
>       parameters:
>         - name: limit
>           in: query
>           required: false
>           description: How many properties per page, from 1 to 100.
>           schema:
>             type: integer
>             minimum: 1
>             maximum: 100
>             default: 25
>         - name: cursor
>           in: query
>           required: false
>           description: |
>             The `page.next_cursor` of the previous page, exactly as returned. It is opaque and
>             works only with the PMS credential and environment it was issued to. Don't store
>             it or build it by hand.
>           schema:
>             type: string
>       responses:
>         "200":
>           description: One page of properties.
>           headers:
>             X-Request-Id:
>               $ref: "#/components/headers/XRequestId"
>           content:
>             application/json:
>               schema:
>                 $ref: "#/components/schemas/PropertyList"
>               examples:
>                 allOnOnePage:
>                   summary: Every connected property on one page
>                   value:
>                     data:
>                       - id: 6cfa992d-1805-4de6-892c-23785031aba0
>                         name: Fixture Loft Kreuzberg
>                         timezone: Europe/Berlin
>                         status: active
>                         country: Germany
>                         city: Berlin
>                         max_guests: 2
>                         currency: EUR
>                         updated_at: 2026-10-01T09:00:00.000Z
>                       - id: 934f807c-39d6-45de-b107-d5c9e03cb041
>                         name: Fixture House Alfama
>                         timezone: Europe/Lisbon
>                         status: inactive
>                         country: Portugal
>                         city: Lisbon
>                         max_guests: 6
>                         currency: EUR
>                         updated_at: 2026-10-01T09:00:00.000Z
>                       - id: bef2859f-2444-47ec-b5f4-f1e6701f087f
>                         name: Fixture Apartment Trastevere
>                         timezone: Europe/Rome
>                         status: active
>                         country: Italy
>                         city: Rome
>                         max_guests: 4
>                         currency: EUR
>                         updated_at: 2026-10-01T09:00:00.000Z
>                     page:
>                       next_cursor: null
>                 firstOfSeveralPages:
>                   summary: "The first page at limit=1: follow page.next_cursor for the next"
>                   value:
>                     data:
>                       - id: 6cfa992d-1805-4de6-892c-23785031aba0
>                         name: Fixture Loft Kreuzberg
>                         timezone: Europe/Berlin
>                         status: active
>                         country: Germany
>                         city: Berlin
>                         max_guests: 2
>                         currency: EUR
>                         updated_at: 2026-10-01T09:00:00.000Z
>                     page:
>                       next_cursor: pKZAA9cXZioUAmmXQVzN4RBwg8cC3KXflLg_Ys2qB0vNw7TfJ1kq3m8cWl5yHh0eE4tR6uD1aPo
>         "400":
>           description: "`limit` is out of range (`invalid_limit`), or `cursor` is not a cursor this key was given (`invalid_cursor`)."
>           headers:
>             X-Request-Id:
>               $ref: "#/components/headers/XRequestId"
>           content:
>             application/json:
>               schema:
>                 $ref: "#/components/schemas/InvalidListQueryError"
>               examples:
>                 invalidLimit:
>                   summary: limit is not a whole number from 1 to 100
>                   value:
>                     error:
>                       code: invalid_limit
>                       message: limit must be a whole number from 1 to 100.
>                       request_id: 451fe2aa-a20b-4a92-b34f-3a27f5dd2f8b
>                 invalidCursor:
>                   summary: The cursor was edited, made by hand or issued to another key
>                   value:
>                     error:
>                       code: invalid_cursor
>                       message: The cursor is not valid. Use page.next_cursor exactly as returned, with the same key.
>                       request_id: 30c04c3a-c527-432c-8db3-f4943d4bcf57
>         "401":
>           $ref: "#/components/responses/Unauthorized"
>         "403":
>           $ref: "#/components/responses/InsufficientScope"
>         "429":
>           $ref: "#/components/responses/RateLimited"
>   /v1/properties/{propertyId}:
>     get:
>       operationId: getProperty
>       tags:
>         - Properties
>       summary: Read one property connected to your PMS
>       description: |
>         Reads one property your hosts have connected to your PMS. A property that is not
>         connected to your PMS, was removed, or never existed gets the same `404`, so the
>         answer reveals nothing about properties not connected to you. Needs the
>         `properties:read` scope.
>       parameters:
>         - name: propertyId
>           in: path
>           required: true
>           description: The property's `id`, as listed by `GET /v1/properties`.
>           schema:
>             type: string
>             format: uuid
>           example: bef2859f-2444-47ec-b5f4-f1e6701f087f
>       responses:
>         "200":
>           description: The property.
>           headers:
>             X-Request-Id:
>               $ref: "#/components/headers/XRequestId"
>           content:
>             application/json:
>               schema:
>                 $ref: "#/components/schemas/Property"
>               examples:
>                 active:
>                   summary: A connected, published property
>                   value:
>                     id: bef2859f-2444-47ec-b5f4-f1e6701f087f
>                     name: Fixture Apartment Trastevere
>                     timezone: Europe/Rome
>                     status: active
>                     country: Italy
>                     city: Rome
>                     max_guests: 4
>                     currency: EUR
>                     updated_at: 2026-10-01T09:00:00.000Z
>                 inactive:
>                   summary: A connected, suspended property
>                   value:
>                     id: 934f807c-39d6-45de-b107-d5c9e03cb041
>                     name: Fixture House Alfama
>                     timezone: Europe/Lisbon
>                     status: inactive
>                     country: Portugal
>                     city: Lisbon
>                     max_guests: 6
>                     currency: EUR
>                     updated_at: 2026-10-01T09:00:00.000Z
>         "401":
>           $ref: "#/components/responses/Unauthorized"
>         "403":
>           $ref: "#/components/responses/InsufficientScope"
>         "404":
>           description: The property is not connected to your PMS, or does not exist.
>           headers:
>             X-Request-Id:
>               $ref: "#/components/headers/XRequestId"
>           content:
>             application/json:
>               schema:
>                 $ref: "#/components/schemas/PropertyNotFoundError"
>               examples:
>                 notFound:
>                   summary: Not connected to your PMS, or does not exist
>                   value:
>                     error:
>                       code: property_not_found
>                       message: Property not found.
>                       request_id: 385c1118-7082-4e15-97a7-16703f74d58b
>         "429":
>           $ref: "#/components/responses/RateLimited"
> components:
>   securitySchemes:
>     PmsCredential:
>       type: http
>       scheme: bearer
>       description: |
>         A PMS credential issued by Tatallo: an opaque key of the form `tat_<env>_sk_…`, where
>         `<env>` is `stg` on staging and `live` on production. A key works only in its own
>         environment. Send it as `Authorization: Bearer <key>`, from your servers only.
>   headers:
>     XRequestId:
>       description: The request's ID, on every response. Your own UUID if you sent a well-formed one in `X-Request-Id`, otherwise one Tatallo generated. Quote it to support.
>       required: true
>       schema:
>         type: string
>         format: uuid
>     RetryAfter:
>       description: Seconds to wait before the next request.
>       required: true
>       schema:
>         type: integer
>         minimum: 1
>   responses:
>     Unauthorized:
>       description: The key is missing, malformed, for another environment, expired or revoked. All of these get the same answer.
>       headers:
>         X-Request-Id:
>           $ref: "#/components/headers/XRequestId"
>       content:
>         application/json:
>           schema:
>             $ref: "#/components/schemas/UnauthorizedError"
>           examples:
>             unauthorized:
>               summary: Missing, malformed, expired or revoked key
>               value:
>                 error:
>                   code: unauthorized
>                   message: Missing or invalid PMS credential.
>                   request_id: e867476c-9237-4ebd-af42-b93abc47d0ed
>     InsufficientScope:
>       description: The key is valid but lacks the `properties:read` scope.
>       headers:
>         X-Request-Id:
>           $ref: "#/components/headers/XRequestId"
>       content:
>         application/json:
>           schema:
>             $ref: "#/components/schemas/InsufficientScopeError"
>           examples:
>             insufficientScope:
>               summary: The key lacks properties:read
>               value:
>                 error:
>                   code: insufficient_scope
>                   message: This PMS credential lacks the properties:read scope.
>                   request_id: 0f3b8f8e-5f8c-4b84-9a8e-5d6c2a1e7b40
>     RateLimited:
>       description: Too many requests in the current minute. Wait for `Retry-After` seconds.
>       headers:
>         X-Request-Id:
>           $ref: "#/components/headers/XRequestId"
>         Retry-After:
>           $ref: "#/components/headers/RetryAfter"
>       content:
>         application/json:
>           schema:
>             $ref: "#/components/schemas/RateLimitedError"
>           examples:
>             rateLimited:
>               summary: More than 60 requests in a minute
>               value:
>                 error:
>                   code: rate_limited
>                   message: Too many requests. Retry after the number of seconds in Retry-After.
>                   request_id: c2b7e1d4-8a3f-4e6b-9d2c-7f1a5e9b3c08
>   schemas:
>     Health:
>       type: object
>       additionalProperties: false
>       required:
>         - status
>       properties:
>         status:
>           type: string
>           enum:
>             - ok
>     Me:
>       type: object
>       additionalProperties: false
>       required:
>         - credential_id
>         - pms_name
>         - environment
>         - scopes
>       properties:
>         credential_id:
>           type: string
>           format: uuid
>           description: The public ID of the PMS credential that made the call. Not a secret.
>         pms_name:
>           type: string
>           description: Your PMS, as Tatallo knows it.
>         environment:
>           type: string
>           enum:
>             - staging
>             - production
>             - development
>           description: The environment the key belongs to. `development` is Tatallo-internal.
>         scopes:
>           type: array
>           items:
>             type: string
>             enum:
>               - properties:read
>           description: What the key may do. `properties:read` lists and reads properties.
>     Property:
>       type: object
>       additionalProperties: false
>       required:
>         - id
>         - name
>         - timezone
>         - status
>         - country
>         - city
>         - max_guests
>         - currency
>         - updated_at
>       properties:
>         id:
>           type: string
>           format: uuid
>           description: |
>             The property's permanent, opaque identifier. Store it once in your mapping table: it
>             never changes meaning. It is an identifier, not a credential: knowing it grants
>             nothing.
>         name:
>           type: string
>           description: The property's name on Tatallo.
>         timezone:
>           type:
>             - string
>             - "null"
>           description: The IANA time zone of the property (for example `Europe/Rome`). Interpret stay dates and check-in times in it. May be `null` only while the property is `pending`.
>           example: Europe/Rome
>         status:
>           type: string
>           enum:
>             - active
>             - inactive
>             - pending
>           description: |
>             Whether the property can sell: `active` can; `inactive` was suspended and cannot;
>             `pending` is not live yet.
>         country:
>           type: string
>           description: The property's country, by name.
>         city:
>           type: string
>         max_guests:
>           type: integer
>           minimum: 1
>           description: The most guests the property sleeps.
>         currency:
>           type: string
>           pattern: ^[A-Z]{3}$
>           description: The property's currency, ISO 4217.
>         updated_at:
>           type: string
>           format: date-time
>           description: When the property last changed, ISO 8601 in UTC.
>     PageInfo:
>       type: object
>       additionalProperties: false
>       required:
>         - next_cursor
>       properties:
>         next_cursor:
>           type:
>             - string
>             - "null"
>           description: Pass it as `cursor` to get the next page. `null` on the last page.
>     PropertyList:
>       type: object
>       additionalProperties: false
>       required:
>         - data
>         - page
>       properties:
>         data:
>           type: array
>           items:
>             $ref: "#/components/schemas/Property"
>         page:
>           $ref: "#/components/schemas/PageInfo"
>     Error:
>       type: object
>       additionalProperties: false
>       required:
>         - error
>       description: |
>         The one error shape. Branch on `code`: `unauthorized` (401), `insufficient_scope` (403),
>         `property_not_found` (404), `invalid_cursor` (400), `invalid_limit` (400),
>         `rate_limited` (429). `message` is English and may change; codes never do.
>       properties:
>         error:
>           type: object
>           additionalProperties: false
>           required:
>             - code
>             - message
>             - request_id
>           properties:
>             code:
>               type: string
>               description: A stable, snake_case error code.
>             message:
>               type: string
>               description: An English explanation for people. May change; never branch on it.
>             request_id:
>               type: string
>               format: uuid
>               description: The same value as the `X-Request-Id` header.
>     UnauthorizedError:
>       allOf:
>         - $ref: "#/components/schemas/Error"
>         - type: object
>           properties:
>             error:
>               type: object
>               properties:
>                 code:
>                   const: unauthorized
>     InsufficientScopeError:
>       allOf:
>         - $ref: "#/components/schemas/Error"
>         - type: object
>           properties:
>             error:
>               type: object
>               properties:
>                 code:
>                   const: insufficient_scope
>     PropertyNotFoundError:
>       allOf:
>         - $ref: "#/components/schemas/Error"
>         - type: object
>           properties:
>             error:
>               type: object
>               properties:
>                 code:
>                   const: property_not_found
>     InvalidListQueryError:
>       allOf:
>         - $ref: "#/components/schemas/Error"
>         - type: object
>           properties:
>             error:
>               type: object
>               properties:
>                 code:
>                   enum:
>                     - invalid_limit
>                     - invalid_cursor
>     RateLimitedError:
>       allOf:
>         - $ref: "#/components/schemas/Error"
>         - type: object
>           properties:
>             error:
>               type: object
>               properties:
>                 code:
>                   const: rate_limited
> ```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.