{
  "openapi": "3.0.3",
  "info": {
    "title": "CliniDeck: API de integração",
    "version": "v1",
    "description": "Agenda online da clínica para o site e o chatbot do parceiro. Guia: https://clinideck.com.br/integration/api."
  },
  "servers": [
    {
      "url": "https://api.clinideck.com.br/api"
    }
  ],
  "security": [
    {
      "integratorToken": [],
      "integrationType": [],
      "integrationLogin": [],
      "integrationPassword": []
    }
  ],
  "paths": {
    "/integration/v1/specialties": {
      "get": {
        "operationId": "listSpecialties",
        "summary": "Especialidades",
        "description": "As especialidades dos profissionais que a clínica da credencial abriu para a agenda online, sem repetição.",
        "x-rate-limit-bucket": "read",
        "x-scopes": [
          "availability:read"
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SpecialtyList"
                }
              }
            }
          },
          "401": {
            "description": "Credencial ausente, inválida, revogada ou sem o escopo da rota: a mesma recusa para todos os casos.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "A clínica não aceita reserva online agora (`onlineBooking.unavailable`), a régua do profissional (antecedência, horizonte, clientela), o teto de reservas em aberto, ou outra escrita em curso.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Teto de chamadas da credencial. Espere o `Retry-After`.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/integration/v1/professionals": {
      "get": {
        "operationId": "listProfessionals",
        "summary": "Profissionais agendáveis",
        "description": "Quem a clínica abriu para a agenda online, com as restrições de clientela e de prazo. O filtro de especialidade ignora caixa e acento.",
        "x-rate-limit-bucket": "read",
        "x-scopes": [
          "availability:read"
        ],
        "parameters": [
          {
            "name": "specialty",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 120,
              "minLength": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProfessionalList"
                }
              }
            }
          },
          "400": {
            "description": "Pedido recusado pela validação (`validation_failed`, com os campos, inclusive os do paciente novo), horário tomado ou fora da grade (`appointment.slotUnavailable`), ou a régua da paciente.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Credencial ausente, inválida, revogada ou sem o escopo da rota: a mesma recusa para todos os casos.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "A clínica não aceita reserva online agora (`onlineBooking.unavailable`), a régua do profissional (antecedência, horizonte, clientela), o teto de reservas em aberto, ou outra escrita em curso.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Teto de chamadas da credencial. Espere o `Retry-After`.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/integration/v1/procedures": {
      "get": {
        "operationId": "listProcedures",
        "summary": "Procedimentos do profissional",
        "description": "Os procedimentos que o profissional atende pela agenda online, com preço e duração.",
        "x-rate-limit-bucket": "read",
        "x-scopes": [
          "availability:read"
        ],
        "parameters": [
          {
            "name": "professionalId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProcedureList"
                }
              }
            }
          },
          "400": {
            "description": "Pedido recusado pela validação (`validation_failed`, com os campos, inclusive os do paciente novo), horário tomado ou fora da grade (`appointment.slotUnavailable`), ou a régua da paciente.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Credencial ausente, inválida, revogada ou sem o escopo da rota: a mesma recusa para todos os casos.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Não existe para esta credencial.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "A clínica não aceita reserva online agora (`onlineBooking.unavailable`), a régua do profissional (antecedência, horizonte, clientela), o teto de reservas em aberto, ou outra escrita em curso.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Teto de chamadas da credencial. Espere o `Retry-After`.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/integration/v1/availability": {
      "get": {
        "operationId": "getAvailability",
        "summary": "Horários livres do mês",
        "description": "Os horários livres do profissional no mês pedido, no fuso da clínica. O `startsAt` de cada horário é o instante UTC que a reserva recebe. Sem `month`, o mês corrente da clínica; mês passado recusa.",
        "x-rate-limit-bucket": "read",
        "x-scopes": [
          "availability:read"
        ],
        "parameters": [
          {
            "name": "professionalId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
            }
          },
          {
            "name": "month",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^\\d{4}-(0[1-9]|1[0-2])$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Availability"
                }
              }
            }
          },
          "400": {
            "description": "Pedido recusado pela validação (`validation_failed`, com os campos, inclusive os do paciente novo), horário tomado ou fora da grade (`appointment.slotUnavailable`), ou a régua da paciente.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Credencial ausente, inválida, revogada ou sem o escopo da rota: a mesma recusa para todos os casos.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Não existe para esta credencial.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "A clínica não aceita reserva online agora (`onlineBooking.unavailable`), a régua do profissional (antecedência, horizonte, clientela), o teto de reservas em aberto, ou outra escrita em curso.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Teto de chamadas da credencial. Espere o `Retry-After`.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/integration/v1/bookings": {
      "post": {
        "operationId": "createBooking",
        "summary": "Reservar",
        "description": "Reserva um horário pela régua da agenda online da clínica. Com a clínica que exige pagamento, a reserva nasce `AWAITING_PAYMENT` com o `checkoutUrl` e vence se não for paga no prazo; sem a exigência, nasce `PENDING_CONFIRMATION`. Uma reserva por checkout. Cada credencial tem no máximo 20 reservas em aberto. A `Idempotency-Key` é obrigatória: a mesma chave com o mesmo corpo devolve a mesma reserva, com o header `Idempotent-Replayed: true`.",
        "x-rate-limit-bucket": "booking",
        "x-scopes": [
          "booking:write"
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "Uma chave por reserva pretendida (um UUID serve). Repita a MESMA chave ao refazer o pedido.",
            "schema": {
              "type": "string",
              "pattern": "^[!-~]{1,255}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateIntegrationBookingDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "OK",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              },
              "Idempotent-Replayed": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                },
                "description": "Resposta repetida pela chave."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Booking"
                }
              }
            }
          },
          "400": {
            "description": "Pedido recusado pela validação (`validation_failed`, com os campos, inclusive os do paciente novo), horário tomado ou fora da grade (`appointment.slotUnavailable`), ou a régua da paciente.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Credencial ausente, inválida, revogada ou sem o escopo da rota: a mesma recusa para todos os casos.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Não existe para esta credencial.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "A clínica não aceita reserva online agora (`onlineBooking.unavailable`), a régua do profissional (antecedência, horizonte, clientela), o teto de reservas em aberto, ou outra escrita em curso.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Corpo grande demais.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "A `Idempotency-Key` já foi usada com outro corpo (`idempotency.keyReused`).",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Teto de chamadas da credencial. Espere o `Retry-After`.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Indisponível agora. Tente de novo depois do `Retry-After`, com a mesma `Idempotency-Key`.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/integration/v1/bookings/{id}": {
      "get": {
        "operationId": "getBooking",
        "summary": "Situação da reserva",
        "description": "A reserva que esta credencial criou. A reserva de outra credencial, de outra clínica ou da recepção responde o mesmo 404.",
        "x-rate-limit-bucket": "read",
        "x-scopes": [
          "booking:write"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Booking"
                }
              }
            }
          },
          "401": {
            "description": "Credencial ausente, inválida, revogada ou sem o escopo da rota: a mesma recusa para todos os casos.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Não existe para esta credencial.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "A clínica não aceita reserva online agora (`onlineBooking.unavailable`), a régua do profissional (antecedência, horizonte, clientela), o teto de reservas em aberto, ou outra escrita em curso.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Teto de chamadas da credencial. Espere o `Retry-After`.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store, private"
                  ]
                }
              },
              "Pragma": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              },
              "Vary": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "Authorization, X-Integration-Type, X-Integration-Login, X-Integration-Password, Idempotency-Key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "x-webhooks": {
    "booking.confirmed": {
      "post": {
        "operationId": "webhook.booking.confirmed",
        "summary": "booking.confirmed",
        "description": "A reserva saiu de pendente, ou de cancelada (reativada pela clínica), para confirmada: paga, confirmada pela clínica ou em atendimento. Responda 2xx em até 10 s; a falha se repete até 10 tentativas.",
        "security": [],
        "parameters": [
          {
            "name": "X-CliniDeck-Signature",
            "in": "header",
            "required": true,
            "description": "`t=<unix do envio>,v1=<hex>[,v1=<hex>]`: cada `v1` é o HMAC-SHA256 de `<t>.<corpo>` com a chave de assinatura. Aceite qualquer `v1=` que case e recuse `t` com mais de 300 s de diferença.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-CliniDeck-Event-Id",
            "in": "header",
            "required": true,
            "description": "O `id` do aviso.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "X-CliniDeck-Event-Type",
            "in": "header",
            "required": true,
            "description": "O `type` do aviso.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Recebido."
          }
        }
      }
    },
    "booking.canceled": {
      "post": {
        "operationId": "webhook.booking.canceled",
        "summary": "booking.canceled",
        "description": "A reserva foi cancelada, venceu sem pagamento ou foi excluída. Responda 2xx em até 10 s; a falha se repete até 10 tentativas.",
        "security": [],
        "parameters": [
          {
            "name": "X-CliniDeck-Signature",
            "in": "header",
            "required": true,
            "description": "`t=<unix do envio>,v1=<hex>[,v1=<hex>]`: cada `v1` é o HMAC-SHA256 de `<t>.<corpo>` com a chave de assinatura. Aceite qualquer `v1=` que case e recuse `t` com mais de 300 s de diferença.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-CliniDeck-Event-Id",
            "in": "header",
            "required": true,
            "description": "O `id` do aviso.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "X-CliniDeck-Event-Type",
            "in": "header",
            "required": true,
            "description": "O `type` do aviso.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Recebido."
          }
        }
      }
    },
    "payment.confirmed": {
      "post": {
        "operationId": "webhook.payment.confirmed",
        "summary": "payment.confirmed",
        "description": "A cobrança da reserva foi paga. Responda 2xx em até 10 s; a falha se repete até 10 tentativas.",
        "security": [],
        "parameters": [
          {
            "name": "X-CliniDeck-Signature",
            "in": "header",
            "required": true,
            "description": "`t=<unix do envio>,v1=<hex>[,v1=<hex>]`: cada `v1` é o HMAC-SHA256 de `<t>.<corpo>` com a chave de assinatura. Aceite qualquer `v1=` que case e recuse `t` com mais de 300 s de diferença.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-CliniDeck-Event-Id",
            "in": "header",
            "required": true,
            "description": "O `id` do aviso.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "X-CliniDeck-Event-Type",
            "in": "header",
            "required": true,
            "description": "O `type` do aviso.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Recebido."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "integratorToken": {
        "type": "http",
        "scheme": "bearer",
        "description": "O token do integrador (`cdk_int_...`)."
      },
      "integrationType": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Integration-Type",
        "description": "`AGENDA_ONLINE`."
      },
      "integrationLogin": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Integration-Login",
        "description": "O login da clínica."
      },
      "integrationPassword": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Integration-Password",
        "description": "A senha da clínica."
      }
    },
    "schemas": {
      "Availability": {
        "type": "object",
        "properties": {
          "professionalId": {
            "type": "string",
            "format": "uuid"
          },
          "timezone": {
            "type": "string",
            "description": "Fuso IANA da clínica."
          },
          "month": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}$"
          },
          "bookingEnabled": {
            "type": "boolean",
            "description": "Com `false`, a clínica não recebe reserva agora e `days` sai vazio."
          },
          "days": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AvailabilityDay"
            }
          }
        },
        "required": [
          "professionalId",
          "timezone",
          "month",
          "bookingEnabled",
          "days"
        ],
        "additionalProperties": false
      },
      "AvailabilityDay": {
        "type": "object",
        "properties": {
          "date": {
            "type": "string",
            "format": "date",
            "description": "Dia civil no fuso da clínica."
          },
          "slots": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AvailabilitySlot"
            }
          }
        },
        "required": [
          "date",
          "slots"
        ],
        "additionalProperties": false
      },
      "AvailabilitySlot": {
        "type": "object",
        "properties": {
          "startsAt": {
            "type": "string",
            "format": "date-time",
            "description": "Instante UTC, o valor que `POST /bookings` recebe."
          },
          "time": {
            "type": "string",
            "description": "Hora local da clínica (`HH:mm`)."
          },
          "durationMinutes": {
            "type": "integer"
          },
          "group": {
            "type": "boolean"
          }
        },
        "required": [
          "startsAt",
          "time",
          "durationMinutes",
          "group"
        ],
        "additionalProperties": false
      },
      "Booking": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "enum": [
              "AWAITING_PAYMENT",
              "PENDING_CONFIRMATION",
              "CONFIRMED",
              "CANCELED",
              "COMPLETED",
              "NO_SHOW"
            ]
          },
          "paymentRequired": {
            "type": "boolean"
          },
          "checkoutUrl": {
            "type": "string",
            "nullable": true,
            "description": "O link de pagamento, só enquanto a reserva espera o pagamento."
          },
          "professional": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "name": {
                "type": "string"
              }
            },
            "required": [
              "id",
              "name"
            ],
            "additionalProperties": false
          },
          "procedure": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "name": {
                "type": "string"
              }
            },
            "required": [
              "id",
              "name"
            ],
            "additionalProperties": false
          },
          "startsAt": {
            "type": "string",
            "format": "date-time"
          },
          "durationMinutes": {
            "type": "integer"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "status",
          "paymentRequired",
          "checkoutUrl",
          "professional",
          "procedure",
          "startsAt",
          "durationMinutes",
          "createdAt"
        ],
        "additionalProperties": false
      },
      "CreateIntegrationBookingDto": {
        "type": "object",
        "properties": {
          "patient": {
            "$ref": "#/components/schemas/PublicCheckoutPatientDto"
          },
          "professionalId": {
            "type": "string",
            "format": "uuid",
            "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
          },
          "procedureId": {
            "type": "string",
            "format": "uuid",
            "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
          },
          "startsAt": {
            "type": "string",
            "description": "Data ou instante ISO 8601."
          }
        },
        "required": [
          "patient",
          "professionalId",
          "procedureId",
          "startsAt"
        ],
        "additionalProperties": false
      },
      "Error": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Código estável, para o parceiro decidir. A mensagem pode mudar."
          },
          "message": {
            "type": "string"
          },
          "details": {
            "type": "object",
            "properties": {
              "fields": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "field": {
                      "type": "string"
                    },
                    "rules": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  },
                  "required": [
                    "field",
                    "rules"
                  ],
                  "additionalProperties": false
                }
              },
              "retryAfterSeconds": {
                "type": "integer"
              },
              "supportId": {
                "type": "string"
              }
            },
            "additionalProperties": false
          }
        },
        "required": [
          "code",
          "message"
        ],
        "additionalProperties": false
      },
      "Procedure": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "professionalId": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "description": "Texto puro, uma linha por bloco."
          },
          "priceCents": {
            "type": "integer"
          },
          "currencyCode": {
            "type": "string"
          },
          "durationMinutes": {
            "type": "integer",
            "nullable": true
          },
          "type": {
            "type": "string"
          },
          "sessionQuantity": {
            "type": "integer",
            "nullable": true,
            "description": "Pacote: só a 1ª sessão se reserva pela API."
          },
          "groupBookable": {
            "type": "boolean",
            "description": "Aceita horário de turma (`group: true`)."
          }
        },
        "required": [
          "id",
          "professionalId",
          "name",
          "description",
          "priceCents",
          "currencyCode",
          "durationMinutes",
          "type",
          "sessionQuantity",
          "groupBookable"
        ],
        "additionalProperties": false
      },
      "ProcedureList": {
        "type": "object",
        "properties": {
          "procedures": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Procedure"
            }
          }
        },
        "required": [
          "procedures"
        ],
        "additionalProperties": false
      },
      "Professional": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "avatarUrl": {
            "type": "string",
            "nullable": true
          },
          "bio": {
            "type": "string",
            "description": "Texto puro."
          },
          "specialties": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "minPatientAge": {
            "type": "integer",
            "nullable": true
          },
          "maxPatientAge": {
            "type": "integer",
            "nullable": true
          },
          "attendedGenders": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "MALE",
                "FEMALE",
                "OTHER"
              ]
            },
            "description": "Vazio: atende todos."
          },
          "minBookingNoticeMinutes": {
            "type": "integer"
          },
          "maxBookingHorizonDays": {
            "type": "integer",
            "description": "0 = sem limite."
          }
        },
        "required": [
          "id",
          "name",
          "avatarUrl",
          "bio",
          "specialties",
          "minPatientAge",
          "maxPatientAge",
          "attendedGenders",
          "minBookingNoticeMinutes",
          "maxBookingHorizonDays"
        ],
        "additionalProperties": false
      },
      "ProfessionalList": {
        "type": "object",
        "properties": {
          "professionals": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Professional"
            }
          }
        },
        "required": [
          "professionals"
        ],
        "additionalProperties": false
      },
      "PublicCheckoutPatientDto": {
        "type": "object",
        "description": "Paciente novo: `name`, `email`, `document`, `birthDate` e `phone` são obrigatórios; `name`, `email`, `document` e `phone` que faltarem voltam juntos em `validation_failed`, com o caminho de cada campo em `details.fields`, e a `birthDate` ausente ou inválida volta em `publicCheckout.patientBirthDateRequired`, nos dois modos. `gender` é obrigatório quando o profissional restringe os sexos atendidos. Paciente da clínica: `useExistingPatient: true`, `document` e `birthDate`; o resto é ignorado.",
        "properties": {
          "useExistingPatient": {
            "type": "boolean"
          },
          "name": {
            "type": "string",
            "maxLength": 120,
            "minLength": 1
          },
          "gender": {
            "type": "string",
            "enum": [
              "MALE",
              "FEMALE",
              "OTHER"
            ]
          },
          "email": {
            "type": "string",
            "maxLength": 160,
            "format": "email"
          },
          "document": {
            "type": "string",
            "maxLength": 18,
            "minLength": 1
          },
          "birthDate": {
            "type": "string",
            "description": "Data ou instante ISO 8601."
          },
          "phone": {
            "type": "string",
            "maxLength": 30,
            "minLength": 1
          }
        },
        "required": [
          "document"
        ],
        "additionalProperties": false
      },
      "Specialty": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          }
        },
        "required": [
          "name"
        ],
        "additionalProperties": false
      },
      "SpecialtyList": {
        "type": "object",
        "properties": {
          "specialties": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Specialty"
            }
          }
        },
        "required": [
          "specialties"
        ],
        "additionalProperties": false
      },
      "WebhookBooking": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "O mesmo id do `POST /bookings`."
          },
          "status": {
            "type": "string",
            "enum": [
              "CONFIRMED",
              "CANCELED"
            ],
            "description": "Só nos eventos da reserva."
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false
      },
      "WebhookEvent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "O id do aviso: se repete em toda tentativa, para descartar a repetição."
          },
          "type": {
            "type": "string",
            "enum": [
              "booking.confirmed",
              "booking.canceled",
              "payment.confirmed"
            ]
          },
          "occurredAt": {
            "type": "string",
            "format": "date-time",
            "description": "Instante UTC do fato."
          },
          "company": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              }
            },
            "required": [
              "id"
            ],
            "additionalProperties": false
          },
          "integration": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "login": {
                "type": "string",
                "description": "O login da clínica."
              }
            },
            "required": [
              "id",
              "login"
            ],
            "additionalProperties": false
          },
          "data": {
            "type": "object",
            "properties": {
              "booking": {
                "$ref": "#/components/schemas/WebhookBooking"
              },
              "payment": {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "PAID"
                    ]
                  }
                },
                "required": [
                  "status"
                ],
                "additionalProperties": false,
                "description": "Só no `payment.confirmed`."
              }
            },
            "required": [
              "booking"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "id",
          "type",
          "occurredAt",
          "company",
          "integration",
          "data"
        ],
        "additionalProperties": false
      }
    }
  }
}
