Skip to content

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:

json
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Descrição legível"
  }
}
HTTPcodeQuando ocorre
400VALIDATION_ERRORBody/params/query inválidos (Zod)
401UNAUTHORIZEDToken ausente, expirado ou inválido
403FORBIDDENSem permissão para o recurso
404NOT_FOUNDRecurso não existe
409CONFLICTConflito de estado (ex.: e-mail já cadastrado)
422VALIDATION_ERRORRegra de negócio violada
429Rate limit atingido
500INTERNAL_ERRORErro inesperado do servidor

Health

GET /health

Resposta 200:

json
{ "status": "ok" }

Autenticação

Login

POST /api/auth/login

Rate limit: 5 req / 15 min.

Body:

json
{
  "email": "usuario@email.com",
  "password": "senha123"
}

Resposta 200:

json
{
  "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/refresh

Body:

json
{ "refreshToken": "<uuid>" }

Resposta 200:

json
{
  "accessToken": "<jwt>",
  "refreshToken": "<novo-uuid>"
}

O refresh token anterior é revogado (rotação automática).


Logout

POST /api/auth/logout

Body:

json
{ "refreshToken": "<uuid>" }

Resposta 204: sem body.


Esqueci minha senha

POST /api/auth/forgot-password

Rate limit: 5 req / 1 hora.

Body:

json
{ "email": "usuario@email.com" }

Resposta 200: { "ok": true }

Envia e-mail com token de reset.


Resetar senha

POST /api/auth/reset-password

Rate limit: 5 req / 1 hora.

Body:

json
{
  "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/at

Rate limit: 10 req / 1 hora.

Body:

json
{
  "nomeCompleto": "Maria Santos",
  "cpf": "12345678901",
  "email": "maria@email.com",
  "telefone": "11999990000",
  "cidade": "São Paulo",
  "estado": "SP",
  "password": "senha123",
  "passwordConfirmation": "senha123"
}
CampoRegras
cpfExatamente 11 dígitos numéricos, com validação de dígitos verificadores
estado2 letras (UF)
telefoneMínimo 10 dígitos
passwordMínimo 8 caracteres

Resposta 201:

json
{
  "accessToken": "<jwt>",
  "refreshToken": "<uuid>",
  "user": { "id": "<uuid>", "tipo": "at", ... }
}

Etapa 2: Upload de documentos

POST /api/auth/register/at/documentos

Auth obrigatória. Multipart form-data. Limite: 10 MB por arquivo.

Campo multipartTipoDescrição
certificadofileCertificado de formação (PDF/JPG/PNG)
antecedentesfileCertidão de antecedentes criminais (PDF/JPG/PNG)
foto_perfilfileFoto 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/familia

Rate limit: 10 req / 1 hora.

Body:

json
{
  "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:

json
{
  "accessToken": "<jwt>",
  "refreshToken": "<uuid>",
  "user": { "id": "<uuid>", "tipo": "familia", ... }
}

Etapa 2: Cadastrar criança

POST /api/auth/register/familia/crianca

Body:

json
{
  "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/laudo

Multipart form-data.

Campo multipartTipoDescrição
criancaIdtextUUID da criança
laudofileArquivo do laudo médico (PDF/JPG/PNG)

Resposta 200: { "ok": true }


Etapa 4: Necessidades da criança

POST /api/auth/register/familia/necessidades

Body:

json
{
  "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 | noite
localPreferido: casa | escola | outro

Resposta 200: { "ok": true }


Verificação

Enviar código de verificação de e-mail

POST /api/verify/email/send

Body:

json
{ "email": "usuario@email.com" }

Resposta 200: { "ok": true }


Verificar e-mail

POST /api/verify/email

Auth obrigatória.

Body:

json
{ "codigo": "123456" }

codigo: exatamente 6 dígitos.

Resposta 200: { "ok": true }


Verificar telefone

POST /api/verify/phone

Auth obrigatória.

Body:

json
{ "codigo": "123456" }

Resposta 200: { "ok": true }


Reenviar código de telefone

POST /api/verify/phone/resend

Auth obrigatória. Sem body.

Resposta 200: { "ok": true }


AT — Perfil

Obter próprio perfil

GET /api/at/perfil

Auth obrigatória (tipo: at).

Resposta 200:

json
{
  "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 | rejeitado
genero: masculino | feminino | outro | prefiro_nao_informar
valorSessao e saldoDisponivel em centavos.


Atualizar perfil

PATCH /api/at/perfil

Auth obrigatória (tipo: at).

Body (todos opcionais):

json
{
  "bio": "Nova bio",
  "especializacoes": ["TEA"],
  "formacao": "Psicologia - USP",
  "certificacoes": "Cert. Y",
  "valorSessao": 18000,
  "regiaoAtendimento": "Zona Norte",
  "genero": "feminino"
}

Alteração de valorSessao reflete apenas em novas solicitações.

Resposta 200: perfil atualizado.


Atualizar foto de perfil

POST /api/at/perfil/foto

Auth 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/:atId

Auth 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:

json
{
  "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/disponibilidade

Auth obrigatória (tipo: at).

Resposta 200:

json
{
  "horarios": {
    "segunda": ["manha", "tarde"],
    "sexta": ["noite"]
  }
}

Atualizar disponibilidade

PUT /api/at/disponibilidade

Auth obrigatória (tipo: at).

Body:

json
{
  "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/bloqueio

Auth obrigatória (tipo: at).

Body:

json
{
  "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/:bloqueioId

Auth obrigatória (tipo: at).

Resposta 204: sem body.


AT — Documentos

Reenviar documento recusado

PUT /api/at/documentos/:tipo

Auth obrigatória (tipo: at). Multipart form-data.

ParamValores aceitos
tipoantecedentes | certificado

Campo multipart: arquivo do documento (file).

Resposta 204: sem body.

Ao reenviar, o documento volta ao status em_analise para revisão do admin.


AT — Pacientes

Listar pacientes

GET /api/at/pacientes?status=ativo&busca=Enzo

Auth obrigatória (tipo: at).

Query paramTipoDescrição
statusstring?ativo | inativo | pausado | encerrado
buscastring?Busca por nome da criança

Resposta 200: array de vínculos com dados da criança.


Detalhe de paciente

GET /api/at/pacientes/:criancaId

Auth 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/vinculo

Auth obrigatória (tipo: at).

Body:

json
{ "status": "pausado" }

status: pausado | encerrado

Resposta 200: { "ok": true }


Busca de ATs

GET /api/ats?cidade=São+Paulo&page=1

Rota pública — sem autenticação.

Query paramObrigatórioTipoDescrição
cidadestringFiltra ATs pela cidade (case-insensitive)
pagenumberPágina (default: 1)
especializacaostringFiltra por especialização exata
generostringmasculino | feminino | outro | prefiro_nao_informar
valorMaxnumberValor máximo por sessão (centavos)

Retorna apenas ATs com status = verificado. Paginação fixa em 10 por página.

Resposta 200:

json
{
  "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/perfil

Auth obrigatória (tipo: familia).

Resposta 200:

json
{
  "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/perfil

Auth obrigatória (tipo: familia).

Body (todos opcionais):

json
{
  "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/criancas

Auth obrigatória (tipo: familia).

Resposta 200: array de crianças da família.


Detalhe de criança

GET /api/familia/criancas/:criancaId

Auth obrigatória (tipo: familia).

Resposta 200: dados completos da criança.


Adicionar criança

POST /api/familia/criancas

Auth obrigatória (tipo: familia).

Body:

json
{
  "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/:criancaId

Auth obrigatória (tipo: familia). Body igual ao POST, todos os campos opcionais.

Resposta 200: criança atualizada.


Remover criança

DELETE /api/familia/criancas/:criancaId

Auth obrigatória (tipo: familia).

Resposta 204: sem body.


Upload / atualização de laudo

POST /api/familia/criancas/:criancaId/laudo

Auth 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/necessidades

Auth obrigatória (tipo: familia).

Body:

json
{
  "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+Paulo

Auth obrigatória (tipo: familia). Mesmos parâmetros e resposta que GET /api/ats.


Fluxo de Solicitação de Sessão

A Sessao real só é criada após pagamento confirmado. O fluxo completo é:

Família solicita → AT confirma → Família paga → Sessão criada

Estados da SolicitacaoSessao

StatusSignificado
aguardando_confirmacao_atFamília criou; AT ainda não respondeu (expira em 24h)
aguardando_pagamentoAT confirmou; aguardando pagamento da família
confirmadaFamília pagou — Sessao real foi criada e solicitação é removida
canceladaAT recusou ou família cancelou
expiradaAT não respondeu em 24h (job automático)

Criar solicitação (família)

POST /api/solicitacoes

Auth obrigatória (tipo: familia).

Body:

json
{
  "atId": "<uuid>",
  "criancaId": "<uuid>",
  "data": "2026-05-15",
  "horarioInicio": "09:00",
  "local": "casa",
  "enderecoCustom": "Rua X, 10",
  "valorSugerido": 15000
}
CampoObrigatórioDescrição
atIdUUID do AT (deve estar verificado)
criancaIdUUID da criança (deve pertencer à família)
dataYYYY-MM-DD
horarioInicioHH:mm
localcasa | escola | outro
enderecoCustomCondicionalObrigatório quando local = "outro"
valorSugeridoEm 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/confirmar

Auth obrigatória (tipo: at).

Body (ambos opcionais — para sugerir novo horário):

json
{
  "novaData": "2026-05-16",
  "novoHorarioInicio": "10:00"
}

aguardando_confirmacao_ataguardando_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/recusar

Auth obrigatória (tipo: at).

Body:

json
{ "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/pagar

Auth obrigatória (tipo: familia). Sem body.

aguardando_pagamentoconfirmada (transacional)

Em uma única transação:

  1. Pagamento marcado como pago
  2. Sessao criada com status: "confirmada"
  3. Vínculo AT↔criança criado (ou mantido se já existe)
  4. Pagamento migrado da solicitação para a sessão
  5. SolicitacaoSessao removida

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=20

Auth obrigatória. AT vê as suas; família vê as suas.

Query paramTipoDescrição
statusstring?Filtrar por status (ver tabela de estados)
pagenumberDefault: 1
limitnumberDefault: 20, max: 50

Resposta 200:

json
{
  "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/:solicitacaoId

Auth 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 existe POST /api/sessoes — use /api/solicitacoes para iniciar o agendamento.

Estados da Sessao

StatusDescrição
agendadaCriada (após pagamento), aguardando chegada da data
confirmadaConfirmada e pronta para check-in
em_checkinAT iniciou o check-in; código gerado, aguardando validação
em_andamentoCódigo de check-in validado; sessão em curso
finalizadaCheck-out realizado; split 87/13 aplicado
canceladaCancelada por AT, família ou sistema

Listar sessões

GET /api/sessoes?tab=proximas&page=1&limit=20

Auth obrigatória.

Query paramTipoDescrição
tabstringproximas | historico — default: proximas
criancaIduuid?Filtrar por criança (família)
messtring?Filtrar por mês (2026-05)
pagenumberDefault: 1
limitnumberDefault: 20, max: 50

proximas: status agendada, confirmada, em_checkin, em_andamento.
historico: status finalizada, cancelada.

Resposta 200:

json
{
  "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-pendentes

Auth obrigatória (tipo: at).

Resposta 200: array de sessões finalizada sem relatório enviado.


Detalhe de sessão

GET /api/sessoes/:sessaoId

Auth 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-horario

Auth obrigatória (tipo: at).

Body:

json
{
  "data": "2026-05-20",
  "horarioInicio": "14:00"
}

Resposta 200: sessão com scheduledAt atualizado.


Check-in (etapa 1 — AT inicia)

POST /api/sessoes/:sessaoId/checkin

Auth obrigatória (tipo: at). Sem body.

confirmadaem_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-checkin

Auth obrigatória (tipo: at).

Body:

json
{ "codigo": "4823" }

codigo: exatamente 4 dígitos.

em_checkinem_andamento

Erros possíveis:

  • 422 se o código for incorreto
  • 422 se o código expirou (>10 minutos)
  • 422 se o código já foi usado

Resposta 200: { "ok": true }


Checkout

POST /api/sessoes/:sessaoId/checkout

Auth obrigatória (tipo: at). Sem body.

em_andamentofinalizada

Ao fazer checkout:

  1. checkoutAt registrado
  2. Split aplicado: 87% creditado em at.saldoDisponivel, 13% fica na plataforma
  3. pagamento.valorAt e pagamento.valorPlataforma atualizados

Resposta 204: sem body.


Cancelar sessão

POST /api/sessoes/:sessaoId/cancelar

Auth obrigatória (AT ou família).

Body:

json
{ "motivo": "Criança adoeceu" }

motivo opcional.

Regras de reembolso por quem cancela:

Quem cancelaAntecedênciaReembolso à família
Família> 24h100%
Família12h–24h50% (AT recebe 50%)
Família< 12h0% (AT recebe 100%)
ATQualquer100%

Resposta 204: sem body.


Relatórios de Sessão

Criar relatório

POST /api/sessoes/:sessaoId/relatorio

Auth obrigatória (tipo: at).

Body:

json
{
  "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/relatorio

Auth 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/relatorio

Auth obrigatória (tipo: at). Editável até 24h após o envio.

Body (todos opcionais):

json
{
  "objetivosTrabalhados": "...",
  "atividadesRealizadas": "...",
  "observacoesClinicas": "...",
  "progressoObservado": "..."
}

Resposta 200: relatório atualizado.


Pagamentos

Webhook Asaas

POST /api/pagamentos/webhook

Sem autenticação via Bearer. Validado por assinatura HMAC-SHA256 no header asaas-access-token.

Body: payload de evento do Asaas.

Eventos tratados:

Evento AsaasAção
PAYMENT_CONFIRMEDMarca pagamento como pago, avança solicitação para aguardando_confirmacao_at
PAYMENT_REFUNDEDAtualiza status do pagamento para reembolsado
TRANSFER_SUCCESSMarca saque como concluido
TRANSFER_FAILEDDevolve valor ao saldoDisponivel do AT; marca saque como recusado

Resposta 200: { "received": true }


Extrato financeiro — AT

GET /api/at/financeiro?mes=2026-05

Auth obrigatória (tipo: at).

Query paramTipoDescrição
messtring?Filtrar por mês (YYYY-MM)

Resposta 200:

json
{
  "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/saques

Auth obrigatória (tipo: at).

Resposta 200: array de saques.

json
[
  {
    "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/saque

Auth obrigatória (tipo: at).

Body:

json
{
  "valor": 50000,
  "chavePix": "maria@email.com"
}

valor em centavos. Deve ser ≤ saldoDisponivel.

Fluxo:

  1. Saldo subtraído imediatamente (reservado)
  2. Saque registrado com status: "pendente"
  3. Transferência PIX solicitada ao Asaas
  4. 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=pago

Auth obrigatória (tipo: familia).

Query paramTipoDescrição
periodostring?Mês (YYYY-MM)
statusstring?pendente | pago | reembolsado | reembolso_parcial | disputado

Resposta 200: array de pagamentos.


Oportunidades

Listar oportunidades

GET /api/oportunidades?page=1&limit=20

Auth obrigatória.

Query paramTipoDescrição
pagenumberDefault: 1
limitnumberDefault: 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:

json
{
  "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/oportunidades

Auth obrigatória (tipo: familia).

Body:

json
{
  "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/interesse

Auth obrigatória (tipo: at, deve estar verificado).

Body:

json
{
  "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/aceitar

Auth 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/reviews

Auth obrigatória (tipo: familia).

Body:

json
{
  "atId": "<uuid>",
  "nota": 4.5,
  "comentario": "Excelente profissional, muito atencioso",
  "periodoRef": "2026-04"
}
CampoRegras
notaNúmero entre 1 e 5 (aceita decimal)
comentarioOpcional
periodoRefString 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=20

Auth obrigatória.

Query paramTipoDescrição
pagenumberDefault: 1
limitnumberDefault: 20, max: 50

Resposta 200:

json
{
  "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=20

Auth obrigatória.

Query paramTipoDescrição
lida"true" | "false"Filtrar por status de leitura
pagenumberDefault: 1
limitnumberDefault: 20, max: 50

Resposta 200:

json
{
  "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/lida

Auth obrigatória. Sem body.

Resposta 204: sem body.


Marcar todas como lidas

PUT /api/notificacoes/todas-lidas

Auth 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/revisao

Auth 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/:tipo

Auth obrigatória (adminGuard).

ParamValores
tipoantecedentes | certificado

Body:

json
{
  "decisao": "aprovado",
  "motivoRecusa": "Documento ilegível"
}

decisao: aprovado | recusado
motivoRecusa: obrigatório quando decisao = "recusado".

Resposta 200: { "ok": true }


Jobs em background

Executados internamente via node-cron. Não possuem endpoints HTTP.

JobFrequênciaAção
expireSessoesA cada 15 minutosSolicitações aguardando_confirmacao_at com expiresAt < nowexpirada
atualizarVinculosDiário (00:00)Vínculos sem sessão nos últimos 14 dias e sem sessão futura → inativo
alertarRelatoriosA cada 1 horaATs com sessão finalizada há +48h sem relatório → status pendencias

Enums de referência

EnumValores
UserTipoat, familia
AtStatusem_analise, verificado, pendencias, suspenso, rejeitado
Generomasculino, feminino, outro, prefiro_nao_informar
DocumentoTipocertificado, antecedentes, foto_perfil
DocumentoStatusem_analise, aprovado, recusado
Diagnosticotea, tdah, outro, aguardando_diagnostico
LocalSessaocasa, escola, outro
Turnomanha, tarde, noite
VinculoStatusativo, inativo, pausado, encerrado
SolicitacaoStatusaguardando_confirmacao_at, aguardando_pagamento, confirmada, cancelada, expirada
SessaoStatusagendada, confirmada, em_checkin, em_andamento, finalizada, cancelada
SessaoOrigemsolicitacao_familia, solicitacao_at, oportunidade, reagendamento
PagamentoStatuspendente, pago, reembolsado, reembolso_parcial, disputado
FormaPagamentopix, credito, debito
SaqueStatuspendente, processando, concluido, recusado
OportunidadeStatusaberta, em_negociacao, fechada, cancelada
PropostaStatusenviada, aceita, recusada

Changelog

VersãoDataAlteração
v1.02026-04-13Documento inicial
v1.12026-04-13Correções de fluxo de check-in, split, acesso a relatório
v2.02026-04-23Reescrita 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

Criado para empoderar famílias e terapeutas.