MATS API — Referência Completa
Base URL: https://api.withmats.com/api
Autenticação: Bearer token (JWT) — Authorization: Bearer <accessToken>
Content-Type: application/json (exceto uploads multipart)
Valores monetários: sempre em centavos (inteiro). Ex.: R$ 150,00 → 15000
Datas: ISO 8601 — YYYY-MM-DD (datas) e HH:mm (horários)
Respostas de erro
Todos os erros seguem o envelope:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Descrição legível"
}
}| HTTP | code | Quando ocorre |
|---|---|---|
| 400 | VALIDATION_ERROR | Body/params/query inválidos (Zod) |
| 401 | UNAUTHORIZED | Token ausente, expirado ou inválido |
| 403 | FORBIDDEN | Sem permissão para o recurso |
| 404 | NOT_FOUND | Recurso não existe |
| 409 | CONFLICT | Conflito de estado (ex.: e-mail já cadastrado) |
| 422 | VALIDATION_ERROR | Regra de negócio violada |
| 429 | — | Rate limit atingido |
| 500 | INTERNAL_ERROR | Erro inesperado do servidor |
Health
GET /healthResposta 200:
{ "status": "ok" }Autenticação
Login
POST /api/auth/loginRate limit: 5 req / 15 min.
Body:
{
"email": "usuario@email.com",
"password": "senha123"
}Resposta 200:
{
"accessToken": "<jwt>",
"refreshToken": "<uuid>",
"user": {
"id": "<uuid>",
"tipo": "at",
"nomeCompleto": "Maria Santos",
"email": "usuario@email.com",
"emailVerificado": false,
"telefoneVerificado": false
}
}tipo: at | familia
Refresh de token
POST /api/auth/refreshBody:
{ "refreshToken": "<uuid>" }Resposta 200:
{
"accessToken": "<jwt>",
"refreshToken": "<novo-uuid>"
}O refresh token anterior é revogado (rotação automática).
Logout
POST /api/auth/logoutBody:
{ "refreshToken": "<uuid>" }Resposta 204: sem body.
Esqueci minha senha
POST /api/auth/forgot-passwordRate limit: 5 req / 1 hora.
Body:
{ "email": "usuario@email.com" }Resposta 200: { "ok": true }
Envia e-mail com token de reset.
Resetar senha
POST /api/auth/reset-passwordRate limit: 5 req / 1 hora.
Body:
{
"token": "<token-do-email>",
"password": "novaSenha123",
"passwordConfirmation": "novaSenha123"
}password: mínimo 8 caracteres. Deve coincidir com passwordConfirmation.
Resposta 200: { "ok": true }
Cadastro — AT
Etapa 1: Dados pessoais
POST /api/auth/register/atRate limit: 10 req / 1 hora.
Body:
{
"nomeCompleto": "Maria Santos",
"cpf": "12345678901",
"email": "maria@email.com",
"telefone": "11999990000",
"cidade": "São Paulo",
"estado": "SP",
"password": "senha123",
"passwordConfirmation": "senha123"
}| Campo | Regras |
|---|---|
cpf | Exatamente 11 dígitos numéricos, com validação de dígitos verificadores |
estado | 2 letras (UF) |
telefone | Mínimo 10 dígitos |
password | Mínimo 8 caracteres |
Resposta 201:
{
"accessToken": "<jwt>",
"refreshToken": "<uuid>",
"user": { "id": "<uuid>", "tipo": "at", ... }
}Etapa 2: Upload de documentos
POST /api/auth/register/at/documentosAuth obrigatória. Multipart form-data. Limite: 10 MB por arquivo.
| Campo multipart | Tipo | Descrição |
|---|---|---|
certificado | file | Certificado de formação (PDF/JPG/PNG) |
antecedentes | file | Certidão de antecedentes criminais (PDF/JPG/PNG) |
foto_perfil | file | Foto de perfil (JPG/PNG) |
Resposta 200: { "ok": true }
Após o upload, o status do AT muda para
em_analise. Aprovação feita pelo admin.
Cadastro — Família
Etapa 1: Dados do responsável
POST /api/auth/register/familiaRate limit: 10 req / 1 hora.
Body:
{
"nomeCompleto": "Carlos Lima",
"cpf": "98765432100",
"email": "carlos@email.com",
"telefone": "11988880000",
"endereco": {
"logradouro": "Rua das Flores",
"numero": "42",
"complemento": "Apto 3",
"bairro": "Centro",
"cidade": "São Paulo",
"estado": "SP",
"cep": "01310100"
},
"password": "senha123",
"passwordConfirmation": "senha123"
}complemento opcional. cep exatamente 8 dígitos.
Resposta 201:
{
"accessToken": "<jwt>",
"refreshToken": "<uuid>",
"user": { "id": "<uuid>", "tipo": "familia", ... }
}Etapa 2: Cadastrar criança
POST /api/auth/register/familia/criancaBody:
{
"familiaId": "<uuid>",
"nome": "Enzo Lima",
"cpf": "11122233344",
"dataNascimento": "2018-03-15",
"diagnostico": "tea"
}cpf opcional.diagnostico: tea | tdah | outro | aguardando_diagnostico
Resposta 201: { "crianca": { "id": "<uuid>", ... } }
Etapa 3: Upload de laudo
POST /api/auth/register/familia/laudoMultipart form-data.
| Campo multipart | Tipo | Descrição |
|---|---|---|
criancaId | text | UUID da criança |
laudo | file | Arquivo do laudo médico (PDF/JPG/PNG) |
Resposta 200: { "ok": true }
Etapa 4: Necessidades da criança
POST /api/auth/register/familia/necessidadesBody:
{
"criancaId": "<uuid>",
"necessidadesEspecificas": "Precisa de ambiente calmo",
"contextoEscolar": "Escola regular com suporte",
"objetivosTerapeuticos": "Desenvolver comunicação verbal",
"preferenciasHorario": ["manha", "tarde"],
"localPreferido": "casa"
}preferenciasHorario: array com manha | tarde | noitelocalPreferido: casa | escola | outro
Resposta 200: { "ok": true }
Verificação
Enviar código de verificação de e-mail
POST /api/verify/email/sendBody:
{ "email": "usuario@email.com" }Resposta 200: { "ok": true }
Verificar e-mail
POST /api/verify/emailAuth obrigatória.
Body:
{ "codigo": "123456" }codigo: exatamente 6 dígitos.
Resposta 200: { "ok": true }
Verificar telefone
POST /api/verify/phoneAuth obrigatória.
Body:
{ "codigo": "123456" }Resposta 200: { "ok": true }
Reenviar código de telefone
POST /api/verify/phone/resendAuth obrigatória. Sem body.
Resposta 200: { "ok": true }
AT — Perfil
Obter próprio perfil
GET /api/at/perfilAuth obrigatória (tipo: at).
Resposta 200:
{
"id": "<uuid>",
"userId": "<uuid>",
"status": "em_analise",
"bio": "Texto de apresentação",
"especializacoes": ["TEA", "TDAH"],
"formacao": "Psicologia - USP",
"certificacoes": "Certificado X",
"valorSessao": 15000,
"regiaoAtendimento": "Zona Sul",
"cidade": "São Paulo",
"estado": "SP",
"genero": "masculino",
"fotoUrl": "https://...",
"saldoDisponivel": 87000,
"cancelamentos30d": 0
}status: em_analise | verificado | pendencias | suspenso | rejeitadogenero: masculino | feminino | outro | prefiro_nao_informarvalorSessao e saldoDisponivel em centavos.
Atualizar perfil
PATCH /api/at/perfilAuth obrigatória (tipo: at).
Body (todos opcionais):
{
"bio": "Nova bio",
"especializacoes": ["TEA"],
"formacao": "Psicologia - USP",
"certificacoes": "Cert. Y",
"valorSessao": 18000,
"regiaoAtendimento": "Zona Norte",
"genero": "feminino"
}Alteração de
valorSessaoreflete apenas em novas solicitações.
Resposta 200: perfil atualizado.
Atualizar foto de perfil
POST /api/at/perfil/fotoAuth obrigatória (tipo: at). Multipart form-data.
Campo multipart: foto (file, imagem).
Resposta 200: { "fotoUrl": "https://..." }
Perfil público de um AT
GET /api/at/perfil/publico/:atIdAuth obrigatória.
Retorna dados públicos do AT: nome, bio, especializações, formação, valor/sessão, disponibilidade, avaliação média, total de reviews. Não retorna saldo, dados financeiros, CPF ou telefone.
Resposta 200:
{
"data": {
"id": "<uuid>",
"nomeCompleto": "Maria Santos",
"bio": "AT com foco em acompanhamento escolar",
"especializacoes": ["TEA", "ABA"],
"formacao": "Psicologia - USP",
"valorSessao": 15000,
"regiaoAtendimento": "Zona Sul",
"cidade": "São Paulo",
"estado": "SP",
"genero": "feminino",
"fotoUrl": "https://...",
"disponibilidade": {
"recorrente": {
"segunda": ["manha", "tarde"],
"sexta": ["noite"]
},
"bloqueios": [
{
"id": "<uuid>",
"atId": "<uuid>",
"data": "2026-05-01T00:00:00.000Z",
"horarioInicio": null,
"horarioFim": null,
"motivo": "Feriado",
"createdAt": "2026-04-22T12:00:00.000Z"
}
]
},
"avaliacaoMedia": 4.8,
"totalReviews": 12
}
}AT — Disponibilidade
Obter disponibilidade
GET /api/at/disponibilidadeAuth obrigatória (tipo: at).
Resposta 200:
{
"horarios": {
"segunda": ["manha", "tarde"],
"sexta": ["noite"]
}
}Atualizar disponibilidade
PUT /api/at/disponibilidadeAuth obrigatória (tipo: at).
Body:
{
"horarios": {
"segunda": ["manha", "tarde"],
"quarta": ["tarde"],
"sexta": ["manha", "noite"]
}
}Dias válidos: segunda | terca | quarta | quinta | sexta | sabado | domingo
Turnos válidos: manha | tarde | noite
Resposta 200: { "ok": true }
Adicionar bloqueio de agenda
POST /api/at/disponibilidade/bloqueioAuth obrigatória (tipo: at).
Body:
{
"data": "2026-05-10",
"horarioInicio": "09:00",
"horarioFim": "12:00",
"motivo": "Consulta médica"
}horarioInicio, horarioFim e motivo são opcionais. Omitindo horarioInicio/horarioFim, o dia inteiro é bloqueado.
Resposta 201: { "bloqueio": { "id": "<uuid>", ... } }
Remover bloqueio
DELETE /api/at/disponibilidade/bloqueio/:bloqueioIdAuth obrigatória (tipo: at).
Resposta 204: sem body.
AT — Documentos
Reenviar documento recusado
PUT /api/at/documentos/:tipoAuth obrigatória (tipo: at). Multipart form-data.
| Param | Valores aceitos |
|---|---|
tipo | antecedentes | certificado |
Campo multipart: arquivo do documento (file).
Resposta 204: sem body.
Ao reenviar, o documento volta ao status
em_analisepara revisão do admin.
AT — Pacientes
Listar pacientes
GET /api/at/pacientes?status=ativo&busca=EnzoAuth obrigatória (tipo: at).
| Query param | Tipo | Descrição |
|---|---|---|
status | string? | ativo | inativo | pausado | encerrado |
busca | string? | Busca por nome da criança |
Resposta 200: array de vínculos com dados da criança.
Detalhe de paciente
GET /api/at/pacientes/:criancaIdAuth obrigatória (tipo: at).
Resposta 200: dados completos do vínculo + criança + histórico de sessões.
Atualizar status do vínculo
PATCH /api/at/pacientes/:criancaId/vinculoAuth obrigatória (tipo: at).
Body:
{ "status": "pausado" }status: pausado | encerrado
Resposta 200: { "ok": true }
Busca de ATs
GET /api/ats?cidade=São+Paulo&page=1Rota pública — sem autenticação.
| Query param | Obrigatório | Tipo | Descrição |
|---|---|---|---|
cidade | ✅ | string | Filtra ATs pela cidade (case-insensitive) |
page | ❌ | number | Página (default: 1) |
especializacao | ❌ | string | Filtra por especialização exata |
genero | ❌ | string | masculino | feminino | outro | prefiro_nao_informar |
valorMax | ❌ | number | Valor máximo por sessão (centavos) |
Retorna apenas ATs com status = verificado. Paginação fixa em 10 por página.
Resposta 200:
{
"items": [
{
"id": "<uuid>",
"nomeCompleto": "Maria Santos",
"bio": "Especialista em TEA com 5 anos de experiência",
"especializacoes": ["TEA", "TDAH"],
"valorSessao": 15000,
"regiaoAtendimento": "Zona Sul",
"cidade": "São Paulo",
"estado": "SP",
"genero": "feminino",
"fotoUrl": "https://...",
"avaliacaoMedia": 4.8,
"totalReviews": 12
}
],
"total": 47,
"page": 1,
"totalPages": 5,
"pageSize": 10
}avaliacaoMedia é null quando o AT ainda não tem reviews.
Família — Perfil
Obter perfil
GET /api/familia/perfilAuth obrigatória (tipo: familia).
Resposta 200:
{
"id": "<uuid>",
"userId": "<uuid>",
"enderecoLogradouro": "Rua das Flores",
"enderecoNumero": "42",
"enderecoComplemento": null,
"enderecoBairro": "Centro",
"enderecoCidade": "São Paulo",
"enderecoEstado": "SP",
"enderecoCep": "01310100",
"user": { "nomeCompleto": "Carlos Lima", "email": "carlos@email.com" },
"criancas": [ ... ]
}Atualizar perfil
PATCH /api/familia/perfilAuth obrigatória (tipo: familia).
Body (todos opcionais):
{
"endereco": {
"logradouro": "Rua das Flores",
"numero": "42",
"complemento": "Apto 12",
"bairro": "Centro",
"cidade": "São Paulo",
"estado": "SP",
"cep": "01310100"
}
}Resposta 200: perfil atualizado.
Família — Crianças
Listar crianças
GET /api/familia/criancasAuth obrigatória (tipo: familia).
Resposta 200: array de crianças da família.
Detalhe de criança
GET /api/familia/criancas/:criancaIdAuth obrigatória (tipo: familia).
Resposta 200: dados completos da criança.
Adicionar criança
POST /api/familia/criancasAuth obrigatória (tipo: familia).
Body:
{
"nome": "Ana Lima",
"cpf": "11122233344",
"dataNascimento": "2019-07-20",
"diagnostico": "tdah"
}cpf opcional.diagnostico: tea | tdah | outro | aguardando_diagnostico
Resposta 201: { "crianca": { "id": "<uuid>", ... } }
Atualizar criança
PATCH /api/familia/criancas/:criancaIdAuth obrigatória (tipo: familia). Body igual ao POST, todos os campos opcionais.
Resposta 200: criança atualizada.
Remover criança
DELETE /api/familia/criancas/:criancaIdAuth obrigatória (tipo: familia).
Resposta 204: sem body.
Upload / atualização de laudo
POST /api/familia/criancas/:criancaId/laudoAuth obrigatória (tipo: familia). Multipart form-data.
Campo multipart: laudo (file, PDF/JPG/PNG).
Resposta 200: { "laudoUrl": "https://..." }
Atualizar necessidades da criança
PATCH /api/familia/criancas/:criancaId/necessidadesAuth obrigatória (tipo: familia).
Body:
{
"necessidadesEspecificas": "...",
"contextoEscolar": "...",
"objetivosTerapeuticos": "...",
"preferenciasHorario": ["manha"],
"localPreferido": "escola"
}Resposta 200: { "ok": true }
Busca de ATs (família autenticada)
GET /api/familia/buscar-ats?cidade=São+PauloAuth obrigatória (tipo: familia). Mesmos parâmetros e resposta que GET /api/ats.
Fluxo de Solicitação de Sessão
A
Sessaoreal só é criada após pagamento confirmado. O fluxo completo é:Família solicita → AT confirma → Família paga → Sessão criada
Estados da SolicitacaoSessao
| Status | Significado |
|---|---|
aguardando_confirmacao_at | Família criou; AT ainda não respondeu (expira em 24h) |
aguardando_pagamento | AT confirmou; aguardando pagamento da família |
confirmada | Família pagou — Sessao real foi criada e solicitação é removida |
cancelada | AT recusou ou família cancelou |
expirada | AT não respondeu em 24h (job automático) |
Criar solicitação (família)
POST /api/solicitacoesAuth obrigatória (tipo: familia).
Body:
{
"atId": "<uuid>",
"criancaId": "<uuid>",
"data": "2026-05-15",
"horarioInicio": "09:00",
"local": "casa",
"enderecoCustom": "Rua X, 10",
"valorSugerido": 15000
}| Campo | Obrigatório | Descrição |
|---|---|---|
atId | ✅ | UUID do AT (deve estar verificado) |
criancaId | ✅ | UUID da criança (deve pertencer à família) |
data | ✅ | YYYY-MM-DD |
horarioInicio | ✅ | HH:mm |
local | ✅ | casa | escola | outro |
enderecoCustom | Condicional | Obrigatório quando local = "outro" |
valorSugerido | ❌ | Em centavos; se omitido, usa at.valorSessao |
Resposta 201: SolicitacaoSessao com status: "aguardando_confirmacao_at".
Nenhum pagamento é gerado neste momento. O AT tem 24h para responder antes da solicitação expirar automaticamente.
Confirmar solicitação (AT)
POST /api/solicitacoes/:solicitacaoId/confirmarAuth obrigatória (tipo: at).
Body (ambos opcionais — para sugerir novo horário):
{
"novaData": "2026-05-16",
"novoHorarioInicio": "10:00"
}aguardando_confirmacao_at → aguardando_pagamento
Ao confirmar, a cobrança Asaas (ou mock) é gerada e vinculada à solicitação. A família deve então efetuar o pagamento.
Resposta 200: SolicitacaoSessao atualizada com status: "aguardando_pagamento".
Recusar solicitação (AT)
POST /api/solicitacoes/:solicitacaoId/recusarAuth obrigatória (tipo: at).
Body:
{ "motivo": "Indisponível na data" }motivo opcional.
Válido nos estados: aguardando_confirmacao_at ou aguardando_pagamento.
Se o pagamento já tiver sido realizado, o reembolso é marcado automaticamente.
Resposta 204: sem body.
Pagar solicitação (família)
POST /api/solicitacoes/:solicitacaoId/pagarAuth obrigatória (tipo: familia). Sem body.
aguardando_pagamento → confirmada (transacional)
Em uma única transação:
- Pagamento marcado como
pago Sessaocriada comstatus: "confirmada"- Vínculo AT↔criança criado (ou mantido se já existe)
- Pagamento migrado da solicitação para a sessão
SolicitacaoSessaoremovida
Resposta 200: Sessao criada.
Em produção, esse passo acontece automaticamente via webhook do Asaas (
PAYMENT_CONFIRMED). Esta rota existe para testes com mock de pagamento.
Listar solicitações
GET /api/solicitacoes?status=aguardando_confirmacao_at&page=1&limit=20Auth obrigatória. AT vê as suas; família vê as suas.
| Query param | Tipo | Descrição |
|---|---|---|
status | string? | Filtrar por status (ver tabela de estados) |
page | number | Default: 1 |
limit | number | Default: 20, max: 50 |
Resposta 200:
{
"data": {
"data": [
{
"id": "<uuid>",
"status": "aguardando_confirmacao_at",
"scheduledAt": "2026-05-15T09:00:00.000-03:00",
"valor": 15000,
"local": "casa",
"at": { "user": { "nomeCompleto": "Maria Santos" } },
"crianca": { "nome": "Enzo", "diagnostico": "tea" },
"pagamento": null
}
],
"meta": { "total": 3, "page": 1, "limit": 20 }
}
}Detalhe de solicitação
GET /api/solicitacoes/:solicitacaoIdAuth obrigatória. Família vê as próprias; AT vê as que são dele.
Resposta 200: SolicitacaoSessao com at, crianca e pagamento incluídos.
Sessões
Sessões são criadas automaticamente após o pagamento de uma solicitação.
Não existePOST /api/sessoes— use/api/solicitacoespara iniciar o agendamento.
Estados da Sessao
| Status | Descrição |
|---|---|
agendada | Criada (após pagamento), aguardando chegada da data |
confirmada | Confirmada e pronta para check-in |
em_checkin | AT iniciou o check-in; código gerado, aguardando validação |
em_andamento | Código de check-in validado; sessão em curso |
finalizada | Check-out realizado; split 87/13 aplicado |
cancelada | Cancelada por AT, família ou sistema |
Listar sessões
GET /api/sessoes?tab=proximas&page=1&limit=20Auth obrigatória.
| Query param | Tipo | Descrição |
|---|---|---|
tab | string | proximas | historico — default: proximas |
criancaId | uuid? | Filtrar por criança (família) |
mes | string? | Filtrar por mês (2026-05) |
page | number | Default: 1 |
limit | number | Default: 20, max: 50 |
proximas: status agendada, confirmada, em_checkin, em_andamento.historico: status finalizada, cancelada.
Resposta 200:
{
"data": [
{
"id": "<uuid>",
"status": "confirmada",
"scheduledAt": "2026-05-15T09:00:00.000-03:00",
"valor": 15000,
"local": "casa"
}
],
"meta": { "total": 10, "page": 1, "limit": 20 }
}Relatórios pendentes (AT)
GET /api/sessoes/relatorios-pendentesAuth obrigatória (tipo: at).
Resposta 200: array de sessões finalizada sem relatório enviado.
Detalhe de sessão
GET /api/sessoes/:sessaoIdAuth obrigatória. Apenas AT ou família participantes da sessão.
Resposta 200: sessão completa com pagamento.
Propor novo horário
POST /api/sessoes/:sessaoId/propor-horarioAuth obrigatória (tipo: at).
Body:
{
"data": "2026-05-20",
"horarioInicio": "14:00"
}Resposta 200: sessão com scheduledAt atualizado.
Check-in (etapa 1 — AT inicia)
POST /api/sessoes/:sessaoId/checkinAuth obrigatória (tipo: at). Sem body.
confirmada → em_checkin
Gera um código numérico de 4 dígitos (válido por 10 minutos) e registra checkinAt.
Resposta 200: { "codigoCheckin": "4823" }
O código deve ser exibido pela família ao AT para confirmar a presença. A família o recebe por push notification.
Validar código de check-in (etapa 2 — AT confirma)
POST /api/sessoes/:sessaoId/validar-checkinAuth obrigatória (tipo: at).
Body:
{ "codigo": "4823" }codigo: exatamente 4 dígitos.
em_checkin → em_andamento
Erros possíveis:
422se o código for incorreto422se o código expirou (>10 minutos)422se o código já foi usado
Resposta 200: { "ok": true }
Checkout
POST /api/sessoes/:sessaoId/checkoutAuth obrigatória (tipo: at). Sem body.
em_andamento → finalizada
Ao fazer checkout:
checkoutAtregistrado- Split aplicado: 87% creditado em
at.saldoDisponivel, 13% fica na plataforma pagamento.valorAtepagamento.valorPlataformaatualizados
Resposta 204: sem body.
Cancelar sessão
POST /api/sessoes/:sessaoId/cancelarAuth obrigatória (AT ou família).
Body:
{ "motivo": "Criança adoeceu" }motivo opcional.
Regras de reembolso por quem cancela:
| Quem cancela | Antecedência | Reembolso à família |
|---|---|---|
| Família | > 24h | 100% |
| Família | 12h–24h | 50% (AT recebe 50%) |
| Família | < 12h | 0% (AT recebe 100%) |
| AT | Qualquer | 100% |
Resposta 204: sem body.
Relatórios de Sessão
Criar relatório
POST /api/sessoes/:sessaoId/relatorioAuth obrigatória (tipo: at).
Body:
{
"objetivosTrabalhados": "Comunicação verbal e contato visual",
"atividadesRealizadas": "Jogos simbólicos e atividades lúdicas",
"observacoesClinicas": "Boa tolerância à frustração",
"progressoObservado": "Iniciou contato visual espontâneo"
}Todos os campos são obrigatórios e não podem ser vazios.
Regras:
- Prazo: até 48h após
checkoutAt - AT com relatório atrasado (>48h) fica bloqueado de novas sessões
Resposta 201: { "relatorio": { "id": "<uuid>", ... } }
Obter relatório
GET /api/sessoes/:sessaoId/relatorioAuth obrigatória. Apenas AT da sessão e admin (supervisor).
A família não tem acesso ao relatório clínico.
Resposta 200: relatório completo.
Editar relatório
PUT /api/sessoes/:sessaoId/relatorioAuth obrigatória (tipo: at). Editável até 24h após o envio.
Body (todos opcionais):
{
"objetivosTrabalhados": "...",
"atividadesRealizadas": "...",
"observacoesClinicas": "...",
"progressoObservado": "..."
}Resposta 200: relatório atualizado.
Pagamentos
Webhook Asaas
POST /api/pagamentos/webhookSem autenticação via Bearer. Validado por assinatura HMAC-SHA256 no header asaas-access-token.
Body: payload de evento do Asaas.
Eventos tratados:
| Evento Asaas | Ação |
|---|---|
PAYMENT_CONFIRMED | Marca pagamento como pago, avança solicitação para aguardando_confirmacao_at |
PAYMENT_REFUNDED | Atualiza status do pagamento para reembolsado |
TRANSFER_SUCCESS | Marca saque como concluido |
TRANSFER_FAILED | Devolve valor ao saldoDisponivel do AT; marca saque como recusado |
Resposta 200: { "received": true }
Extrato financeiro — AT
GET /api/at/financeiro?mes=2026-05Auth obrigatória (tipo: at).
| Query param | Tipo | Descrição |
|---|---|---|
mes | string? | Filtrar por mês (YYYY-MM) |
Resposta 200:
{
"saldoDisponivel": 87000,
"extrato": [
{
"sessaoId": "<uuid>",
"data": "2026-05-15T09:00:00.000-03:00",
"valorAt": 13050,
"status": "pago"
}
]
}Listar saques — AT
GET /api/at/financeiro/saquesAuth obrigatória (tipo: at).
Resposta 200: array de saques.
[
{
"id": "<uuid>",
"valor": 50000,
"chavePix": "maria@email.com",
"status": "concluido",
"createdAt": "2026-05-01T10:00:00.000Z",
"processadoEm": "2026-05-02T08:00:00.000Z"
}
]status: pendente | processando | concluido | recusado
Solicitar saque — AT
POST /api/at/financeiro/saqueAuth obrigatória (tipo: at).
Body:
{
"valor": 50000,
"chavePix": "maria@email.com"
}valor em centavos. Deve ser ≤ saldoDisponivel.
Fluxo:
- Saldo subtraído imediatamente (reservado)
- Saque registrado com
status: "pendente" - Transferência PIX solicitada ao Asaas
- Asaas confirma ou recusa via webhook (
TRANSFER_SUCCESS/TRANSFER_FAILED)
Resposta 201: { "saque": { "id": "<uuid>", "status": "pendente", ... } }
Histórico de pagamentos — Família
GET /api/familia/pagamentos?periodo=2026-05&status=pagoAuth obrigatória (tipo: familia).
| Query param | Tipo | Descrição |
|---|---|---|
periodo | string? | Mês (YYYY-MM) |
status | string? | pendente | pago | reembolsado | reembolso_parcial | disputado |
Resposta 200: array de pagamentos.
Oportunidades
Listar oportunidades
GET /api/oportunidades?page=1&limit=20Auth obrigatória.
| Query param | Tipo | Descrição |
|---|---|---|
page | number | Default: 1 |
limit | number | Default: 20, max: 50 |
AT verificado vê a descrição completa. AT não verificado vê preview truncado (50 chars) e sem dados sensíveis.
Resposta 200:
{
"data": [
{
"id": "<uuid>",
"descricao": "Procuramos AT com experiência em TEA...",
"local": "casa",
"valorProposto": 15000,
"horarioPreferido": ["manha", "tarde"],
"status": "aberta",
"createdAt": "2026-05-01T10:00:00.000Z"
}
],
"total": 5,
"page": 1,
"limit": 20
}Criar oportunidade (família)
POST /api/oportunidadesAuth obrigatória (tipo: familia).
Body:
{
"criancaId": "<uuid>",
"descricao": "Procuramos AT especializado em TEA para sessões semanais",
"horarioPreferido": ["manha", "tarde"],
"local": "casa",
"valorProposto": 15000
}horarioPreferido: array não vazio de strings.valorProposto: inteiro positivo em centavos.
Resposta 201: { "oportunidade": { "id": "<uuid>", ... } }
Demonstrar interesse / enviar proposta (AT)
POST /api/oportunidades/:id/interesseAuth obrigatória (tipo: at, deve estar verificado).
Body:
{
"mensagem": "Tenho 5 anos de experiência com TEA",
"valorProposto": 14000,
"disponibilidade": "Terças e quintas pela manhã"
}Todos os campos são obrigatórios.
Resposta 201: { "proposta": { "id": "<uuid>", ... } }
Aceitar proposta (família)
POST /api/oportunidades/:id/propostas/:propostaId/aceitarAuth obrigatória (tipo: familia, deve ser dona da oportunidade). Sem body.
Fecha a oportunidade (status: "fechada") e marca a proposta como aceita.
Resposta 204: sem body.
Reviews
Criar review (família)
POST /api/reviewsAuth obrigatória (tipo: familia).
Body:
{
"atId": "<uuid>",
"nota": 4.5,
"comentario": "Excelente profissional, muito atencioso",
"periodoRef": "2026-04"
}| Campo | Regras |
|---|---|
nota | Número entre 1 e 5 (aceita decimal) |
comentario | Opcional |
periodoRef | String no formato YYYY-MM |
Exige ao menos uma sessão finalizada com o AT.
Resposta 201: { "review": { "id": "<uuid>", ... } }
Listar reviews de um AT
GET /api/reviews/at/:atId?page=1&limit=20Auth obrigatória.
| Query param | Tipo | Descrição |
|---|---|---|
page | number | Default: 1 |
limit | number | Default: 20, max: 50 |
Resposta 200:
{
"data": [
{
"id": "<uuid>",
"nota": 4.5,
"comentario": "Ótimo profissional",
"periodoRef": "2026-04",
"createdAt": "2026-04-30T18:00:00.000Z"
}
],
"total": 12,
"page": 1,
"limit": 20
}Notificações
Listar notificações
GET /api/notificacoes?lida=false&page=1&limit=20Auth obrigatória.
| Query param | Tipo | Descrição |
|---|---|---|
lida | "true" | "false" | Filtrar por status de leitura |
page | number | Default: 1 |
limit | number | Default: 20, max: 50 |
Resposta 200:
{
"data": [
{
"id": "<uuid>",
"titulo": "Nova solicitação de sessão",
"corpo": "Família Lima solicitou uma sessão para 15/05",
"lida": false,
"tipo": "nova_solicitacao",
"createdAt": "2026-05-01T08:00:00.000Z"
}
],
"total": 3,
"page": 1,
"limit": 20
}Marcar notificação como lida
PUT /api/notificacoes/:id/lidaAuth obrigatória. Sem body.
Resposta 204: sem body.
Marcar todas como lidas
PUT /api/notificacoes/todas-lidasAuth obrigatória. Sem body.
Resposta 204: sem body.
Admin
Protegido por
adminGuard— requer credencial de admin separada do JWT padrão.
Listar ATs em revisão
GET /api/admin/ats/revisaoAuth obrigatória (adminGuard).
Resposta 200: array de ATs com status: "em_analise" ou "pendencias", incluindo documentos pendentes de revisão.
Revisar documento de AT
PATCH /api/admin/ats/:atId/documentos/:tipoAuth obrigatória (adminGuard).
| Param | Valores |
|---|---|
tipo | antecedentes | certificado |
Body:
{
"decisao": "aprovado",
"motivoRecusa": "Documento ilegível"
}decisao: aprovado | recusadomotivoRecusa: obrigatório quando decisao = "recusado".
Resposta 200: { "ok": true }
Jobs em background
Executados internamente via node-cron. Não possuem endpoints HTTP.
| Job | Frequência | Ação |
|---|---|---|
expireSessoes | A cada 15 minutos | Solicitações aguardando_confirmacao_at com expiresAt < now → expirada |
atualizarVinculos | Diário (00:00) | Vínculos sem sessão nos últimos 14 dias e sem sessão futura → inativo |
alertarRelatorios | A cada 1 hora | ATs com sessão finalizada há +48h sem relatório → status pendencias |
Enums de referência
| Enum | Valores |
|---|---|
UserTipo | at, familia |
AtStatus | em_analise, verificado, pendencias, suspenso, rejeitado |
Genero | masculino, feminino, outro, prefiro_nao_informar |
DocumentoTipo | certificado, antecedentes, foto_perfil |
DocumentoStatus | em_analise, aprovado, recusado |
Diagnostico | tea, tdah, outro, aguardando_diagnostico |
LocalSessao | casa, escola, outro |
Turno | manha, tarde, noite |
VinculoStatus | ativo, inativo, pausado, encerrado |
SolicitacaoStatus | aguardando_confirmacao_at, aguardando_pagamento, confirmada, cancelada, expirada |
SessaoStatus | agendada, confirmada, em_checkin, em_andamento, finalizada, cancelada |
SessaoOrigem | solicitacao_familia, solicitacao_at, oportunidade, reagendamento |
PagamentoStatus | pendente, pago, reembolsado, reembolso_parcial, disputado |
FormaPagamento | pix, credito, debito |
SaqueStatus | pendente, processando, concluido, recusado |
OportunidadeStatus | aberta, em_negociacao, fechada, cancelada |
PropostaStatus | enviada, aceita, recusada |
Changelog
| Versão | Data | Alteração |
|---|---|---|
| v1.0 | 2026-04-13 | Documento inicial |
| v1.1 | 2026-04-13 | Correções de fluxo de check-in, split, acesso a relatório |
| v2.0 | 2026-04-23 | Reescrita completa baseada no código implementado: fluxo de solicitação corrigido (família cria → AT confirma → família paga), check-in em duas etapas (em_checkin + validar código), rotas reais documentadas (DELETE /familia/criancas, POST /validar-checkin, GET /familia/buscar-ats), jobs cron, enums atualizados |