{
  "openapi": "3.1.0",
  "info": {
    "title": "API do Ruche",
    "version": "1.2.0",
    "description": "A API do negócio no Ruche: ler os horários, os clientes e os serviços, marcar, remarcar, cancelar e cadastrar clientes. A chave é criada em Ajustes, Integrações, com os escopos escolhidos. Cada chave vê só o próprio negócio. Limite de 120 pedidos por minuto por chave. As escritas pedem o cabeçalho Idempotency-Key.",
    "contact": {
      "name": "Ruche",
      "url": "https://ruche.my/pt-br/api/"
    }
  },
  "servers": [
    {
      "url": "https://api.ruche.my/v1/api"
    }
  ],
  "security": [
    {
      "bearer": []
    },
    {
      "apiKey": []
    }
  ],
  "paths": {
    "/me": {
      "get": {
        "summary": "O negócio e a chave",
        "operationId": "whoami",
        "description": "Qualquer chave válida.",
        "responses": {
          "200": {
            "description": "Certo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "business": {
                      "type": "object",
                      "properties": {
                        "slug": {
                          "type": "string"
                        },
                        "name": {
                          "type": "string"
                        },
                        "timezone": {
                          "type": "string"
                        },
                        "country": {
                          "type": "string"
                        },
                        "currency": {
                          "type": "string"
                        },
                        "locale": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      },
                      "required": [
                        "slug",
                        "name",
                        "timezone",
                        "country",
                        "currency",
                        "locale"
                      ]
                    },
                    "key": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "prefix": {
                          "type": "string"
                        },
                        "createdAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "scopes": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "scope": {
                                "type": "string",
                                "enum": [
                                  "appointments.read",
                                  "appointments.write",
                                  "clients.read",
                                  "clients.write",
                                  "services.read",
                                  "payments.read",
                                  "sales.read"
                                ]
                              },
                              "description": {
                                "type": "string"
                              }
                            },
                            "required": [
                              "scope",
                              "description"
                            ]
                          }
                        }
                      },
                      "required": [
                        "name",
                        "prefix",
                        "createdAt",
                        "scopes"
                      ]
                    }
                  },
                  "required": [
                    "business",
                    "key"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida ou revogada (API_KEY_INVALID)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "O plano do negócio não tem os módulos de gestão (PLAN_INTEGRATIONS)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Passou de 120 pedidos por minuto (API_RATE_LIMIT, com Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/appointments": {
      "get": {
        "summary": "Horários de um intervalo",
        "operationId": "listAppointments",
        "x-ruche-scope": "appointments.read",
        "description": "Escopo: `appointments.read` (Ver os horários marcados (sem o código do horário e sem o motivo do cancelamento)).",
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "PENDING",
                "CONFIRMED",
                "RESCHEDULED",
                "CANCELLED",
                "COMPLETED",
                "NO_SHOW"
              ]
            }
          },
          {
            "name": "staffId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 200
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "default": 50,
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Certo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "status": {
                            "type": "string",
                            "enum": [
                              "PENDING",
                              "CONFIRMED",
                              "RESCHEDULED",
                              "CANCELLED",
                              "COMPLETED",
                              "NO_SHOW"
                            ]
                          },
                          "scheduledAt": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "endsAt": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "durationMin": {
                            "type": "integer",
                            "minimum": -9007199254740991,
                            "maximum": 9007199254740991
                          },
                          "service": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "anyOf": [
                                  {
                                    "type": "string",
                                    "format": "uuid"
                                  },
                                  {
                                    "type": "null"
                                  }
                                ]
                              },
                              "name": {
                                "type": "string"
                              }
                            },
                            "required": [
                              "id",
                              "name"
                            ]
                          },
                          "price": {
                            "type": "object",
                            "properties": {
                              "cents": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991,
                                "description": "Valor em centavos"
                              },
                              "currency": {
                                "type": "string",
                                "description": "Moeda do negócio (ISO 4217)"
                              }
                            },
                            "required": [
                              "cents",
                              "currency"
                            ]
                          },
                          "staff": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "string",
                                "format": "uuid"
                              },
                              "name": {
                                "type": "string"
                              }
                            },
                            "required": [
                              "id",
                              "name"
                            ]
                          },
                          "client": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "string",
                                "format": "uuid"
                              },
                              "name": {
                                "type": "string"
                              }
                            },
                            "required": [
                              "id",
                              "name"
                            ]
                          },
                          "source": {
                            "type": "string"
                          },
                          "locationId": {
                            "anyOf": [
                              {
                                "type": "string",
                                "format": "uuid"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "rescheduledFromId": {
                            "anyOf": [
                              {
                                "type": "string",
                                "format": "uuid"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "createdAt": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "updatedAt": {
                            "type": "string",
                            "format": "date-time"
                          }
                        },
                        "required": [
                          "id",
                          "status",
                          "scheduledAt",
                          "endsAt",
                          "durationMin",
                          "service",
                          "price",
                          "staff",
                          "client",
                          "source",
                          "locationId",
                          "rescheduledFromId",
                          "createdAt",
                          "updatedAt"
                        ],
                        "description": "Um horário. Nunca leva o código do horário nem o motivo do cancelamento."
                      }
                    },
                    "nextCursor": {
                      "description": "Mande em `cursor` para a próxima página; nulo no fim",
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "nextCursor"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Pedido inválido (o corpo, a consulta ou a Idempotency-Key)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida ou revogada (API_KEY_INVALID)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "O plano do negócio não tem os módulos de gestão (PLAN_INTEGRATIONS)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "A chave não tem o escopo da rota (API_SCOPE_MISSING)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Passou de 120 pedidos por minuto (API_RATE_LIMIT, com Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Marcar um horário",
        "operationId": "bookAppointment",
        "x-ruche-scope": "appointments.write",
        "description": "Escopo: `appointments.write` (Marcar, remarcar e cancelar horários (pelo mesmo caminho do painel, com as mesmas regras)).",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "Obrigatória nas escritas: de 8 a 255 caracteres (um UUID serve). A mesma chave com o mesmo corpo devolve a mesma resposta por 24 horas; com outro corpo, 409.",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255,
              "pattern": "^[A-Za-z0-9_\\-:.]{8,255}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "staffId": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "serviceId": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "startAt": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "client": {
                    "anyOf": [
                      {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid"
                          }
                        },
                        "required": [
                          "id"
                        ],
                        "additionalProperties": false
                      },
                      {
                        "type": "object",
                        "properties": {
                          "name": {
                            "type": "string",
                            "minLength": 2,
                            "maxLength": 120
                          },
                          "phone": {
                            "type": "string"
                          },
                          "email": {
                            "anyOf": [
                              {
                                "type": "string",
                                "format": "email"
                              },
                              {
                                "type": "string",
                                "const": ""
                              }
                            ]
                          }
                        },
                        "required": [
                          "name",
                          "phone"
                        ],
                        "additionalProperties": false
                      }
                    ]
                  }
                },
                "required": [
                  "staffId",
                  "serviceId",
                  "startAt",
                  "client"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Marcado",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Appointment"
                }
              }
            }
          },
          "400": {
            "description": "Pedido inválido (o corpo, a consulta ou a Idempotency-Key)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida ou revogada (API_KEY_INVALID)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "O plano do negócio não tem os módulos de gestão (PLAN_INTEGRATIONS)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "A chave não tem o escopo da rota (API_SCOPE_MISSING)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Não encontrado neste negócio",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflito: horário ocupado (SLOT_TAKEN), cliente que já existe (CLIENT_EXISTS) ou a Idempotency-Key com outro corpo (IDEMPOTENCY_KEY_REUSED)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Passou de 120 pedidos por minuto (API_RATE_LIMIT, com Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/appointments/{id}": {
      "get": {
        "summary": "Um horário",
        "operationId": "getAppointment",
        "x-ruche-scope": "appointments.read",
        "description": "Escopo: `appointments.read` (Ver os horários marcados (sem o código do horário e sem o motivo do cancelamento)).",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Certo",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Appointment"
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida ou revogada (API_KEY_INVALID)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "O plano do negócio não tem os módulos de gestão (PLAN_INTEGRATIONS)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "A chave não tem o escopo da rota (API_SCOPE_MISSING)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Não encontrado neste negócio",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Passou de 120 pedidos por minuto (API_RATE_LIMIT, com Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/appointments/{id}/reschedule": {
      "post": {
        "summary": "Remarcar (nasce um horário novo; o antigo fica RESCHEDULED)",
        "operationId": "rescheduleAppointment",
        "x-ruche-scope": "appointments.write",
        "description": "Escopo: `appointments.write` (Marcar, remarcar e cancelar horários (pelo mesmo caminho do painel, com as mesmas regras)).",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "Obrigatória nas escritas: de 8 a 255 caracteres (um UUID serve). A mesma chave com o mesmo corpo devolve a mesma resposta por 24 horas; com outro corpo, 409.",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255,
              "pattern": "^[A-Za-z0-9_\\-:.]{8,255}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "startAt": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "staffId": {
                    "type": "string",
                    "format": "uuid"
                  }
                },
                "required": [
                  "startAt"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "O horário novo",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Appointment"
                }
              }
            }
          },
          "400": {
            "description": "Pedido inválido (o corpo, a consulta ou a Idempotency-Key)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida ou revogada (API_KEY_INVALID)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "O plano do negócio não tem os módulos de gestão (PLAN_INTEGRATIONS)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "A chave não tem o escopo da rota (API_SCOPE_MISSING)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Não encontrado neste negócio",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflito: horário ocupado (SLOT_TAKEN), cliente que já existe (CLIENT_EXISTS) ou a Idempotency-Key com outro corpo (IDEMPOTENCY_KEY_REUSED)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Passou de 120 pedidos por minuto (API_RATE_LIMIT, com Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/appointments/{id}/cancel": {
      "post": {
        "summary": "Cancelar com o motivo",
        "operationId": "cancelAppointment",
        "x-ruche-scope": "appointments.write",
        "description": "Escopo: `appointments.write` (Marcar, remarcar e cancelar horários (pelo mesmo caminho do painel, com as mesmas regras)).",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "Obrigatória nas escritas: de 8 a 255 caracteres (um UUID serve). A mesma chave com o mesmo corpo devolve a mesma resposta por 24 horas; com outro corpo, 409.",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255,
              "pattern": "^[A-Za-z0-9_\\-:.]{8,255}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "reason": {
                    "type": "string",
                    "minLength": 3,
                    "maxLength": 500
                  }
                },
                "required": [
                  "reason"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Certo",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Appointment"
                }
              }
            }
          },
          "400": {
            "description": "Pedido inválido (o corpo, a consulta ou a Idempotency-Key)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida ou revogada (API_KEY_INVALID)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "O plano do negócio não tem os módulos de gestão (PLAN_INTEGRATIONS)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "A chave não tem o escopo da rota (API_SCOPE_MISSING)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Não encontrado neste negócio",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflito: horário ocupado (SLOT_TAKEN), cliente que já existe (CLIENT_EXISTS) ou a Idempotency-Key com outro corpo (IDEMPOTENCY_KEY_REUSED)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Passou de 120 pedidos por minuto (API_RATE_LIMIT, com Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/clients": {
      "get": {
        "summary": "Clientes",
        "operationId": "listClients",
        "x-ruche-scope": "clients.read",
        "description": "Escopo: `clients.read` (Ver os clientes: nome, telefone, e-mail e data de nascimento (nunca as notas, as fichas nem as fotos)).",
        "parameters": [
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 200
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "default": 50,
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Certo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "name": {
                            "type": "string"
                          },
                          "phone": {
                            "description": "Com o código do país, começando por +",
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "email": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "birthDate": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "createdAt": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "updatedAt": {
                            "type": "string",
                            "format": "date-time"
                          }
                        },
                        "required": [
                          "id",
                          "name",
                          "phone",
                          "email",
                          "birthDate",
                          "createdAt",
                          "updatedAt"
                        ],
                        "description": "Um cliente. Nunca leva as notas, as fichas nem as fotos."
                      }
                    },
                    "nextCursor": {
                      "description": "Mande em `cursor` para a próxima página; nulo no fim",
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "nextCursor"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Pedido inválido (o corpo, a consulta ou a Idempotency-Key)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida ou revogada (API_KEY_INVALID)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "O plano do negócio não tem os módulos de gestão (PLAN_INTEGRATIONS)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "A chave não tem o escopo da rota (API_SCOPE_MISSING)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Passou de 120 pedidos por minuto (API_RATE_LIMIT, com Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Cadastrar um cliente",
        "operationId": "createClient",
        "x-ruche-scope": "clients.write",
        "description": "Escopo: `clients.write` (Cadastrar clientes novos (nome, telefone, e-mail e data de nascimento)).",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "Obrigatória nas escritas: de 8 a 255 caracteres (um UUID serve). A mesma chave com o mesmo corpo devolve a mesma resposta por 24 horas; com outro corpo, 409.",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255,
              "pattern": "^[A-Za-z0-9_\\-:.]{8,255}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 120
                  },
                  "phone": {
                    "type": "string"
                  },
                  "email": {
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "email"
                      },
                      {
                        "type": "string",
                        "const": ""
                      }
                    ]
                  },
                  "birthDate": {
                    "anyOf": [
                      {
                        "anyOf": [
                          {
                            "type": "string"
                          },
                          {
                            "type": "string",
                            "const": ""
                          }
                        ]
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "guardianName": {
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 120
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "guardianEmail": {
                    "anyOf": [
                      {
                        "anyOf": [
                          {
                            "type": "string",
                            "format": "email"
                          },
                          {
                            "type": "string",
                            "const": ""
                          }
                        ]
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "consent": {
                    "type": "boolean",
                    "const": true
                  }
                },
                "required": [
                  "name",
                  "phone",
                  "consent"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Cadastrado",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Client"
                }
              }
            }
          },
          "400": {
            "description": "Pedido inválido (o corpo, a consulta ou a Idempotency-Key)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida ou revogada (API_KEY_INVALID)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "O plano do negócio não tem os módulos de gestão (PLAN_INTEGRATIONS)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "A chave não tem o escopo da rota (API_SCOPE_MISSING)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflito: horário ocupado (SLOT_TAKEN), cliente que já existe (CLIENT_EXISTS) ou a Idempotency-Key com outro corpo (IDEMPOTENCY_KEY_REUSED)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Passou de 120 pedidos por minuto (API_RATE_LIMIT, com Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/clients/{id}": {
      "get": {
        "summary": "Um cliente",
        "operationId": "getClient",
        "x-ruche-scope": "clients.read",
        "description": "Escopo: `clients.read` (Ver os clientes: nome, telefone, e-mail e data de nascimento (nunca as notas, as fichas nem as fotos)).",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Certo",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Client"
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida ou revogada (API_KEY_INVALID)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "O plano do negócio não tem os módulos de gestão (PLAN_INTEGRATIONS)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "A chave não tem o escopo da rota (API_SCOPE_MISSING)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Não encontrado neste negócio",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Passou de 120 pedidos por minuto (API_RATE_LIMIT, com Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/services": {
      "get": {
        "summary": "Serviços",
        "operationId": "listServices",
        "x-ruche-scope": "services.read",
        "description": "Escopo: `services.read` (Ver os serviços, a duração e o preço).",
        "responses": {
          "200": {
            "description": "Certo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "name": {
                            "type": "string"
                          },
                          "durationMin": {
                            "type": "integer",
                            "minimum": -9007199254740991,
                            "maximum": 9007199254740991
                          },
                          "price": {
                            "type": "object",
                            "properties": {
                              "cents": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991,
                                "description": "Valor em centavos"
                              },
                              "currency": {
                                "type": "string",
                                "description": "Moeda do negócio (ISO 4217)"
                              }
                            },
                            "required": [
                              "cents",
                              "currency"
                            ]
                          },
                          "active": {
                            "type": "boolean"
                          },
                          "category": {
                            "type": [
                              "string",
                              "null"
                            ]
                          }
                        },
                        "required": [
                          "id",
                          "name",
                          "durationMin",
                          "price",
                          "active",
                          "category"
                        ]
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida ou revogada (API_KEY_INVALID)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "O plano do negócio não tem os módulos de gestão (PLAN_INTEGRATIONS)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "A chave não tem o escopo da rota (API_SCOPE_MISSING)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Passou de 120 pedidos por minuto (API_RATE_LIMIT, com Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/payments": {
      "get": {
        "summary": "Pagamentos, em ordem de atualização",
        "operationId": "listPayments",
        "x-ruche-scope": "payments.read",
        "description": "Escopo: `payments.read` (Ver os pagamentos e os valores recebidos (sem dados do meio de pagamento)).",
        "parameters": [
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 200
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "default": 50,
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Certo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "appointmentId": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "channel": {
                            "type": "string"
                          },
                          "method": {
                            "type": "string"
                          },
                          "status": {
                            "type": "string"
                          },
                          "isDeposit": {
                            "type": "boolean"
                          },
                          "amountCents": {
                            "type": "integer",
                            "minimum": -9007199254740991,
                            "maximum": 9007199254740991
                          },
                          "currency": {
                            "type": "string"
                          },
                          "paidAt": {
                            "anyOf": [
                              {
                                "type": "string",
                                "format": "date-time"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "refundCents": {
                            "type": "integer",
                            "minimum": -9007199254740991,
                            "maximum": 9007199254740991
                          },
                          "createdAt": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "updatedAt": {
                            "type": "string",
                            "format": "date-time"
                          }
                        },
                        "required": [
                          "id",
                          "appointmentId",
                          "channel",
                          "method",
                          "status",
                          "isDeposit",
                          "amountCents",
                          "currency",
                          "paidAt",
                          "refundCents",
                          "createdAt",
                          "updatedAt"
                        ]
                      }
                    },
                    "nextCursor": {
                      "description": "Mande em `cursor` para a próxima página; nulo no fim",
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "nextCursor"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Pedido inválido (o corpo, a consulta ou a Idempotency-Key)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida ou revogada (API_KEY_INVALID)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "O plano do negócio não tem os módulos de gestão (PLAN_INTEGRATIONS)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "A chave não tem o escopo da rota (API_SCOPE_MISSING)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Passou de 120 pedidos por minuto (API_RATE_LIMIT, com Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/payments/{id}": {
      "get": {
        "summary": "Detalhes do pagamento recebido no aviso payment.received",
        "operationId": "getPayment",
        "x-ruche-scope": "payments.read",
        "description": "Escopo: `payments.read` (Ver os pagamentos e os valores recebidos (sem dados do meio de pagamento)).",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Certo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "appointmentId": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "channel": {
                      "type": "string"
                    },
                    "method": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string"
                    },
                    "isDeposit": {
                      "type": "boolean"
                    },
                    "amountCents": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "currency": {
                      "type": "string"
                    },
                    "paidAt": {
                      "anyOf": [
                        {
                          "type": "string",
                          "format": "date-time"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "refundCents": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "createdAt": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "updatedAt": {
                      "type": "string",
                      "format": "date-time"
                    }
                  },
                  "required": [
                    "id",
                    "appointmentId",
                    "channel",
                    "method",
                    "status",
                    "isDeposit",
                    "amountCents",
                    "currency",
                    "paidAt",
                    "refundCents",
                    "createdAt",
                    "updatedAt"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Pedido inválido (o corpo, a consulta ou a Idempotency-Key)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida ou revogada (API_KEY_INVALID)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "O plano do negócio não tem os módulos de gestão (PLAN_INTEGRATIONS)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "A chave não tem o escopo da rota (API_SCOPE_MISSING)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Não encontrado neste negócio",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Passou de 120 pedidos por minuto (API_RATE_LIMIT, com Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/sales": {
      "get": {
        "summary": "Vendas, em ordem de atualização",
        "operationId": "listSales",
        "x-ruche-scope": "sales.read",
        "description": "Escopo: `sales.read` (Ver as vendas e seus itens (sem custos nem notas internas)).",
        "parameters": [
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 200
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "default": 50,
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Certo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "appointmentId": {
                            "anyOf": [
                              {
                                "type": "string",
                                "format": "uuid"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "clientId": {
                            "anyOf": [
                              {
                                "type": "string",
                                "format": "uuid"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "status": {
                            "type": "string"
                          },
                          "method": {
                            "type": "string"
                          },
                          "paymentPending": {
                            "type": "boolean"
                          },
                          "subtotalCents": {
                            "type": "integer",
                            "minimum": -9007199254740991,
                            "maximum": 9007199254740991
                          },
                          "discountCents": {
                            "type": "integer",
                            "minimum": -9007199254740991,
                            "maximum": 9007199254740991
                          },
                          "totalCents": {
                            "type": "integer",
                            "minimum": -9007199254740991,
                            "maximum": 9007199254740991
                          },
                          "currency": {
                            "type": "string"
                          },
                          "occurredAt": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "cancelledAt": {
                            "anyOf": [
                              {
                                "type": "string",
                                "format": "date-time"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "createdAt": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "updatedAt": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "items": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "id": {
                                  "type": "string",
                                  "format": "uuid"
                                },
                                "kind": {
                                  "type": "string"
                                },
                                "productId": {
                                  "anyOf": [
                                    {
                                      "type": "string",
                                      "format": "uuid"
                                    },
                                    {
                                      "type": "null"
                                    }
                                  ]
                                },
                                "description": {
                                  "type": "string"
                                },
                                "qty": {
                                  "type": "integer",
                                  "minimum": -9007199254740991,
                                  "maximum": 9007199254740991
                                },
                                "unitPriceCents": {
                                  "type": "integer",
                                  "minimum": -9007199254740991,
                                  "maximum": 9007199254740991
                                },
                                "discountCents": {
                                  "type": "integer",
                                  "minimum": -9007199254740991,
                                  "maximum": 9007199254740991
                                },
                                "totalCents": {
                                  "type": "integer",
                                  "minimum": -9007199254740991,
                                  "maximum": 9007199254740991
                                }
                              },
                              "required": [
                                "id",
                                "kind",
                                "productId",
                                "description",
                                "qty",
                                "unitPriceCents",
                                "discountCents",
                                "totalCents"
                              ]
                            }
                          }
                        },
                        "required": [
                          "id",
                          "appointmentId",
                          "clientId",
                          "status",
                          "method",
                          "paymentPending",
                          "subtotalCents",
                          "discountCents",
                          "totalCents",
                          "currency",
                          "occurredAt",
                          "cancelledAt",
                          "createdAt",
                          "updatedAt",
                          "items"
                        ]
                      }
                    },
                    "nextCursor": {
                      "description": "Mande em `cursor` para a próxima página; nulo no fim",
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "nextCursor"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Pedido inválido (o corpo, a consulta ou a Idempotency-Key)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida ou revogada (API_KEY_INVALID)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "O plano do negócio não tem os módulos de gestão (PLAN_INTEGRATIONS)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "A chave não tem o escopo da rota (API_SCOPE_MISSING)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Passou de 120 pedidos por minuto (API_RATE_LIMIT, com Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/sales/{id}": {
      "get": {
        "summary": "Detalhes da venda recebida no aviso sale.created",
        "operationId": "getSale",
        "x-ruche-scope": "sales.read",
        "description": "Escopo: `sales.read` (Ver as vendas e seus itens (sem custos nem notas internas)).",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Certo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "appointmentId": {
                      "anyOf": [
                        {
                          "type": "string",
                          "format": "uuid"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "clientId": {
                      "anyOf": [
                        {
                          "type": "string",
                          "format": "uuid"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "status": {
                      "type": "string"
                    },
                    "method": {
                      "type": "string"
                    },
                    "paymentPending": {
                      "type": "boolean"
                    },
                    "subtotalCents": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "discountCents": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "totalCents": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "currency": {
                      "type": "string"
                    },
                    "occurredAt": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "cancelledAt": {
                      "anyOf": [
                        {
                          "type": "string",
                          "format": "date-time"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "createdAt": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "updatedAt": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "items": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "kind": {
                            "type": "string"
                          },
                          "productId": {
                            "anyOf": [
                              {
                                "type": "string",
                                "format": "uuid"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "description": {
                            "type": "string"
                          },
                          "qty": {
                            "type": "integer",
                            "minimum": -9007199254740991,
                            "maximum": 9007199254740991
                          },
                          "unitPriceCents": {
                            "type": "integer",
                            "minimum": -9007199254740991,
                            "maximum": 9007199254740991
                          },
                          "discountCents": {
                            "type": "integer",
                            "minimum": -9007199254740991,
                            "maximum": 9007199254740991
                          },
                          "totalCents": {
                            "type": "integer",
                            "minimum": -9007199254740991,
                            "maximum": 9007199254740991
                          }
                        },
                        "required": [
                          "id",
                          "kind",
                          "productId",
                          "description",
                          "qty",
                          "unitPriceCents",
                          "discountCents",
                          "totalCents"
                        ]
                      }
                    }
                  },
                  "required": [
                    "id",
                    "appointmentId",
                    "clientId",
                    "status",
                    "method",
                    "paymentPending",
                    "subtotalCents",
                    "discountCents",
                    "totalCents",
                    "currency",
                    "occurredAt",
                    "cancelledAt",
                    "createdAt",
                    "updatedAt",
                    "items"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Pedido inválido (o corpo, a consulta ou a Idempotency-Key)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida ou revogada (API_KEY_INVALID)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "O plano do negócio não tem os módulos de gestão (PLAN_INTEGRATIONS)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "A chave não tem o escopo da rota (API_SCOPE_MISSING)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Não encontrado neste negócio",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Passou de 120 pedidos por minuto (API_RATE_LIMIT, com Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "webhooks": {
    "aviso": {
      "post": {
        "summary": "Aviso do Ruche para o seu endereço",
        "description": "Assinado com HMAC-SHA256: x-ruche-signature é sha256=<hex> do texto \"<x-ruche-timestamp>.<corpo>\", com o segredo do endereço. Tipos: appointment.created, appointment.confirmed, appointment.cancelled, appointment.rescheduled, client.created, payment.received, sale.created. Responda 2xx em até 10 segundos; senão, o Ruche tenta de novo.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "format": "uuid",
                    "description": "Id único do aviso: use para não processar duas vezes"
                  },
                  "event": {
                    "type": "string",
                    "enum": [
                      "appointment.created",
                      "appointment.confirmed",
                      "appointment.cancelled",
                      "appointment.rescheduled",
                      "client.created",
                      "payment.received",
                      "sale.created",
                      "ping"
                    ]
                  },
                  "createdAt": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "data": {
                    "type": "object",
                    "properties": {
                      "appointment": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "scheduledAt": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "previousId": {
                            "type": "string",
                            "format": "uuid"
                          }
                        },
                        "required": [
                          "id"
                        ]
                      },
                      "client": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "createdAt": {
                            "type": "string",
                            "format": "date-time"
                          }
                        },
                        "required": [
                          "id"
                        ]
                      },
                      "payment": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "paidAt": {
                            "type": "string",
                            "format": "date-time"
                          }
                        },
                        "required": [
                          "id"
                        ]
                      },
                      "sale": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "createdAt": {
                            "type": "string",
                            "format": "date-time"
                          }
                        },
                        "required": [
                          "id"
                        ]
                      }
                    },
                    "description": "Um só objeto, conforme o tipo do aviso"
                  }
                },
                "required": [
                  "id",
                  "event",
                  "createdAt",
                  "data"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Recebido"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearer": {
        "type": "http",
        "scheme": "bearer",
        "description": "Authorization: Bearer rk_live_..."
      },
      "apiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Api-Key"
      }
    },
    "schemas": {
      "Appointment": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "CONFIRMED",
              "RESCHEDULED",
              "CANCELLED",
              "COMPLETED",
              "NO_SHOW"
            ]
          },
          "scheduledAt": {
            "type": "string",
            "format": "date-time"
          },
          "endsAt": {
            "type": "string",
            "format": "date-time"
          },
          "durationMin": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991
          },
          "service": {
            "type": "object",
            "properties": {
              "id": {
                "anyOf": [
                  {
                    "type": "string",
                    "format": "uuid"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "name": {
                "type": "string"
              }
            },
            "required": [
              "id",
              "name"
            ]
          },
          "price": {
            "type": "object",
            "properties": {
              "cents": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991,
                "description": "Valor em centavos"
              },
              "currency": {
                "type": "string",
                "description": "Moeda do negócio (ISO 4217)"
              }
            },
            "required": [
              "cents",
              "currency"
            ]
          },
          "staff": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "name": {
                "type": "string"
              }
            },
            "required": [
              "id",
              "name"
            ]
          },
          "client": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "name": {
                "type": "string"
              }
            },
            "required": [
              "id",
              "name"
            ]
          },
          "source": {
            "type": "string"
          },
          "locationId": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ]
          },
          "rescheduledFromId": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ]
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "status",
          "scheduledAt",
          "endsAt",
          "durationMin",
          "service",
          "price",
          "staff",
          "client",
          "source",
          "locationId",
          "rescheduledFromId",
          "createdAt",
          "updatedAt"
        ],
        "description": "Um horário. Nunca leva o código do horário nem o motivo do cancelamento."
      },
      "Client": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "phone": {
            "description": "Com o código do país, começando por +",
            "type": [
              "string",
              "null"
            ]
          },
          "email": {
            "type": [
              "string",
              "null"
            ]
          },
          "birthDate": {
            "type": [
              "string",
              "null"
            ]
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "name",
          "phone",
          "email",
          "birthDate",
          "createdAt",
          "updatedAt"
        ],
        "description": "Um cliente. Nunca leva as notas, as fichas nem as fotos."
      },
      "Error": {
        "type": "object",
        "properties": {
          "statusCode": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991
          },
          "message": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            ],
            "description": "O código do erro, como `API_SCOPE_MISSING`"
          }
        },
        "required": [
          "statusCode",
          "message"
        ]
      }
    }
  }
}
