Appearance
Agendamentos
O agendamento tem duas camadas: o cabeçalho (quem, status, total, código legível para o cliente informar por telefone) e os itens — cada serviço do pacote com seu próprio horário e profissional: corte 10:00–10:30 com a Joana, barba 10:30–10:50 com a mesma Joana, ou manicure e pedicure simultâneas com pessoas diferentes.
Três decisões de design valem ouro na operação:
- Congelamento: nome do serviço, preço e duração são copiados para o item no momento da criação. A tabela pode subir amanhã — o que foi combinado com aquele cliente não muda.
- Janela bloqueada: cada item ocupa a agenda de
startAt - bufferBeforeatéendAt + bufferAfter. O banco recusa sobreposição sobre essa janela, não só sobre o horário do serviço. - Trilha de eventos: toda transição registra status de origem/destino, quem fez (staff, cliente ou sistema) e uma nota. Cancelamentos viram discussão com o cliente — sem trilha você não tem resposta.
Headers obrigatórios
Todas as requisições devem incluir o header X-Booking-Id (UUID) e Authorization: Bearer {token} com o token de um usuário staff. A leitura é livre para qualquer papel; a escrita (criar e transicionar) exige owner, manager ou receptionist (403 FORBIDDEN caso contrário). Usuários professional veem apenas a própria agenda.
Máquina de Estados
O status do agendamento segue transições estritas — fora delas, a API responde 422 INVALID_STATUS_TRANSITION:
| De | Para | Ação | Efeito |
|---|---|---|---|
| (criação) | pending | POST /appointments | Status inicial quando a instância não confirma automaticamente ou algum serviço exige confirmação. |
| (criação) | confirmed | POST /appointments | Quando isAutoConfirm está ligado e nenhum serviço exige confirmação (confirmedAt preenchido). |
pending | confirmed | PATCH .../confirm | Preenche confirmedAt. |
confirmed | confirmed | PATCH .../check-in | Cliente chegou — preenche checkedInAt, sem mudar o status. |
confirmed | completed | PATCH .../complete | Atendimento concluído — preenche completedAt. |
pending / confirmed | canceled | PATCH .../cancel | Cancela em cascata (itens e recursos), registra motivo e autor. |
confirmed | no_show | PATCH .../no-show | Falta do cliente — só após o horário; incrementa totalNoShows. |
pending / confirmed | (novo agendamento) | PATCH .../reschedule | Cria um novo agendamento e cancela o antigo. |
Endpoints
Listar Agendamentos
Lista paginada com filtros de período, status, origem e cliente — a base das telas de histórico.
http
GET /v1/booking/user/appointmentsParâmetros de Query
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
page / perPage | number | Não | Paginação (máx. 100 por página). |
from | string | Não | Início do período (YYYY-MM-DD), aplicado em startsAt. |
to | string | Não | Fim do período (YYYY-MM-DD), aplicado em startsAt. |
status | enum | Não | pending, confirmed, canceled, completed ou no_show. |
source | enum | Não | online, phone, walk_in, admin ou api. |
bookingCustomerId | number | Não | Filtra por cliente. |
search | string | Não | Busca por código ou nome do convidado. |
orderBy | enum | Não | id, startsAt, createdAt ou totalPrice (padrão: startsAt). |
orderDirection | enum | Não | asc ou desc (padrão: desc). |
Exemplo de Requisição
bash
curl -X GET "https://api.us.basis.tavares.in/v1/booking/user/appointments?from=2026-09-01&to=2026-09-30&status=confirmed" \
-H "X-Booking-Id: 3fa85f64-5717-4562-b3fc-2c963f66afa6" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"Respostas
200 OK
Retorna a página de agendamentos com o cliente embutido em cada item.
json
{
"meta": {
"currentPage": 1,
"perPage": 25
},
"data": [
{
"id": 1,
"bookingId": 1,
"code": "X7K2P9",
"bookingCustomerId": 1,
"guestName": null,
"guestPhone": null,
"guestEmail": null,
"status": "confirmed",
"source": "online",
"startsAt": "2026-09-20T14:00:00.000-03:00",
"endsAt": "2026-09-20T14:45:00.000-03:00",
"totalPrice": "80.00",
"totalDurationMinutes": 45,
"createdAt": "2026-09-10T14:22:10.000+00:00",
"updatedAt": "2026-09-10T14:22:10.000+00:00",
"bookingCustomer": {
"id": 1,
"name": "Maria Silva"
}
}
]
}Agenda do Intervalo
A consulta mais executada do módulo: a agenda do dia (ou da semana), ordenada por horário de início, com itens, profissionais, serviços e cliente embutidos — tudo em uma chamada.
http
GET /v1/booking/user/appointments/agendaParâmetros de Query
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
from | string | Sim | Início do intervalo (YYYY-MM-DD). |
to | string | Sim | Fim do intervalo (YYYY-MM-DD). |
bookingProfessionalId | number | Não | Filtra agendamentos que têm itens com o profissional (ignorado para usuários professional — o escopo deles é sempre a própria agenda). |
status | enum | Não | Filtra por status. |
Exemplo de Requisição
bash
curl -X GET "https://api.us.basis.tavares.in/v1/booking/user/appointments/agenda?from=2026-09-20&to=2026-09-20" \
-H "X-Booking-Id: 3fa85f64-5717-4562-b3fc-2c963f66afa6" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"Respostas
200 OK
Retorna o array de agendamentos do intervalo (sem paginação), ordenado por startsAt ascendente.
json
[
{
"id": 1,
"code": "X7K2P9",
"bookingCustomerId": 1,
"status": "confirmed",
"source": "online",
"startsAt": "2026-09-20T14:00:00.000-03:00",
"endsAt": "2026-09-20T14:45:00.000-03:00",
"totalPrice": "80.00",
"totalDurationMinutes": 45,
"bookingCustomer": {
"id": 1,
"name": "Maria Silva",
"phone": "11987654321"
},
"bookingAppointmentItems": [
{
"id": 1,
"bookingServiceId": 1,
"bookingProfessionalId": 1,
"startAt": "2026-09-20T14:00:00.000-03:00",
"endAt": "2026-09-20T14:45:00.000-03:00",
"price": "80.00",
"durationMinutes": 45,
"serviceName": "Corte Masculino",
"bookingProfessional": { "id": 1, "name": "Ana Souza" },
"bookingService": { "id": 1, "name": "Corte Masculino" }
}
]
}
]Criar Agendamento (Staff)
Criação manual pela recepção — telefone, walk-in, encaixe. Tudo roda em uma única transação: cabeçalho, itens, alocação de recursos e o primeiro evento.
O processo, item a item:
- Resolve o serviço (ativo) e o vínculo profissional ↔ serviço, aplicando preço e duração customizados quando existem.
- Calcula
endAt(início + duração) e a janela bloqueada com buffers. - Valida conflito na agenda do profissional (
422 SLOT_UNAVAILABLE). - Aloca o primeiro recurso obrigatório livre (
422 RESOURCE_UNAVAILABLEse todos ocupados). - Congela
serviceName,priceedurationMinutesno item.
O cabeçalho recebe um code legível único (6 caracteres, ex.: X7K2P9), startsAt/endsAt agregados dos itens, totais somados e o status inicial conforme a máquina de estados. Uma notificação de confirmação é enfileirada automaticamente.
http
POST /v1/booking/user/appointmentsPayload (Body)
| Atributo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
bookingCustomerId | number | Condicional | Cliente cadastrado (deve existir na instância). Obrigatório se não houver convidado. |
guestName | string | Condicional | Nome do convidado (máx. 150). Com convidado, exige guestPhone ou guestEmail. |
guestPhone | string | Condicional | Telefone do convidado (máx. 50). |
guestEmail | string | Condicional | E-mail do convidado (válido, máx. 200). |
items | array | Sim | Pelo menos um item (ver abaixo). |
items[].bookingServiceId | number | Sim | Serviço (deve existir e estar ativo na instância). |
items[].bookingProfessionalId | number | Sim | Profissional (deve existir, estar ativo e executar o serviço). |
items[].startAt | string | Sim | Início do atendimento, ISO 8601 com fuso (2026-09-20T14:00:00.000-03:00). |
notes | string | Não | Observações visíveis à equipe (máx. 10000 caracteres). |
Exemplo de Requisição
bash
curl -X POST "https://api.us.basis.tavares.in/v1/booking/user/appointments" \
-H "X-Booking-Id: 3fa85f64-5717-4562-b3fc-2c963f66afa6" \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"bookingCustomerId": 1,
"items": [
{
"bookingServiceId": 1,
"bookingProfessionalId": 1,
"startAt": "2026-09-20T14:00:00.000-03:00"
}
],
"notes": "Cliente pediu atendimento com a Ana."
}'Respostas
201 Created
Retorna o ID e o código legível do agendamento.
json
{
"id": 1,
"code": "X7K2P9"
}422 Unprocessable Entity
Conflito de horário (SLOT_UNAVAILABLE), recurso ocupado (RESOURCE_UNAVAILABLE), profissional que não executa o serviço (PROFESSIONAL_SERVICE_MISMATCH), cliente bloqueado (CUSTOMER_BLOCKED) ou identificação insuficiente (INVALID_CUSTOMER_IDENTITY).
json
{
"message": "Horário indisponível para este profissional",
"code": "SLOT_UNAVAILABLE"
}Obter Agendamento por ID
Detalhe completo: itens (com profissional e serviço), trilha de eventos (com o usuário autor de cada transição) e cliente.
http
GET /v1/booking/user/appointments/:idRespostas
200 OK
Retorna o agendamento com bookingAppointmentItems, bookingAppointmentEvents e bookingCustomer.
json
{
"id": 1,
"code": "X7K2P9",
"status": "confirmed",
"source": "online",
"startsAt": "2026-09-20T14:00:00.000-03:00",
"endsAt": "2026-09-20T14:45:00.000-03:00",
"totalPrice": "80.00",
"totalDurationMinutes": 45,
"notes": "Cliente pediu atendimento com a Ana.",
"internalNotes": null,
"confirmedAt": "2026-09-10T14:22:10.000+00:00",
"checkedInAt": null,
"completedAt": null,
"canceledAt": null,
"bookingCustomer": {
"id": 1,
"name": "Maria Silva",
"email": "maria.silva@email.com",
"phone": "11987654321"
},
"bookingAppointmentItems": [
{
"id": 1,
"startAt": "2026-09-20T14:00:00.000-03:00",
"endAt": "2026-09-20T14:45:00.000-03:00",
"price": "80.00",
"durationMinutes": 45,
"serviceName": "Corte Masculino",
"bookingProfessional": { "id": 1, "name": "Ana Souza" },
"bookingService": { "id": 1, "name": "Corte Masculino" }
}
],
"bookingAppointmentEvents": [
{
"id": 1,
"fromStatus": "confirmed",
"toStatus": "confirmed",
"actorType": "customer",
"bookingUserId": null,
"note": "Agendamento criado",
"createdAt": "2026-09-10T14:22:10.000+00:00",
"bookingUser": null
}
]
}404 Not Found
Ocorre quando o agendamento não existe na instância.
Transições
Todas as transições são PATCH sem payload (exceto cancel e reschedule), respondem 204 No Content no sucesso e registram um evento na trilha. Fora da tabela de transições válidas, respondem 422 INVALID_STATUS_TRANSITION.
Confirmar
http
PATCH /v1/booking/user/appointments/:id/confirmpending → confirmed, preenchendo confirmedAt.
Check-in
http
PATCH /v1/booking/user/appointments/:id/check-inMarca a chegada do cliente (checkedInAt). O status permanece confirmed — o evento registra o check-in na trilha.
Concluir
http
PATCH /v1/booking/user/appointments/:id/completeconfirmed → completed, preenchendo completedAt. Alimenta a receita realizada nas métricas.
Cancelar
http
PATCH /v1/booking/user/appointments/:id/cancel| Atributo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
reason | string | Não | Motivo do cancelamento (máx. 255 caracteres) — vai para a trilha e para o agendamento. |
Exemplo de Requisição
bash
curl -X PATCH "https://api.us.basis.tavares.in/v1/booking/user/appointments/1/cancel" \
-H "X-Booking-Id: 3fa85f64-5717-4562-b3fc-2c963f66afa6" \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{ "reason": "Cliente pediu para cancelar" }'Cancelamento em cascata
O cancelamento marca canceledAt no agendamento, em todos os itens e nos vínculos de recursos — liberando a agenda do profissional e a sala/cadeira na mesma transação. Uma notificação de cancelamento é enfileirada. O staff cancela a qualquer momento; o prazo cancellationDeadlineMinutes só é aplicado no portal do cliente.
No-show
http
PATCH /v1/booking/user/appointments/:id/no-showconfirmed → no_show, somente depois do horário do agendamento (422 APPOINTMENT_NOT_STARTED antes disso). Incrementa totalNoShows do cliente.
Reagendar
http
PATCH /v1/booking/user/appointments/:id/rescheduleCria um novo agendamento (mesma identidade e serviços, novos horários), cancela o antigo com motivo "Reagendado" e registra eventos nos dois. O novo aponta para o antigo em rebookingAppointmentId — a cadeia de reagendamentos fica auditável.
Payload (Body)
| Atributo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
items | array | Sim | Os novos horários — mesmo formato dos itens da criação. |
Exemplo de Requisição
bash
curl -X PATCH "https://api.us.basis.tavares.in/v1/booking/user/appointments/1/reschedule" \
-H "X-Booking-Id: 3fa85f64-5717-4562-b3fc-2c963f66afa6" \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"items": [
{
"bookingServiceId": 1,
"bookingProfessionalId": 1,
"startAt": "2026-09-22T15:00:00.000-03:00"
}
]
}'Respostas
200 OK
Retorna o ID e o código do novo agendamento (o antigo foi cancelado).
json
{
"id": 2,
"code": "M4T8QW"
}422 Unprocessable Entity
Ocorre quando o novo horário conflita (SLOT_UNAVAILABLE) ou o agendamento não está em pending/confirmed (INVALID_STATUS_TRANSITION).