{
  "openapi": "3.1.0",
  "info": {
    "title": "vFound API",
    "version": "1.0.0",
    "summary": "Lost & Found, Parcels, Checkroom, Equipment and Visitors for front desks.",
    "description": "Every plan includes the API. Create a key in Settings, For developers, choose its scopes, and send it as a Bearer token. Each operation names the scope it needs. Changes accept an Idempotency-Key header for safe retries. The reference with examples is at https://vfound.io/developers.",
    "termsOfService": "https://vfound.io/terms",
    "contact": {
      "name": "vFound",
      "url": "https://vfound.io/developers",
      "email": "armaan@vfound.io"
    }
  },
  "servers": [
    {
      "url": "https://vfound.io/api/v1"
    }
  ],
  "security": [
    {
      "apiKey": []
    }
  ],
  "tags": [
    {
      "name": "Lost & Found"
    },
    {
      "name": "Parcels"
    },
    {
      "name": "Checkroom"
    },
    {
      "name": "Equipment"
    },
    {
      "name": "Visitors"
    },
    {
      "name": "People"
    },
    {
      "name": "Webhooks"
    }
  ],
  "paths": {
    "/items": {
      "get": {
        "operationId": "listItems",
        "summary": "List found items",
        "tags": [
          "Lost & Found"
        ],
        "security": [
          {
            "apiKey": [
              "items:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "in_care",
                "claimed",
                "expired",
                "donated",
                "disposed",
                "trash"
              ]
            }
          },
          {
            "name": "updated_since",
            "in": "query",
            "description": "Only records changed at or after this time.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Words in the title, description, brand, colour or tags.",
            "schema": {
              "type": "string",
              "maxLength": 120
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "per_page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Item"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "data",
                    "meta"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields, or a conflict with the record's state (see code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createItem",
        "summary": "Add a found item",
        "tags": [
          "Lost & Found"
        ],
        "security": [
          {
            "apiKey": [
              "items:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Send any unique value to make a retry safe: the same key and body within 24 hours returns the first answer instead of running twice.",
            "schema": {
              "type": "string",
              "maxLength": 191
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "maxLength": 191
                  },
                  "category": {
                    "oneOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "integer"
                      }
                    ],
                    "description": "A name from GET /categories, or its id."
                  },
                  "found_date": {
                    "type": "string",
                    "format": "date"
                  },
                  "found_time": {
                    "type": "string",
                    "description": "HH:MM"
                  },
                  "keep_until": {
                    "type": "string",
                    "format": "date"
                  },
                  "location": {
                    "type": "string",
                    "maxLength": 191
                  },
                  "description": {
                    "type": "string",
                    "maxLength": 2000
                  },
                  "colour": {
                    "type": "string",
                    "maxLength": 60
                  },
                  "brand": {
                    "type": "string",
                    "maxLength": 80
                  },
                  "tags": {
                    "oneOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      }
                    ],
                    "description": "Comma-separated, or a list."
                  },
                  "value_band": {
                    "type": "string",
                    "enum": [
                      "unknown",
                      "low",
                      "medium",
                      "high"
                    ]
                  },
                  "notes": {
                    "type": "string",
                    "description": "Staff only.",
                    "maxLength": 10000
                  },
                  "photo_public": {
                    "type": "boolean"
                  },
                  "photo": {
                    "type": "string",
                    "description": "A base64 data URL up to 8 MB. Not checked by vFound AI's privacy guard: set photo_public to false for any photo showing personal details."
                  }
                },
                "required": [
                  "title",
                  "category"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Item"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields, or a conflict with the record's state (see code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/items/{id}": {
      "get": {
        "operationId": "getItem",
        "summary": "Get a found item",
        "tags": [
          "Lost & Found"
        ],
        "security": [
          {
            "apiKey": [
              "items:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Item"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found at this venue.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "updateItem",
        "summary": "Update a found item",
        "tags": [
          "Lost & Found"
        ],
        "security": [
          {
            "apiKey": [
              "items:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Send any unique value to make a retry safe: the same key and body within 24 hours returns the first answer instead of running twice.",
            "schema": {
              "type": "string",
              "maxLength": 191
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "maxLength": 191
                  },
                  "category": {
                    "oneOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "integer"
                      }
                    ],
                    "description": "A name from GET /categories, or its id."
                  },
                  "location": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "description": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "colour": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "brand": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "tags": {
                    "oneOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      }
                    ],
                    "description": "Comma-separated, or a list."
                  },
                  "value_band": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "enum": [
                      "unknown",
                      "low",
                      "medium",
                      "high",
                      null
                    ]
                  },
                  "notes": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "photo_public": {
                    "type": "boolean"
                  },
                  "keep_until": {
                    "type": "string",
                    "format": "date"
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "in_care",
                      "expired",
                      "donated",
                      "disposed",
                      "trash"
                    ]
                  }
                },
                "required": [],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Item"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found at this venue.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields, or a conflict with the record's state (see code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/categories": {
      "get": {
        "operationId": "listCategories",
        "summary": "List item categories",
        "tags": [
          "Lost & Found"
        ],
        "security": [
          {
            "apiKey": [
              "items:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/claims": {
      "get": {
        "operationId": "listClaims",
        "summary": "List claims",
        "tags": [
          "Lost & Found"
        ],
        "security": [
          {
            "apiKey": [
              "claims:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "unread",
                "open",
                "accepted",
                "awaiting_information",
                "ready_for_pickup",
                "ready_for_shipment",
                "shipped",
                "closed",
                "rejected"
              ]
            }
          },
          {
            "name": "updated_since",
            "in": "query",
            "description": "Only records changed at or after this time.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "per_page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Claim"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "data",
                    "meta"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields, or a conflict with the record's state (see code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/claims/{id}": {
      "get": {
        "operationId": "getClaim",
        "summary": "Get a claim",
        "tags": [
          "Lost & Found"
        ],
        "security": [
          {
            "apiKey": [
              "claims:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The claim's reference."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Claim"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found at this venue.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/lost-reports": {
      "get": {
        "operationId": "listLostReports",
        "summary": "List lost reports",
        "tags": [
          "Lost & Found"
        ],
        "security": [
          {
            "apiKey": [
              "lost_reports:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "open",
                "closed"
              ]
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "per_page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/LostReport"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "data",
                    "meta"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields, or a conflict with the record's state (see code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/analytics": {
      "get": {
        "operationId": "getAnalytics",
        "summary": "Lost & Found figures",
        "tags": [
          "Lost & Found"
        ],
        "security": [
          {
            "apiKey": [
              "analytics:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "days",
            "in": "query",
            "schema": {
              "type": "integer",
              "enum": [
                7,
                30,
                90,
                365
              ],
              "default": 30
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Analytics"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields, or a conflict with the record's state (see code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/parcels": {
      "get": {
        "operationId": "listParcels",
        "summary": "List parcels",
        "tags": [
          "Parcels"
        ],
        "security": [
          {
            "apiKey": [
              "parcels:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "waiting",
                "collected",
                "returned"
              ]
            }
          },
          {
            "name": "updated_since",
            "in": "query",
            "description": "Only records changed at or after this time.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Part of the recipient's name or unit, the tracking number or sender, or the exact pickup code.",
            "schema": {
              "type": "string",
              "maxLength": 120
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "per_page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Parcel"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "data",
                    "meta"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields, or a conflict with the record's state (see code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createParcel",
        "summary": "Log a parcel",
        "tags": [
          "Parcels"
        ],
        "security": [
          {
            "apiKey": [
              "parcels:write"
            ]
          }
        ],
        "description": "Goes through the same matching, email and history as the desk. Refused with tracking_duplicate when a waiting parcel already has that tracking number.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Send any unique value to make a retry safe: the same key and body within 24 hours returns the first answer instead of running twice.",
            "schema": {
              "type": "string",
              "maxLength": 191
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "recipient_email": {
                    "type": "string",
                    "format": "email",
                    "description": "Matches the people list. Give this or recipient_name."
                  },
                  "recipient_name": {
                    "type": "string",
                    "maxLength": 120
                  },
                  "unit": {
                    "type": "string",
                    "maxLength": 60
                  },
                  "carrier": {
                    "type": "string",
                    "maxLength": 60
                  },
                  "tracking": {
                    "type": "string",
                    "maxLength": 80
                  },
                  "sender": {
                    "type": "string",
                    "maxLength": 120
                  },
                  "shelf": {
                    "type": "string",
                    "maxLength": 60
                  },
                  "notify": {
                    "type": "boolean",
                    "description": "Email the recipient their pickup code now. Defaults to true."
                  }
                },
                "required": [],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Parcel"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields, or a conflict with the record's state (see code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/parcels/{id}": {
      "get": {
        "operationId": "getParcel",
        "summary": "Get a parcel",
        "tags": [
          "Parcels"
        ],
        "security": [
          {
            "apiKey": [
              "parcels:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Parcel"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found at this venue.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/parcels/{id}/collect": {
      "post": {
        "operationId": "collectParcel",
        "summary": "Hand a parcel over",
        "tags": [
          "Parcels"
        ],
        "security": [
          {
            "apiKey": [
              "parcels:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Send any unique value to make a retry safe: the same key and body within 24 hours returns the first answer instead of running twice.",
            "schema": {
              "type": "string",
              "maxLength": 191
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "collected_by": {
                    "type": "string",
                    "description": "Who collected it.",
                    "maxLength": 120
                  },
                  "signature": {
                    "type": "string",
                    "description": "A PNG data URL of their signature."
                  }
                },
                "required": [
                  "collected_by"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Parcel"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found at this venue.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields, or a conflict with the record's state (see code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/parcels/{id}/return": {
      "post": {
        "operationId": "returnParcel",
        "summary": "Return a parcel to the sender",
        "tags": [
          "Parcels"
        ],
        "security": [
          {
            "apiKey": [
              "parcels:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Send any unique value to make a retry safe: the same key and body within 24 hours returns the first answer instead of running twice.",
            "schema": {
              "type": "string",
              "maxLength": 191
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "note": {
                    "type": "string",
                    "maxLength": 200
                  }
                },
                "required": [],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Parcel"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found at this venue.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields, or a conflict with the record's state (see code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/parcels/{id}/remind": {
      "post": {
        "operationId": "remindParcel",
        "summary": "Remind the recipient",
        "tags": [
          "Parcels"
        ],
        "security": [
          {
            "apiKey": [
              "parcels:write"
            ]
          }
        ],
        "description": "Emails the recipient a reminder to collect a waiting parcel. Refused with no_email when they have no email address.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Send any unique value to make a retry safe: the same key and body within 24 hours returns the first answer instead of running twice.",
            "schema": {
              "type": "string",
              "maxLength": 191
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Parcel"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found at this venue.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields, or a conflict with the record's state (see code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/checkroom/tickets": {
      "get": {
        "operationId": "listCheckroomTickets",
        "summary": "List checkroom tickets",
        "tags": [
          "Checkroom"
        ],
        "security": [
          {
            "apiKey": [
              "checkroom:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "in",
                "returned",
                "left",
                "moved"
              ]
            }
          },
          {
            "name": "updated_since",
            "in": "query",
            "description": "Only records changed at or after this time.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Part of the guest's name or room, the ticket number, or the exact ticket code.",
            "schema": {
              "type": "string",
              "maxLength": 120
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "per_page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CheckroomTicket"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "data",
                    "meta"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields, or a conflict with the record's state (see code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "checkIn",
        "summary": "Check something in",
        "tags": [
          "Checkroom"
        ],
        "security": [
          {
            "apiKey": [
              "checkroom:write"
            ]
          }
        ],
        "description": "Gives the next free number. Refused with capacity_full when every number is in use.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Send any unique value to make a retry safe: the same key and body within 24 hours returns the first answer instead of running twice.",
            "schema": {
              "type": "string",
              "maxLength": 191
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "kind": {
                    "type": "string",
                    "enum": [
                      "coat",
                      "bag",
                      "luggage",
                      "other"
                    ]
                  },
                  "pieces": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 20
                  },
                  "guest_name": {
                    "type": "string",
                    "maxLength": 120
                  },
                  "guest_email": {
                    "type": "string",
                    "format": "email"
                  },
                  "guest_room": {
                    "type": "string",
                    "maxLength": 60
                  },
                  "collect_by": {
                    "type": "string",
                    "format": "date-time",
                    "description": "For luggage."
                  },
                  "notes": {
                    "type": "string",
                    "maxLength": 500
                  },
                  "fee_method": {
                    "type": "string",
                    "enum": [
                      "cash",
                      "card"
                    ]
                  },
                  "language": {
                    "type": "string",
                    "enum": [
                      "en",
                      "es",
                      "fr",
                      "de",
                      "nl",
                      "it"
                    ]
                  },
                  "photo": {
                    "type": "string",
                    "description": "A base64 data URL."
                  }
                },
                "required": [
                  "kind"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/CheckroomTicket"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields, or a conflict with the record's state (see code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/checkroom/tickets/{id}": {
      "get": {
        "operationId": "getCheckroomTicket",
        "summary": "Get a checkroom ticket",
        "tags": [
          "Checkroom"
        ],
        "security": [
          {
            "apiKey": [
              "checkroom:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/CheckroomTicket"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found at this venue.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/checkroom/tickets/{id}/hand-back": {
      "post": {
        "operationId": "handBack",
        "summary": "Hand it back",
        "tags": [
          "Checkroom"
        ],
        "security": [
          {
            "apiKey": [
              "checkroom:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Send any unique value to make a retry safe: the same key and body within 24 hours returns the first answer instead of running twice.",
            "schema": {
              "type": "string",
              "maxLength": 191
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "without_ticket": {
                    "type": "boolean",
                    "description": "The guest lost their ticket and the desk checked who they are."
                  },
                  "collected_by": {
                    "type": "string",
                    "maxLength": 120
                  },
                  "signature": {
                    "type": "string",
                    "description": "A PNG data URL."
                  }
                },
                "required": [],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/CheckroomTicket"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found at this venue.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields, or a conflict with the record's state (see code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/loans": {
      "get": {
        "operationId": "listLoans",
        "summary": "List equipment handed out",
        "tags": [
          "Equipment"
        ],
        "security": [
          {
            "apiKey": [
              "loans:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "out",
                "returned",
                "lost",
                "overdue"
              ]
            }
          },
          {
            "name": "updated_since",
            "in": "query",
            "description": "Only records changed at or after this time.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Part of the borrower's name, email or reference.",
            "schema": {
              "type": "string",
              "maxLength": 120
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "per_page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Loan"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "data",
                    "meta"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields, or a conflict with the record's state (see code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "lend",
        "summary": "Hand equipment out",
        "tags": [
          "Equipment"
        ],
        "security": [
          {
            "apiKey": [
              "loans:write"
            ]
          }
        ],
        "description": "Give item_id or item_code. Refused with item_out, item_in_repair or item_retired when it cannot go out.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Send any unique value to make a retry safe: the same key and body within 24 hours returns the first answer instead of running twice.",
            "schema": {
              "type": "string",
              "maxLength": 191
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "item_id": {
                    "type": "integer"
                  },
                  "item_code": {
                    "type": "string",
                    "description": "The code on its label, or the address its QR code holds.",
                    "maxLength": 300
                  },
                  "borrower_name": {
                    "type": "string",
                    "maxLength": 120
                  },
                  "borrower_email": {
                    "type": "string",
                    "format": "email",
                    "description": "Gets a receipt with the due time."
                  },
                  "borrower_reference": {
                    "type": "string",
                    "maxLength": 80
                  },
                  "due_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Defaults to the item's usual time out."
                  },
                  "note": {
                    "type": "string",
                    "maxLength": 255
                  },
                  "language": {
                    "type": "string",
                    "enum": [
                      "en",
                      "es",
                      "fr",
                      "de",
                      "nl",
                      "it"
                    ]
                  },
                  "signature": {
                    "type": "string",
                    "description": "A PNG data URL."
                  }
                },
                "required": [
                  "borrower_name"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Loan"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields, or a conflict with the record's state (see code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/loans/{id}": {
      "get": {
        "operationId": "getLoan",
        "summary": "Get a loan",
        "tags": [
          "Equipment"
        ],
        "security": [
          {
            "apiKey": [
              "loans:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Loan"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found at this venue.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/loans/{id}/return": {
      "post": {
        "operationId": "returnLoan",
        "summary": "Take equipment back",
        "tags": [
          "Equipment"
        ],
        "security": [
          {
            "apiKey": [
              "loans:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Send any unique value to make a retry safe: the same key and body within 24 hours returns the first answer instead of running twice.",
            "schema": {
              "type": "string",
              "maxLength": 191
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "condition": {
                    "type": "string",
                    "enum": [
                      "good",
                      "damaged",
                      "incomplete"
                    ]
                  },
                  "note": {
                    "type": "string",
                    "maxLength": 500
                  },
                  "set_aside": {
                    "type": "boolean",
                    "description": "Put the item aside for repair."
                  }
                },
                "required": [],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Loan"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found at this venue.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields, or a conflict with the record's state (see code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/loans/{id}/extend": {
      "post": {
        "operationId": "extendLoan",
        "summary": "Give more time",
        "tags": [
          "Equipment"
        ],
        "security": [
          {
            "apiKey": [
              "loans:write"
            ]
          }
        ],
        "description": "Emails the borrower the new due time.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Send any unique value to make a retry safe: the same key and body within 24 hours returns the first answer instead of running twice.",
            "schema": {
              "type": "string",
              "maxLength": 191
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "due_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "The new due time, in the future."
                  }
                },
                "required": [
                  "due_at"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Loan"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found at this venue.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields, or a conflict with the record's state (see code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/loans/items": {
      "get": {
        "operationId": "listEquipment",
        "summary": "List equipment",
        "tags": [
          "Equipment"
        ],
        "security": [
          {
            "apiKey": [
              "loans:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "available",
                "out",
                "repair",
                "retired"
              ]
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Part of its name or asset tag, or the exact label code.",
            "schema": {
              "type": "string",
              "maxLength": 120
            }
          },
          {
            "name": "updated_since",
            "in": "query",
            "description": "Only records changed at or after this time.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "per_page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/EquipmentItem"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "data",
                    "meta"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields, or a conflict with the record's state (see code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createEquipment",
        "summary": "Add equipment",
        "tags": [
          "Equipment"
        ],
        "security": [
          {
            "apiKey": [
              "loans:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Send any unique value to make a retry safe: the same key and body within 24 hours returns the first answer instead of running twice.",
            "schema": {
              "type": "string",
              "maxLength": 191
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 110
                  },
                  "category": {
                    "type": "string",
                    "maxLength": 60
                  },
                  "tag": {
                    "type": "string",
                    "maxLength": 60
                  },
                  "location": {
                    "type": "string",
                    "maxLength": 120
                  },
                  "notes": {
                    "type": "string",
                    "maxLength": 500
                  },
                  "loan_hours": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 2160
                  },
                  "copies": {
                    "type": "integer",
                    "description": "Add several identical items at once, numbered.",
                    "minimum": 1,
                    "maximum": 50
                  },
                  "photo": {
                    "type": "string",
                    "description": "A base64 data URL."
                  }
                },
                "required": [
                  "name"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/EquipmentItem"
                      }
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields, or a conflict with the record's state (see code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/loans/items/{id}": {
      "get": {
        "operationId": "getEquipment",
        "summary": "Get equipment",
        "tags": [
          "Equipment"
        ],
        "security": [
          {
            "apiKey": [
              "loans:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/EquipmentItem"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found at this venue.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "updateEquipment",
        "summary": "Update equipment",
        "tags": [
          "Equipment"
        ],
        "security": [
          {
            "apiKey": [
              "loans:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Send any unique value to make a retry safe: the same key and body within 24 hours returns the first answer instead of running twice.",
            "schema": {
              "type": "string",
              "maxLength": 191
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 120
                  },
                  "category": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "tag": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "location": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "notes": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "loan_hours": {
                    "type": [
                      "integer",
                      "null"
                    ]
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "available",
                      "repair",
                      "retired"
                    ]
                  }
                },
                "required": [],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/EquipmentItem"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found at this venue.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields, or a conflict with the record's state (see code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/visitors": {
      "get": {
        "operationId": "listVisits",
        "summary": "List visits",
        "tags": [
          "Visitors"
        ],
        "security": [
          {
            "apiKey": [
              "visitors:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "expected",
                "in",
                "out",
                "cancelled",
                "missed"
              ]
            }
          },
          {
            "name": "updated_since",
            "in": "query",
            "description": "Only records changed at or after this time.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Part of the visitor's name, email or company, the host's name, or the exact pass code.",
            "schema": {
              "type": "string",
              "maxLength": 120
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "per_page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Visit"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "data",
                    "meta"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields, or a conflict with the record's state (see code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createVisit",
        "summary": "Invite or sign in a visitor",
        "tags": [
          "Visitors"
        ],
        "security": [
          {
            "apiKey": [
              "visitors:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Send any unique value to make a retry safe: the same key and body within 24 hours returns the first answer instead of running twice.",
            "schema": {
              "type": "string",
              "maxLength": 191
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "visitor_name": {
                    "type": "string",
                    "maxLength": 120
                  },
                  "visitor_email": {
                    "type": "string",
                    "format": "email",
                    "description": "Gets their pass."
                  },
                  "visitor_company": {
                    "type": "string",
                    "maxLength": 120
                  },
                  "purpose": {
                    "type": "string",
                    "maxLength": 120
                  },
                  "host_email": {
                    "type": "string",
                    "format": "email",
                    "description": "Matched to the people list; the host is told when the visitor arrives."
                  },
                  "host_name": {
                    "type": "string",
                    "maxLength": 120
                  },
                  "arriving_now": {
                    "type": "boolean",
                    "description": "Sign them in now instead of inviting them."
                  },
                  "expected_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Required unless arriving_now."
                  },
                  "language": {
                    "type": "string",
                    "enum": [
                      "en",
                      "es",
                      "fr",
                      "de",
                      "nl",
                      "it"
                    ]
                  },
                  "note": {
                    "type": "string",
                    "maxLength": 255
                  },
                  "agreed": {
                    "type": "boolean",
                    "description": "They agreed to your visitor terms."
                  }
                },
                "required": [
                  "visitor_name"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Visit"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields, or a conflict with the record's state (see code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/visitors/{id}": {
      "get": {
        "operationId": "getVisit",
        "summary": "Get a visit",
        "tags": [
          "Visitors"
        ],
        "security": [
          {
            "apiKey": [
              "visitors:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Visit"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found at this venue.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/visitors/{id}/sign-in": {
      "post": {
        "operationId": "signInVisit",
        "summary": "Sign a visitor in",
        "tags": [
          "Visitors"
        ],
        "security": [
          {
            "apiKey": [
              "visitors:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Send any unique value to make a retry safe: the same key and body within 24 hours returns the first answer instead of running twice.",
            "schema": {
              "type": "string",
              "maxLength": 191
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "agreed": {
                    "type": "boolean"
                  }
                },
                "required": [],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Visit"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found at this venue.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields, or a conflict with the record's state (see code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/visitors/{id}/sign-out": {
      "post": {
        "operationId": "signOutVisit",
        "summary": "Sign a visitor out",
        "tags": [
          "Visitors"
        ],
        "security": [
          {
            "apiKey": [
              "visitors:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Send any unique value to make a retry safe: the same key and body within 24 hours returns the first answer instead of running twice.",
            "schema": {
              "type": "string",
              "maxLength": 191
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Visit"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found at this venue.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields, or a conflict with the record's state (see code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/visitors/{id}/cancel": {
      "post": {
        "operationId": "cancelVisit",
        "summary": "Cancel an invitation",
        "tags": [
          "Visitors"
        ],
        "security": [
          {
            "apiKey": [
              "visitors:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Send any unique value to make a retry safe: the same key and body within 24 hours returns the first answer instead of running twice.",
            "schema": {
              "type": "string",
              "maxLength": 191
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Visit"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found at this venue.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields, or a conflict with the record's state (see code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/visitors/{id}/send-pass": {
      "post": {
        "operationId": "sendVisitorPass",
        "summary": "Email the pass again",
        "tags": [
          "Visitors"
        ],
        "security": [
          {
            "apiKey": [
              "visitors:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Send any unique value to make a retry safe: the same key and body within 24 hours returns the first answer instead of running twice.",
            "schema": {
              "type": "string",
              "maxLength": 191
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Visit"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found at this venue.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields, or a conflict with the record's state (see code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/people": {
      "get": {
        "operationId": "listPeople",
        "summary": "List people",
        "tags": [
          "People"
        ],
        "security": [
          {
            "apiKey": [
              "people:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "description": "Part of their name, email, unit or reference.",
            "schema": {
              "type": "string",
              "maxLength": 120
            }
          },
          {
            "name": "updated_since",
            "in": "query",
            "description": "Only records changed at or after this time.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "per_page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Person"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  },
                  "required": [
                    "data",
                    "meta"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields, or a conflict with the record's state (see code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createPerson",
        "summary": "Add a person",
        "tags": [
          "People"
        ],
        "security": [
          {
            "apiKey": [
              "people:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Send any unique value to make a retry safe: the same key and body within 24 hours returns the first answer instead of running twice.",
            "schema": {
              "type": "string",
              "maxLength": 191
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 120
                  },
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "unit": {
                    "type": "string",
                    "maxLength": 60
                  },
                  "reference": {
                    "type": "string",
                    "maxLength": 60
                  },
                  "language": {
                    "type": "string",
                    "enum": [
                      "en",
                      "es",
                      "fr",
                      "de",
                      "nl",
                      "it"
                    ]
                  }
                },
                "required": [
                  "name"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Person"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields, or a conflict with the record's state (see code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/people/upsert": {
      "post": {
        "operationId": "upsertPeople",
        "summary": "Add or update up to 500 people",
        "tags": [
          "People"
        ],
        "security": [
          {
            "apiKey": [
              "people:write"
            ]
          }
        ],
        "description": "People whose email is already on the list are updated; the rest are added.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Send any unique value to make a retry safe: the same key and body within 24 hours returns the first answer instead of running twice.",
            "schema": {
              "type": "string",
              "maxLength": 191
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "people": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 500,
                    "items": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string",
                          "maxLength": 120
                        },
                        "email": {
                          "type": "string",
                          "format": "email"
                        },
                        "unit": {
                          "type": "string",
                          "maxLength": 60
                        },
                        "reference": {
                          "type": "string",
                          "maxLength": 60
                        },
                        "language": {
                          "type": "string",
                          "enum": [
                            "en",
                            "es",
                            "fr",
                            "de",
                            "nl",
                            "it"
                          ]
                        }
                      },
                      "required": [
                        "name"
                      ],
                      "additionalProperties": false
                    }
                  }
                },
                "required": [
                  "people"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "added": {
                          "type": "integer"
                        },
                        "updated": {
                          "type": "integer"
                        },
                        "skipped": {
                          "type": "integer"
                        }
                      },
                      "required": [
                        "added",
                        "updated",
                        "skipped"
                      ],
                      "additionalProperties": false
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields, or a conflict with the record's state (see code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/people/{id}": {
      "get": {
        "operationId": "getPerson",
        "summary": "Get a person",
        "tags": [
          "People"
        ],
        "security": [
          {
            "apiKey": [
              "people:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Person"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found at this venue.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "updatePerson",
        "summary": "Update a person",
        "tags": [
          "People"
        ],
        "security": [
          {
            "apiKey": [
              "people:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Send any unique value to make a retry safe: the same key and body within 24 hours returns the first answer instead of running twice.",
            "schema": {
              "type": "string",
              "maxLength": 191
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 120
                  },
                  "email": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "email"
                  },
                  "unit": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 60
                  },
                  "reference": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 60
                  },
                  "language": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "enum": [
                      "en",
                      "es",
                      "fr",
                      "de",
                      "nl",
                      "it"
                    ]
                  }
                },
                "required": [],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Person"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found at this venue.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields, or a conflict with the record's state (see code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deletePerson",
        "summary": "Remove a person",
        "tags": [
          "People"
        ],
        "security": [
          {
            "apiKey": [
              "people:write"
            ]
          }
        ],
        "description": "Their parcels, visits and loans keep their name but are no longer linked.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Send any unique value to make a retry safe: the same key and body within 24 hours returns the first answer instead of running twice.",
            "schema": {
              "type": "string",
              "maxLength": 191
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deleted": {
                      "type": "boolean",
                      "const": true
                    }
                  },
                  "required": [
                    "deleted"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found at this venue.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields, or a conflict with the record's state (see code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/webhooks": {
      "get": {
        "operationId": "listWebhooks",
        "summary": "List webhook addresses",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "apiKey": [
              "webhooks:manage"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Webhook"
                      }
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createWebhook",
        "summary": "Subscribe an address to events",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "apiKey": [
              "webhooks:manage"
            ]
          }
        ],
        "description": "For tools such as Zapier, Make, n8n and Power Automate. Up to 25 addresses per venue.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Send any unique value to make a retry safe: the same key and body within 24 hours returns the first answer instead of running twice.",
            "schema": {
              "type": "string",
              "maxLength": 191
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "description": "A public HTTPS address on port 443.",
                    "maxLength": 500
                  },
                  "events": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                      "type": "string",
                      "enum": [
                        "item.created",
                        "item.updated",
                        "claim.created",
                        "claim.status_changed",
                        "lost_report.created",
                        "parcel.logged",
                        "parcel.updated",
                        "parcel.reminded",
                        "parcel.collected",
                        "parcel.returned",
                        "checkroom.checked_in",
                        "checkroom.handed_back",
                        "checkroom.left",
                        "loan.lent",
                        "loan.due_soon",
                        "loan.overdue",
                        "loan.extended",
                        "loan.returned",
                        "loan.lost",
                        "visit.expected",
                        "visit.signed_in",
                        "visit.host_confirmed",
                        "visit.signed_out",
                        "visit.cancelled"
                      ]
                    }
                  }
                },
                "required": [
                  "url",
                  "events"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/NewWebhook"
                    }
                  },
                  "required": [
                    "data"
                  ],
                  "additionalProperties": false
                }
              }
            },
            "headers": {
              "Location": {
                "description": "The path of the new webhook subscription. Send DELETE to this path to unsubscribe.",
                "schema": {
                  "type": "string",
                  "example": "/api/v1/webhooks/42"
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields, or a conflict with the record's state (see code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/webhooks/{id}": {
      "delete": {
        "operationId": "deleteWebhook",
        "summary": "Remove a webhook address",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "apiKey": [
              "webhooks:manage"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Send any unique value to make a retry safe: the same key and body within 24 hours returns the first answer instead of running twice.",
            "schema": {
              "type": "string",
              "maxLength": 191
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deleted": {
                      "type": "boolean",
                      "const": true
                    }
                  },
                  "required": [
                    "deleted"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key lacks the scope, the product is not open, or the venue is paused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests a minute for this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found at this venue.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid fields, or a conflict with the record's state (see code).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "webhooks": {
    "item.created": {
      "post": {
        "summary": "item.created",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Event"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "type": {
                        "const": "item.created"
                      },
                      "data": {
                        "$ref": "#/components/schemas/Item"
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx answer confirms the delivery."
          }
        }
      }
    },
    "item.updated": {
      "post": {
        "summary": "item.updated",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Event"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "type": {
                        "const": "item.updated"
                      },
                      "data": {
                        "$ref": "#/components/schemas/Item"
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx answer confirms the delivery."
          }
        }
      }
    },
    "claim.created": {
      "post": {
        "summary": "claim.created",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Event"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "type": {
                        "const": "claim.created"
                      },
                      "data": {
                        "$ref": "#/components/schemas/Claim"
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx answer confirms the delivery."
          }
        }
      }
    },
    "claim.status_changed": {
      "post": {
        "summary": "claim.status_changed",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Event"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "type": {
                        "const": "claim.status_changed"
                      },
                      "data": {
                        "$ref": "#/components/schemas/Claim"
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx answer confirms the delivery."
          }
        }
      }
    },
    "lost_report.created": {
      "post": {
        "summary": "lost_report.created",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Event"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "type": {
                        "const": "lost_report.created"
                      },
                      "data": {
                        "$ref": "#/components/schemas/LostReport"
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx answer confirms the delivery."
          }
        }
      }
    },
    "parcel.logged": {
      "post": {
        "summary": "parcel.logged",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Event"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "type": {
                        "const": "parcel.logged"
                      },
                      "data": {
                        "$ref": "#/components/schemas/Parcel"
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx answer confirms the delivery."
          }
        }
      }
    },
    "parcel.updated": {
      "post": {
        "summary": "parcel.updated",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Event"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "type": {
                        "const": "parcel.updated"
                      },
                      "data": {
                        "$ref": "#/components/schemas/Parcel"
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx answer confirms the delivery."
          }
        }
      }
    },
    "parcel.reminded": {
      "post": {
        "summary": "parcel.reminded",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Event"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "type": {
                        "const": "parcel.reminded"
                      },
                      "data": {
                        "$ref": "#/components/schemas/Parcel"
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx answer confirms the delivery."
          }
        }
      }
    },
    "parcel.collected": {
      "post": {
        "summary": "parcel.collected",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Event"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "type": {
                        "const": "parcel.collected"
                      },
                      "data": {
                        "$ref": "#/components/schemas/Parcel"
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx answer confirms the delivery."
          }
        }
      }
    },
    "parcel.returned": {
      "post": {
        "summary": "parcel.returned",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Event"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "type": {
                        "const": "parcel.returned"
                      },
                      "data": {
                        "$ref": "#/components/schemas/Parcel"
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx answer confirms the delivery."
          }
        }
      }
    },
    "checkroom.checked_in": {
      "post": {
        "summary": "checkroom.checked_in",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Event"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "type": {
                        "const": "checkroom.checked_in"
                      },
                      "data": {
                        "$ref": "#/components/schemas/CheckroomTicket"
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx answer confirms the delivery."
          }
        }
      }
    },
    "checkroom.handed_back": {
      "post": {
        "summary": "checkroom.handed_back",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Event"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "type": {
                        "const": "checkroom.handed_back"
                      },
                      "data": {
                        "$ref": "#/components/schemas/CheckroomTicket"
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx answer confirms the delivery."
          }
        }
      }
    },
    "checkroom.left": {
      "post": {
        "summary": "checkroom.left",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Event"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "type": {
                        "const": "checkroom.left"
                      },
                      "data": {
                        "$ref": "#/components/schemas/CheckroomTicket"
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx answer confirms the delivery."
          }
        }
      }
    },
    "loan.lent": {
      "post": {
        "summary": "loan.lent",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Event"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "type": {
                        "const": "loan.lent"
                      },
                      "data": {
                        "$ref": "#/components/schemas/Loan"
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx answer confirms the delivery."
          }
        }
      }
    },
    "loan.due_soon": {
      "post": {
        "summary": "loan.due_soon",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Event"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "type": {
                        "const": "loan.due_soon"
                      },
                      "data": {
                        "$ref": "#/components/schemas/Loan"
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx answer confirms the delivery."
          }
        }
      }
    },
    "loan.overdue": {
      "post": {
        "summary": "loan.overdue",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Event"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "type": {
                        "const": "loan.overdue"
                      },
                      "data": {
                        "$ref": "#/components/schemas/Loan"
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx answer confirms the delivery."
          }
        }
      }
    },
    "loan.extended": {
      "post": {
        "summary": "loan.extended",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Event"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "type": {
                        "const": "loan.extended"
                      },
                      "data": {
                        "$ref": "#/components/schemas/Loan"
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx answer confirms the delivery."
          }
        }
      }
    },
    "loan.returned": {
      "post": {
        "summary": "loan.returned",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Event"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "type": {
                        "const": "loan.returned"
                      },
                      "data": {
                        "$ref": "#/components/schemas/Loan"
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx answer confirms the delivery."
          }
        }
      }
    },
    "loan.lost": {
      "post": {
        "summary": "loan.lost",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Event"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "type": {
                        "const": "loan.lost"
                      },
                      "data": {
                        "$ref": "#/components/schemas/Loan"
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx answer confirms the delivery."
          }
        }
      }
    },
    "visit.expected": {
      "post": {
        "summary": "visit.expected",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Event"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "type": {
                        "const": "visit.expected"
                      },
                      "data": {
                        "$ref": "#/components/schemas/Visit"
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx answer confirms the delivery."
          }
        }
      }
    },
    "visit.signed_in": {
      "post": {
        "summary": "visit.signed_in",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Event"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "type": {
                        "const": "visit.signed_in"
                      },
                      "data": {
                        "$ref": "#/components/schemas/Visit"
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx answer confirms the delivery."
          }
        }
      }
    },
    "visit.host_confirmed": {
      "post": {
        "summary": "visit.host_confirmed",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Event"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "type": {
                        "const": "visit.host_confirmed"
                      },
                      "data": {
                        "$ref": "#/components/schemas/Visit"
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx answer confirms the delivery."
          }
        }
      }
    },
    "visit.signed_out": {
      "post": {
        "summary": "visit.signed_out",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Event"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "type": {
                        "const": "visit.signed_out"
                      },
                      "data": {
                        "$ref": "#/components/schemas/Visit"
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx answer confirms the delivery."
          }
        }
      }
    },
    "visit.cancelled": {
      "post": {
        "summary": "visit.cancelled",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Event"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "type": {
                        "const": "visit.cancelled"
                      },
                      "data": {
                        "$ref": "#/components/schemas/Visit"
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx answer confirms the delivery."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "A venue key, vf_live_…, from Settings, For developers. Each operation lists the scope it needs."
      }
    },
    "schemas": {
      "Item": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "The item's id (a UUID)."
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "in_care",
              "claimed",
              "expired",
              "donated",
              "disposed",
              "trash"
            ],
            "description": "in_care means still held at the venue."
          },
          "category": {
            "type": [
              "string",
              "null"
            ]
          },
          "found_date": {
            "type": "string",
            "format": "date"
          },
          "found_time": {
            "type": [
              "string",
              "null"
            ],
            "description": "HH:MM"
          },
          "keep_until": {
            "type": "string",
            "format": "date"
          },
          "location": {
            "type": [
              "string",
              "null"
            ]
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "colour": {
            "type": [
              "string",
              "null"
            ]
          },
          "brand": {
            "type": [
              "string",
              "null"
            ]
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "value_band": {
            "type": [
              "string",
              "null"
            ]
          },
          "photo_public": {
            "type": "boolean",
            "description": "Whether the photo is shown to guests."
          },
          "photo_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "Only when the photo is public."
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "title",
          "status",
          "category",
          "found_date",
          "found_time",
          "keep_until",
          "location",
          "description",
          "colour",
          "brand",
          "tags",
          "value_band",
          "photo_public",
          "photo_url",
          "created_at",
          "updated_at"
        ],
        "additionalProperties": false,
        "description": "A found item (vFound Lost & Found)."
      },
      "Claim": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The claim's reference."
          },
          "status": {
            "type": "string",
            "enum": [
              "unread",
              "open",
              "accepted",
              "awaiting_information",
              "ready_for_pickup",
              "ready_for_shipment",
              "shipped",
              "closed",
              "rejected"
            ]
          },
          "item": {
            "type": "object",
            "properties": {
              "id": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "uuid"
              },
              "title": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "id",
              "title"
            ],
            "additionalProperties": false
          },
          "claimant": {
            "type": "object",
            "properties": {
              "first_name": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "last_name": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "email": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "email"
              },
              "phone": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "first_name",
              "last_name",
              "email",
              "phone"
            ],
            "additionalProperties": false
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "place_lost": {
            "type": [
              "string",
              "null"
            ]
          },
          "date_lost": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "language": {
            "type": "string",
            "enum": [
              "en",
              "es",
              "fr",
              "de",
              "nl",
              "it"
            ]
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "status",
          "item",
          "claimant",
          "description",
          "place_lost",
          "date_lost",
          "language",
          "created_at",
          "updated_at"
        ],
        "additionalProperties": false,
        "description": "A guest's claim for a found item."
      },
      "LostReport": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The report's reference."
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "closed"
            ]
          },
          "title": {
            "type": [
              "string",
              "null"
            ]
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "category": {
            "type": [
              "string",
              "null"
            ]
          },
          "colour_brand": {
            "type": [
              "string",
              "null"
            ]
          },
          "place_lost": {
            "type": [
              "string",
              "null"
            ]
          },
          "date_lost": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "reporter": {
            "type": "object",
            "properties": {
              "first_name": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "last_name": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "email": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "email"
              },
              "phone": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "first_name",
              "last_name",
              "email",
              "phone"
            ],
            "additionalProperties": false
          },
          "find_my_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "The guest's private page for this report."
          },
          "language": {
            "type": "string",
            "enum": [
              "en",
              "es",
              "fr",
              "de",
              "nl",
              "it"
            ]
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "status",
          "title",
          "description",
          "category",
          "colour_brand",
          "place_lost",
          "date_lost",
          "reporter",
          "find_my_url",
          "language",
          "created_at"
        ],
        "additionalProperties": false,
        "description": "A guest's report of something they lost."
      },
      "Analytics": {
        "type": "object",
        "description": "Lost & Found figures for the period: items logged and returned, return rate, median days to return, claims, what happened to items, categories and hotspots.",
        "properties": {
          "from": {
            "type": "string",
            "format": "date"
          },
          "to": {
            "type": "string",
            "format": "date"
          },
          "logged": {
            "type": "integer"
          },
          "returned": {
            "type": "integer"
          },
          "return_rate": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Percent."
          },
          "median_days_to_return": {
            "type": [
              "number",
              "null"
            ]
          },
          "returns_completed": {
            "type": "integer"
          },
          "claims": {
            "type": "object"
          },
          "disposition": {
            "type": "object"
          },
          "categories": {
            "type": "array"
          },
          "hotspots": {
            "type": "array"
          }
        },
        "additionalProperties": true
      },
      "Parcel": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "status": {
            "type": "string",
            "enum": [
              "waiting",
              "collected",
              "returned"
            ]
          },
          "recipient": {
            "type": "object",
            "properties": {
              "name": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "email": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "email"
              },
              "unit": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "reference": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "name",
              "email",
              "unit",
              "reference"
            ],
            "additionalProperties": false
          },
          "carrier": {
            "type": [
              "string",
              "null"
            ]
          },
          "tracking": {
            "type": [
              "string",
              "null"
            ]
          },
          "sender": {
            "type": [
              "string",
              "null"
            ]
          },
          "size": {
            "type": [
              "string",
              "null"
            ]
          },
          "shelf": {
            "type": [
              "string",
              "null"
            ]
          },
          "pickup_code": {
            "type": [
              "string",
              "null"
            ],
            "description": "The code the recipient shows at the desk, while the parcel waits."
          },
          "notified_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "collected_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "collected_by": {
            "type": [
              "string",
              "null"
            ]
          },
          "returned_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "status",
          "recipient",
          "carrier",
          "tracking",
          "sender",
          "size",
          "shelf",
          "pickup_code",
          "notified_at",
          "collected_at",
          "collected_by",
          "returned_at",
          "created_at",
          "updated_at"
        ],
        "additionalProperties": false,
        "description": "A parcel at the desk (vFound Parcels)."
      },
      "CheckroomTicket": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "in",
              "returned",
              "left",
              "moved"
            ]
          },
          "number": {
            "type": [
              "integer",
              "null"
            ]
          },
          "kind": {
            "type": "string",
            "enum": [
              "coat",
              "bag",
              "luggage",
              "other"
            ]
          },
          "pieces": {
            "type": "integer"
          },
          "guest": {
            "type": "object",
            "properties": {
              "name": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "email": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "email"
              },
              "room": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "name",
              "email",
              "room"
            ],
            "additionalProperties": false
          },
          "fee": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "amount": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "In cents."
              },
              "method": {
                "type": "string",
                "enum": [
                  "cash",
                  "card"
                ]
              }
            },
            "required": [
              "amount",
              "method"
            ],
            "additionalProperties": false
          },
          "collect_by": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "For luggage: when the guest will collect it."
          },
          "checked_in_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "returned_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "without_ticket": {
            "type": "boolean",
            "description": "Handed back without the ticket, after checking who the guest is."
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "status",
          "number",
          "kind",
          "pieces",
          "guest",
          "fee",
          "collect_by",
          "checked_in_at",
          "returned_at",
          "without_ticket",
          "created_at"
        ],
        "additionalProperties": false,
        "description": "A checkroom ticket for coats, bags or luggage (vFound Checkroom)."
      },
      "Loan": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "status": {
            "type": "string",
            "enum": [
              "out",
              "returned",
              "lost"
            ]
          },
          "overdue": {
            "type": "boolean"
          },
          "item": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "id": {
                "type": "integer"
              },
              "name": {
                "type": "string"
              },
              "tag": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "code": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "id",
              "name",
              "tag",
              "code"
            ],
            "additionalProperties": false
          },
          "borrower": {
            "type": "object",
            "properties": {
              "name": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "email": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "email"
              },
              "reference": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "name",
              "email",
              "reference"
            ],
            "additionalProperties": false
          },
          "lent_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "due_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "returned_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "return_condition": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "good",
              "damaged",
              "incomplete",
              null
            ]
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "status",
          "overdue",
          "item",
          "borrower",
          "lent_at",
          "due_at",
          "returned_at",
          "return_condition",
          "created_at",
          "updated_at"
        ],
        "additionalProperties": false,
        "description": "Equipment handed out to someone (vFound Equipment)."
      },
      "EquipmentItem": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "available",
              "out",
              "repair",
              "retired"
            ]
          },
          "category": {
            "type": [
              "string",
              "null"
            ]
          },
          "tag": {
            "type": [
              "string",
              "null"
            ],
            "description": "Your asset tag."
          },
          "code": {
            "type": [
              "string",
              "null"
            ],
            "description": "The code on its vFound label."
          },
          "label_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "The address its label's QR code holds."
          },
          "location": {
            "type": [
              "string",
              "null"
            ]
          },
          "notes": {
            "type": [
              "string",
              "null"
            ]
          },
          "loan_hours": {
            "type": [
              "integer",
              "null"
            ],
            "description": "How many hours it usually goes out for."
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "name",
          "status",
          "category",
          "tag",
          "code",
          "label_url",
          "location",
          "notes",
          "loan_hours",
          "created_at",
          "updated_at"
        ],
        "additionalProperties": false,
        "description": "A thing the desk hands out (vFound Equipment)."
      },
      "Visit": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "status": {
            "type": "string",
            "enum": [
              "expected",
              "in",
              "out",
              "cancelled",
              "missed"
            ]
          },
          "visitor": {
            "type": "object",
            "properties": {
              "name": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "email": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "email"
              },
              "company": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "name",
              "email",
              "company"
            ],
            "additionalProperties": false
          },
          "host": {
            "type": "object",
            "properties": {
              "name": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "email": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "email"
              },
              "confirmed": {
                "type": "boolean"
              }
            },
            "required": [
              "name",
              "email",
              "confirmed"
            ],
            "additionalProperties": false
          },
          "purpose": {
            "type": [
              "string",
              "null"
            ]
          },
          "pass_code": {
            "type": [
              "string",
              "null"
            ],
            "description": "The code on the visitor's pass, while expected or signed in."
          },
          "self_service": {
            "type": "boolean",
            "description": "Signed in from the venue's QR sign."
          },
          "expected_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "signed_in_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "signed_out_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "agreed_to_terms": {
            "type": "boolean"
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "status",
          "visitor",
          "host",
          "purpose",
          "pass_code",
          "self_service",
          "expected_at",
          "signed_in_at",
          "signed_out_at",
          "agreed_to_terms",
          "created_at",
          "updated_at"
        ],
        "additionalProperties": false,
        "description": "A visit (vFound Visitors)."
      },
      "Person": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "email": {
            "type": [
              "string",
              "null"
            ],
            "format": "email"
          },
          "unit": {
            "type": [
              "string",
              "null"
            ]
          },
          "reference": {
            "type": [
              "string",
              "null"
            ]
          },
          "language": {
            "type": "string",
            "enum": [
              "en",
              "es",
              "fr",
              "de",
              "nl",
              "it"
            ]
          },
          "active": {
            "type": "boolean"
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "name",
          "email",
          "unit",
          "reference",
          "language",
          "active",
          "created_at",
          "updated_at"
        ],
        "additionalProperties": false,
        "description": "Someone on the venue's people list, shared by Parcels, Visitors and Equipment."
      },
      "Webhook": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "item.created",
                "item.updated",
                "claim.created",
                "claim.status_changed",
                "lost_report.created",
                "parcel.logged",
                "parcel.updated",
                "parcel.reminded",
                "parcel.collected",
                "parcel.returned",
                "checkroom.checked_in",
                "checkroom.handed_back",
                "checkroom.left",
                "loan.lent",
                "loan.due_soon",
                "loan.overdue",
                "loan.extended",
                "loan.returned",
                "loan.lost",
                "visit.expected",
                "visit.signed_in",
                "visit.host_confirmed",
                "visit.signed_out",
                "visit.cancelled"
              ]
            }
          },
          "enabled": {
            "type": "boolean",
            "description": "False once paused after 15 failed deliveries in a row."
          },
          "last_delivered_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "url",
          "events",
          "enabled",
          "last_delivered_at",
          "created_at"
        ],
        "additionalProperties": false,
        "description": "An address that receives events."
      },
      "NewWebhook": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "item.created",
                "item.updated",
                "claim.created",
                "claim.status_changed",
                "lost_report.created",
                "parcel.logged",
                "parcel.updated",
                "parcel.reminded",
                "parcel.collected",
                "parcel.returned",
                "checkroom.checked_in",
                "checkroom.handed_back",
                "checkroom.left",
                "loan.lent",
                "loan.due_soon",
                "loan.overdue",
                "loan.extended",
                "loan.returned",
                "loan.lost",
                "visit.expected",
                "visit.signed_in",
                "visit.host_confirmed",
                "visit.signed_out",
                "visit.cancelled"
              ]
            }
          },
          "enabled": {
            "type": "boolean",
            "description": "False once paused after 15 failed deliveries in a row."
          },
          "last_delivered_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "secret": {
            "type": "string",
            "description": "Shown once. Signs every delivery; keep it secret."
          }
        },
        "required": [
          "id",
          "url",
          "events",
          "enabled",
          "last_delivered_at",
          "created_at",
          "secret"
        ],
        "additionalProperties": false,
        "description": "An address just subscribed, with its signing secret."
      },
      "Meta": {
        "type": "object",
        "properties": {
          "page": {
            "type": "integer"
          },
          "per_page": {
            "type": "integer"
          },
          "total": {
            "type": "integer"
          },
          "last_page": {
            "type": "integer"
          }
        },
        "required": [
          "page",
          "per_page",
          "total",
          "last_page"
        ],
        "additionalProperties": false
      },
      "Error": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string"
          },
          "code": {
            "type": "string",
            "enum": [
              "parcel_not_waiting",
              "tracking_duplicate",
              "no_email",
              "capacity_full",
              "already_checked_in",
              "already_handed_back",
              "nothing_to_hand_back",
              "number_in_use",
              "ticket_closed",
              "item_out",
              "item_in_repair",
              "item_retired",
              "already_back",
              "not_out",
              "already_signed_in",
              "visit_closed",
              "not_signed_in",
              "not_expected",
              "idempotency_key_invalid",
              "idempotency_key_reused",
              "idempotency_in_progress"
            ],
            "description": "A machine-readable reason, for conflicts."
          },
          "errors": {
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        },
        "required": [
          "message"
        ]
      },
      "Event": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Starts with evt_. The same id is sent again when a delivery is resent."
          },
          "type": {
            "type": "string",
            "enum": [
              "item.created",
              "item.updated",
              "claim.created",
              "claim.status_changed",
              "lost_report.created",
              "parcel.logged",
              "parcel.updated",
              "parcel.reminded",
              "parcel.collected",
              "parcel.returned",
              "checkroom.checked_in",
              "checkroom.handed_back",
              "checkroom.left",
              "loan.lent",
              "loan.due_soon",
              "loan.overdue",
              "loan.extended",
              "loan.returned",
              "loan.lost",
              "visit.expected",
              "visit.signed_in",
              "visit.host_confirmed",
              "visit.signed_out",
              "visit.cancelled"
            ]
          },
          "created": {
            "type": "string",
            "format": "date-time"
          },
          "venue": {
            "type": "object",
            "properties": {
              "code": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "name": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "code",
              "name"
            ],
            "additionalProperties": false
          },
          "data": {
            "type": "object",
            "description": "The record, in the same shape as the API returns it."
          }
        },
        "required": [
          "id",
          "type",
          "created",
          "venue",
          "data"
        ],
        "additionalProperties": false
      }
    }
  }
}
