{"openapi":"3.1.0","info":{"title":"API Marcai","version":"1.0.0","summary":"Serviços, equipa, horários livres, marcações e clientes do teu negócio.","description":"Cada chave pertence a um negócio e só vê os dados dele. Cria as chaves no painel, em Programadores, com os scopes de que precisas (uma chave que só lê nunca escreve).\n\n**Limites:** 60 pedidos por minuto por chave; cada resposta traz `X-RateLimit-Limit`, `X-RateLimit-Remaining` e `X-RateLimit-Reset`.\n\n**Erros:** `{ \"error\": { \"code\": \"...\", \"message\": \"...\" } }`. Decide pelo `code`; a `message` é para pessoas.\n\n**Paginação:** `limit` (1–100) e `cursor`. Cada página traz `data`, `has_more` e `next_cursor`.\n\n**Valores:** dinheiro em cêntimos; datas em ISO 8601 (UTC)."},"servers":[{"url":"https://api-production-ca96.up.railway.app/api/v1","description":"API Marcai"}],"tags":[{"name":"Negócio"},{"name":"Catálogo"},{"name":"Disponibilidade"},{"name":"Marcações"},{"name":"Clientes"}],"security":[{"ApiKey":[]}],"paths":{"/me":{"get":{"operationId":"getBusiness","summary":"Negócio da chave","description":"Devolve o negócio a que a chave pertence. Não precisa de nenhum scope.","tags":["Negócio"],"security":[{"ApiKey":[]},{"BearerKey":[]}],"parameters":[],"responses":{"200":{"description":"Sucesso.","headers":{"X-RateLimit-Limit":{"description":"Pedidos permitidos por minuto e por chave (60).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Pedidos que ainda podes fazer nesta janela.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Quando a janela reinicia (segundos desde 1970-01-01 UTC).","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Business"}}}},"401":{"description":"Chave em falta, inválida ou revogada (`unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"A chave não tem o scope necessário, o plano não inclui a API ou a conta está suspensa (`forbidden`, `bookings_closed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Passaste o limite de pedidos. Espera `Retry-After` segundos (`rate_limited`).","headers":{"Retry-After":{"description":"Segundos até poderes tentar de novo.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/services":{"get":{"operationId":"listServices","summary":"Listar serviços","description":"Serviços activos do negócio, por ordem alfabética.","tags":["Catálogo"],"security":[{"ApiKey":[]},{"BearerKey":[]}],"x-required-scope":"read:services","parameters":[{"name":"limit","in":"query","required":false,"description":"Itens por página (1–100).","schema":{"default":25,"type":"integer","minimum":1,"maximum":100}},{"name":"cursor","in":"query","required":false,"description":"`next_cursor` da página anterior. Opaco: não o interpretes.","schema":{"type":"string","minLength":1,"maxLength":200}}],"responses":{"200":{"description":"Sucesso.","headers":{"X-RateLimit-Limit":{"description":"Pedidos permitidos por minuto e por chave (60).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Pedidos que ainda podes fazer nesta janela.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Quando a janela reinicia (segundos desde 1970-01-01 UTC).","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Service"}},"has_more":{"description":"Há mais itens depois desta página.","type":"boolean"},"next_cursor":{"description":"Cursor da página seguinte; null na última.","anyOf":[{"type":"string"},{"type":"null"}]}},"required":["data","has_more","next_cursor"],"additionalProperties":false}}}},"400":{"description":"Pedido inválido (`validation_error`, `invalid_request`, `invalid_range`, `invalid_cursor`…).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Chave em falta, inválida ou revogada (`unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"A chave não tem o scope necessário, o plano não inclui a API ou a conta está suspensa (`forbidden`, `bookings_closed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Passaste o limite de pedidos. Espera `Retry-After` segundos (`rate_limited`).","headers":{"Retry-After":{"description":"Segundos até poderes tentar de novo.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/staff":{"get":{"operationId":"listStaff","summary":"Listar equipa","description":"Profissionais activos, com os serviços que executam. Usa `staff_id` em `/availability` e `/bookings`.","tags":["Catálogo"],"security":[{"ApiKey":[]},{"BearerKey":[]}],"x-required-scope":"read:services","parameters":[{"name":"limit","in":"query","required":false,"description":"Itens por página (1–100).","schema":{"default":25,"type":"integer","minimum":1,"maximum":100}},{"name":"cursor","in":"query","required":false,"description":"`next_cursor` da página anterior. Opaco: não o interpretes.","schema":{"type":"string","minLength":1,"maxLength":200}},{"name":"service_id","in":"query","required":false,"description":"Só quem executa este serviço.","schema":{"type":"string","minLength":1,"maxLength":60}}],"responses":{"200":{"description":"Sucesso.","headers":{"X-RateLimit-Limit":{"description":"Pedidos permitidos por minuto e por chave (60).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Pedidos que ainda podes fazer nesta janela.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Quando a janela reinicia (segundos desde 1970-01-01 UTC).","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Staff"}},"has_more":{"description":"Há mais itens depois desta página.","type":"boolean"},"next_cursor":{"description":"Cursor da página seguinte; null na última.","anyOf":[{"type":"string"},{"type":"null"}]}},"required":["data","has_more","next_cursor"],"additionalProperties":false}}}},"400":{"description":"Pedido inválido (`validation_error`, `invalid_request`, `invalid_range`, `invalid_cursor`…).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Chave em falta, inválida ou revogada (`unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"A chave não tem o scope necessário, o plano não inclui a API ou a conta está suspensa (`forbidden`, `bookings_closed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Passaste o limite de pedidos. Espera `Retry-After` segundos (`rate_limited`).","headers":{"Retry-After":{"description":"Segundos até poderes tentar de novo.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/availability":{"get":{"operationId":"getAvailability","summary":"Horários livres","description":"Horários reais para um serviço, calculados com as mesmas regras da marcação (horário de trabalho, folgas, antecedência, políticas). Sem `staff_id`, cada horário traz o profissional que o Marcai atribui. Intervalo máximo: 14 dias.","tags":["Disponibilidade"],"security":[{"ApiKey":[]},{"BearerKey":[]}],"x-required-scope":"read:availability","parameters":[{"name":"service_id","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":60}},{"name":"staff_id","in":"query","required":false,"description":"Sem esta indicação, o Marcai escolhe quem fica com cada horário.","schema":{"type":"string","minLength":1,"maxLength":60}},{"name":"from","in":"query","required":true,"description":"Primeiro dia (fuso do negócio).","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},{"name":"to","in":"query","required":false,"description":"Último dia, inclusive. Por omissão igual a `from`; máximo 14 dias.","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},{"name":"location_id","in":"query","required":false,"schema":{"type":"string","minLength":1,"maxLength":60}}],"responses":{"200":{"description":"Sucesso.","headers":{"X-RateLimit-Limit":{"description":"Pedidos permitidos por minuto e por chave (60).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Pedidos que ainda podes fazer nesta janela.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Quando a janela reinicia (segundos desde 1970-01-01 UTC).","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"start_at":{"description":"Início (UTC, ISO 8601).","type":"string","format":"date-time"},"end_at":{"type":"string","format":"date-time"},"staff_id":{"type":"string"},"label":{"description":"Hora local legível, no fuso do negócio.","type":"string"}},"required":["start_at","end_at","staff_id","label"],"additionalProperties":false}}},"required":["data"],"additionalProperties":false}}}},"400":{"description":"Pedido inválido (`validation_error`, `invalid_request`, `invalid_range`, `invalid_cursor`…).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Chave em falta, inválida ou revogada (`unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"A chave não tem o scope necessário, o plano não inclui a API ou a conta está suspensa (`forbidden`, `bookings_closed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"O recurso não existe neste negócio (`not_found`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Passaste o limite de pedidos. Espera `Retry-After` segundos (`rate_limited`).","headers":{"Retry-After":{"description":"Segundos até poderes tentar de novo.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bookings":{"get":{"operationId":"listBookings","summary":"Listar marcações","description":"Da mais recente para a mais antiga (por início). Filtra por datas, estado, cliente ou profissional.","tags":["Marcações"],"security":[{"ApiKey":[]},{"BearerKey":[]}],"x-required-scope":"read:bookings","parameters":[{"name":"limit","in":"query","required":false,"description":"Itens por página (1–100).","schema":{"default":25,"type":"integer","minimum":1,"maximum":100}},{"name":"cursor","in":"query","required":false,"description":"`next_cursor` da página anterior. Opaco: não o interpretes.","schema":{"type":"string","minLength":1,"maxLength":200}},{"name":"from","in":"query","required":false,"description":"Marcações que começam a partir de (ISO 8601).","schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"description":"Marcações que começam antes de (ISO 8601).","schema":{"type":"string","format":"date-time"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["requested","draft","held","pending_payment","pending","confirmed","cancelled","reschedule_requested","rescheduled","checked_in","in_progress","completed","no_show","expired","rejected","cancelled_by_customer","cancelled_by_business"]}},{"name":"client_id","in":"query","required":false,"schema":{"type":"string","minLength":1,"maxLength":60}},{"name":"staff_id","in":"query","required":false,"schema":{"type":"string","minLength":1,"maxLength":60}}],"responses":{"200":{"description":"Sucesso.","headers":{"X-RateLimit-Limit":{"description":"Pedidos permitidos por minuto e por chave (60).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Pedidos que ainda podes fazer nesta janela.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Quando a janela reinicia (segundos desde 1970-01-01 UTC).","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Booking"}},"has_more":{"description":"Há mais itens depois desta página.","type":"boolean"},"next_cursor":{"description":"Cursor da página seguinte; null na última.","anyOf":[{"type":"string"},{"type":"null"}]}},"required":["data","has_more","next_cursor"],"additionalProperties":false}}}},"400":{"description":"Pedido inválido (`validation_error`, `invalid_request`, `invalid_range`, `invalid_cursor`…).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Chave em falta, inválida ou revogada (`unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"A chave não tem o scope necessário, o plano não inclui a API ou a conta está suspensa (`forbidden`, `bookings_closed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Passaste o limite de pedidos. Espera `Retry-After` segundos (`rate_limited`).","headers":{"Retry-After":{"description":"Segundos até poderes tentar de novo.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createBooking","summary":"Criar uma marcação","description":"Cria a marcação depois de revalidar a disponibilidade no servidor, com as mesmas regras e limites da marcação normal. Serviços que exigem pagamento antecipado não se marcam por aqui. Envia sempre um `Idempotency-Key`: repetir o pedido com a mesma chave devolve a resposta original em vez de criar outra marcação.","tags":["Marcações"],"security":[{"ApiKey":[]},{"BearerKey":[]}],"x-required-scope":"write:bookings","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Valor único por operação (ex.: um UUID). Repetir o pedido com o mesmo valor, nas 24 h seguintes, devolve a resposta original (cabeçalho `Idempotent-Replayed: true`) sem repetir a operação.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"service_id":{"type":"string","minLength":1,"maxLength":60},"staff_id":{"type":"string","minLength":1,"maxLength":60},"start_at":{"description":"Início desejado (ISO 8601); vem de `GET /availability`.","type":"string","format":"date-time"},"location_id":{"type":"string","minLength":1,"maxLength":60},"client_id":{"description":"Cliente já existente. Em alternativa a `client`.","type":"string","minLength":1,"maxLength":60},"client":{"description":"Dados do cliente; é reconhecido por email/telefone ou criado.","type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":120},"email":{"type":"string","maxLength":200,"format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"phone":{"type":"string","maxLength":30}},"required":["name"]},"notes":{"type":"string","maxLength":1000}},"required":["service_id","staff_id","start_at"],"additionalProperties":false}}}},"responses":{"201":{"description":"Sucesso.","headers":{"X-RateLimit-Limit":{"description":"Pedidos permitidos por minuto e por chave (60).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Pedidos que ainda podes fazer nesta janela.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Quando a janela reinicia (segundos desde 1970-01-01 UTC).","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Booking"}}}},"400":{"description":"Pedido inválido (`validation_error`, `invalid_request`, `invalid_range`, `invalid_cursor`…).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Chave em falta, inválida ou revogada (`unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"A chave não tem o scope necessário, o plano não inclui a API ou a conta está suspensa (`forbidden`, `bookings_closed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"O recurso não existe neste negócio (`not_found`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflito: o horário já não está livre ou o pedido está em curso (`conflict`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Passaste o limite de pedidos. Espera `Retry-After` segundos (`rate_limited`).","headers":{"Retry-After":{"description":"Segundos até poderes tentar de novo.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bookings/{id}":{"get":{"operationId":"getBooking","summary":"Ver uma marcação","tags":["Marcações"],"security":[{"ApiKey":[]},{"BearerKey":[]}],"x-required-scope":"read:bookings","parameters":[{"name":"id","in":"path","required":true,"description":"Id da marcação.","schema":{"type":"string"}}],"responses":{"200":{"description":"Sucesso.","headers":{"X-RateLimit-Limit":{"description":"Pedidos permitidos por minuto e por chave (60).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Pedidos que ainda podes fazer nesta janela.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Quando a janela reinicia (segundos desde 1970-01-01 UTC).","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Booking"}}}},"401":{"description":"Chave em falta, inválida ou revogada (`unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"A chave não tem o scope necessário, o plano não inclui a API ou a conta está suspensa (`forbidden`, `bookings_closed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"O recurso não existe neste negócio (`not_found`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Passaste o limite de pedidos. Espera `Retry-After` segundos (`rate_limited`).","headers":{"Retry-After":{"description":"Segundos até poderes tentar de novo.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"updateBooking","summary":"Remarcar ou cancelar","description":"Com `start_at`, remarca: o Marcai revalida o horário, a marcação antiga passa a `rescheduled` e a resposta é a **nova** marcação (novo `id`, com `rescheduled_from_id`). Com `status: \"cancelled\"`, cancela (cancelar uma marcação já cancelada não faz nada e devolve-a). Aceita `Idempotency-Key`.","tags":["Marcações"],"security":[{"ApiKey":[]},{"BearerKey":[]}],"x-required-scope":"write:bookings","parameters":[{"name":"id","in":"path","required":true,"description":"Id da marcação.","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Valor único por operação (ex.: um UUID). Repetir o pedido com o mesmo valor, nas 24 h seguintes, devolve a resposta original (cabeçalho `Idempotent-Replayed: true`) sem repetir a operação.","schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"start_at":{"description":"Novo início: remarca a marcação.","type":"string","format":"date-time"}},"required":["start_at"],"additionalProperties":false},{"type":"object","properties":{"status":{"description":"Cancela a marcação.","type":"string","const":"cancelled"},"reason":{"type":"string","minLength":3,"maxLength":280}},"required":["status"],"additionalProperties":false}]}}}},"responses":{"200":{"description":"Sucesso.","headers":{"X-RateLimit-Limit":{"description":"Pedidos permitidos por minuto e por chave (60).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Pedidos que ainda podes fazer nesta janela.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Quando a janela reinicia (segundos desde 1970-01-01 UTC).","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Booking"}}}},"400":{"description":"Pedido inválido (`validation_error`, `invalid_request`, `invalid_range`, `invalid_cursor`…).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Chave em falta, inválida ou revogada (`unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"A chave não tem o scope necessário, o plano não inclui a API ou a conta está suspensa (`forbidden`, `bookings_closed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"O recurso não existe neste negócio (`not_found`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflito: o horário já não está livre ou o pedido está em curso (`conflict`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Passaste o limite de pedidos. Espera `Retry-After` segundos (`rate_limited`).","headers":{"Retry-After":{"description":"Segundos até poderes tentar de novo.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/clients":{"get":{"operationId":"listClients","summary":"Listar clientes","description":"Do mais recente para o mais antigo. `q` procura por nome, email ou telefone.","tags":["Clientes"],"security":[{"ApiKey":[]},{"BearerKey":[]}],"x-required-scope":"read:clients","parameters":[{"name":"limit","in":"query","required":false,"description":"Itens por página (1–100).","schema":{"default":25,"type":"integer","minimum":1,"maximum":100}},{"name":"cursor","in":"query","required":false,"description":"`next_cursor` da página anterior. Opaco: não o interpretes.","schema":{"type":"string","minLength":1,"maxLength":200}},{"name":"q","in":"query","required":false,"description":"Procura por nome, email ou telefone.","schema":{"type":"string","minLength":2,"maxLength":80}}],"responses":{"200":{"description":"Sucesso.","headers":{"X-RateLimit-Limit":{"description":"Pedidos permitidos por minuto e por chave (60).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Pedidos que ainda podes fazer nesta janela.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Quando a janela reinicia (segundos desde 1970-01-01 UTC).","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Client"}},"has_more":{"description":"Há mais itens depois desta página.","type":"boolean"},"next_cursor":{"description":"Cursor da página seguinte; null na última.","anyOf":[{"type":"string"},{"type":"null"}]}},"required":["data","has_more","next_cursor"],"additionalProperties":false}}}},"400":{"description":"Pedido inválido (`validation_error`, `invalid_request`, `invalid_range`, `invalid_cursor`…).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Chave em falta, inválida ou revogada (`unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"A chave não tem o scope necessário, o plano não inclui a API ou a conta está suspensa (`forbidden`, `bookings_closed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Passaste o limite de pedidos. Espera `Retry-After` segundos (`rate_limited`).","headers":{"Retry-After":{"description":"Segundos até poderes tentar de novo.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"ApiKey":{"type":"apiKey","in":"header","name":"x-api-key","description":"A tua chave (`mk_live_…`)."},"BearerKey":{"type":"http","scheme":"bearer","description":"A mesma chave, em `Authorization: Bearer mk_live_…`."}},"schemas":{"Business":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"timezone":{"type":"string"},"currency":{"type":"string"},"country":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","slug","timezone","currency","country"],"additionalProperties":false},"Service":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"duration_minutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"price":{"description":"Preço em cêntimos.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"promo_price":{"description":"Preço promocional em cêntimos, se houver.","anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"currency":{"description":"Código ISO 4217.","type":"string"},"is_public":{"description":"Visível na página pública de marcação.","type":"boolean"}},"required":["id","name","description","duration_minutes","price","promo_price","currency","is_public"],"additionalProperties":false},"Staff":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"title":{"anyOf":[{"type":"string"},{"type":"null"}]},"is_public":{"type":"boolean"},"service_ids":{"description":"Serviços que esta pessoa executa.","type":"array","items":{"type":"string"}}},"required":["id","name","title","is_public","service_ids"],"additionalProperties":false},"Slot":{"type":"object","properties":{"start_at":{"description":"Início (UTC, ISO 8601).","type":"string","format":"date-time"},"end_at":{"type":"string","format":"date-time"},"staff_id":{"type":"string"},"label":{"description":"Hora local legível, no fuso do negócio.","type":"string"}},"required":["start_at","end_at","staff_id","label"],"additionalProperties":false},"Booking":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["requested","draft","held","pending_payment","pending","confirmed","cancelled","reschedule_requested","rescheduled","checked_in","in_progress","completed","no_show","expired","rejected","cancelled_by_customer","cancelled_by_business"]},"start_at":{"type":"string","format":"date-time"},"end_at":{"type":"string","format":"date-time"},"duration_minutes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"price":{"description":"Preço estimado em cêntimos.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"service":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false},"staff":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false},"client":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false},"source":{"description":"Origem da marcação (ex.: `API`, `PUBLIC_SITE`).","type":"string"},"notes":{"description":"Notas do cliente.","anyOf":[{"type":"string"},{"type":"null"}]},"rescheduled_from_id":{"description":"Marcação que esta substituiu, quando veio de uma remarcação.","anyOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string","format":"date-time"}},"required":["id","status","start_at","end_at","duration_minutes","price","service","staff","client","source","notes","rescheduled_from_id","created_at"],"additionalProperties":false},"Client":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string"},"total_bookings":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"last_visit_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"created_at":{"type":"string","format":"date-time"}},"required":["id","name","email","phone","status","total_bookings","last_visit_at","created_at"],"additionalProperties":false},"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"description":"Código estável, para o teu código decidir.","type":"string"},"message":{"description":"Mensagem em português, para mostrar a pessoas.","type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}},"x-scopes":{"read:services":"Ler serviços e equipa","read:availability":"Consultar horários livres","read:bookings":"Ler marcações","write:bookings":"Criar, remarcar e cancelar marcações","read:clients":"Ler clientes"}}