NFS-e/Repasse: Médico
Endpoints da WebApiAlcance para gerenciar médicos vinculados a prestadores no módulo NFS-e/Repasse. Cada médico pertence a um prestador (id_prestador) e pode ter vínculos com usuários internos do sistema. Cobrem criação, listagem geral com filtros, listagem restrita a um prestador, detalhamento por ID, atualização, exclusão e o gerenciamento completo dos vínculos usuário↔médico.
Todos os endpoints exigem autenticação. Veja Autenticação para o fluxo de API Key. O Swagger oficial está em api.contabilidadealcance.com.br/docs.
Escopo compartilhado do módulo NFS-e/Repasse
O primeiro segmento da rota é nfse-repasse (compartilhado por todo o módulo). O escopo é derivado dele: nfse_repasse:read para leitura e nfse_repasse:write para escrita. Ou seja, os recursos internos do módulo (médicos, prestadores etc.) compartilham o mesmo par de escopos nfse_repasse:read / nfse_repasse:write, e não escopos por sub-recurso.
Base path
/api/v1/nfse-repasse/medicosEscopos necessários
nfse_repasse:read- listagens, detalhamento e leitura de vínculos (GET)nfse_repasse:write- criação, atualização e exclusão de médicos e vínculos (POST/PUT/DELETE)
O escopo é derivado do primeiro segmento da rota: /nfse-repasse vira o recurso nfse_repasse (hífen → underscore), compartilhado por todo o módulo. O método HTTP define a ação (read para GET, write para POST/PUT/DELETE).
Perfil administrador nas escritas
Além do escopo nfse_repasse:write, as operações de escrita (criar/atualizar/excluir médico e vínculos) exigem perfil administrador no backend. Leituras (GET) são liberadas a qualquer usuário autenticado.
Endpoints
POST /nfse-repasse/medicos/
Cria um novo médico vinculado a um prestador. O id_usuario_created não entra no body - é forçado pelo backend a partir do usuário autenticado.
Parâmetros
Este endpoint não recebe parâmetros de rota ou query - os dados vão no corpo da requisição (MedicoCreate). Campos obrigatórios: id_prestador e nome.
Request
{
"id_prestador": 1,
"nome": "Dr. João da Silva",
"cpf": "12345678901",
"crm": "CRM/BA 12345",
"email": "joao@exemplo.com.br",
"telefone": "(71) 99999-9999",
"status": "ativo",
"data_inicio": "2026-01-01",
"medico_administrador": false,
"participa_rateio_repasse": true
}Response 201 Created
{
"success": true,
"message": "Médico criado com sucesso!",
"data": {
"id": 1,
"id_prestador": 1,
"nome": "Dr. João da Silva",
"cpf": "12345678901",
"crm": "CRM/BA 12345",
"email": "joao@exemplo.com.br",
"telefone": "(71) 99999-9999",
"status": "ativo",
"data_inicio": "2026-01-01",
"data_fim": null,
"medico_administrador": false,
"participa_rateio_repasse": true,
"uuid_legado": null,
"id_usuario_created": 42,
"created_at": "2026-01-01T12:00:00Z",
"updated_at": "2026-01-01T12:00:00Z"
}
}Escopo: nfse_repasse:write
POST /nfse-repasse/medicos/vinculos
Cria um vínculo usuário↔médico. Rota estática declarada antes de /{medico_id} (ver Notas). O id_usuario_created é forçado pelo backend.
Parâmetros
Este endpoint não recebe parâmetros de rota ou query - os dados vão no corpo da requisição (MedicoUsuarioVinculoCreate). Campo obrigatório: id_medico.
Request
{
"id_medico": 1,
"id_usuario": 42,
"uuid_usuario_legado": "7a06b064-0dc9-414e-bb68-05a3cf7be813"
}Response 201 Created
{
"success": true,
"message": "Vínculo criado com sucesso!",
"data": {
"id": 1,
"id_medico": 1,
"id_usuario": 42,
"uuid_usuario_legado": "7a06b064-0dc9-414e-bb68-05a3cf7be813",
"uuid_legado": null,
"id_usuario_created": 42,
"created_at": "2026-01-01T12:00:00Z",
"updated_at": "2026-01-01T12:00:00Z"
}
}Escopo: nfse_repasse:write
GET /nfse-repasse/medicos/vinculos/by-medico/{id_medico}
Lista os vínculos usuário↔médico de um médico específico. Lista vazia é um estado válido - retorna data: [].
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
id_medico | int | path | sim | ID do médico (medico.id) |
Request
Sem corpo de requisição.
Response 200 OK
{
"success": true,
"message": "Vínculos recuperados com sucesso!",
"data": [
{
"id": 1,
"id_medico": 1,
"id_usuario": 42,
"uuid_usuario_legado": null,
"uuid_legado": null,
"id_usuario_created": 42,
"created_at": "2026-01-01T12:00:00Z",
"updated_at": "2026-01-01T12:00:00Z"
}
]
}Escopo: nfse_repasse:read
PUT /nfse-repasse/medicos/vinculos/{vinculo_id}
Atualiza um vínculo usuário↔médico. O body é um MedicoUsuarioVinculoUpdate com campos parciais - somente o que vier preenchido é alterado.
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
vinculo_id | int | path | sim | ID do vínculo |
Request (MedicoUsuarioVinculoUpdate - todos os campos opcionais)
{
"id_usuario": 43,
"uuid_usuario_legado": "7a06b064-0dc9-414e-bb68-05a3cf7be813"
}Response 200 OK
{
"success": true,
"message": "Vínculo atualizado!",
"data": {
"id": 1,
"id_medico": 1,
"id_usuario": 43,
"uuid_usuario_legado": "7a06b064-0dc9-414e-bb68-05a3cf7be813",
"uuid_legado": null,
"id_usuario_created": 42,
"created_at": "2026-01-01T12:00:00Z",
"updated_at": "2026-01-01T13:30:00Z"
}
}Escopo: nfse_repasse:write
DELETE /nfse-repasse/medicos/vinculos/{vinculo_id}
Remove um vínculo usuário↔médico pelo ID.
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
vinculo_id | int | path | sim | ID do vínculo |
Request
Sem corpo de requisição.
Response 200 OK
{
"success": true,
"message": "Vínculo removido!",
"data": null
}Escopo: nfse_repasse:write
GET /nfse-repasse/medicos/by-prestador/{id_prestador}
Lista os médicos vinculados a um prestador, com filtro de status e paginação. Rota estática declarada antes de /{medico_id}.
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
id_prestador | int | path | sim | ID do prestador (prestador_medico.id) |
status | str | query | não | Filtro por status: ativo ou inativo |
page | int >= 1 | query | não | Página (1-based) |
per_page | int 1..500 | query | não | Itens por página |
Request
Sem corpo de requisição.
Response 200 OK
{
"success": true,
"message": "Médicos recuperados com sucesso!",
"data": [
{
"id": 1,
"id_prestador": 1,
"nome": "Dr. João da Silva",
"cpf": "12345678901",
"crm": "CRM/BA 12345",
"email": "joao@exemplo.com.br",
"telefone": "(71) 99999-9999",
"status": "ativo",
"data_inicio": "2026-01-01",
"data_fim": null,
"medico_administrador": false,
"participa_rateio_repasse": true,
"uuid_legado": null,
"id_usuario_created": 42,
"created_at": "2026-01-01T12:00:00Z",
"updated_at": "2026-01-01T12:00:00Z"
}
]
}Escopo: nfse_repasse:read
GET /nfse-repasse/medicos/
Lista todos os médicos (visão compartilhada single-company), com filtros opcionais e paginação. Lista vazia é um estado válido - retorna data: [].
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
status | str | query | não | Filtro por status: ativo ou inativo |
id_prestador | int | query | não | Filtro por prestador vinculado (prestador_medico.id) |
page | int >= 1 | query | não | Página (1-based) |
per_page | int 1..500 | query | não | Itens por página |
Request
Sem corpo de requisição.
Response 200 OK
{
"success": true,
"message": "Médicos recuperados com sucesso!",
"data": [
{
"id": 1,
"id_prestador": 1,
"nome": "Dr. João da Silva",
"cpf": "12345678901",
"crm": "CRM/BA 12345",
"email": "joao@exemplo.com.br",
"telefone": "(71) 99999-9999",
"status": "ativo",
"data_inicio": "2026-01-01",
"data_fim": null,
"medico_administrador": false,
"participa_rateio_repasse": true,
"uuid_legado": null,
"id_usuario_created": 42,
"created_at": "2026-01-01T12:00:00Z",
"updated_at": "2026-01-01T12:00:00Z"
}
]
}Escopo: nfse_repasse:read
GET /nfse-repasse/medicos/{medico_id}
Detalha um médico pelo ID inteiro. Quando não encontrado, retorna 404 Not Found.
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
medico_id | int | path | sim | ID interno do médico |
Request
Sem corpo de requisição.
Response 200 OK
{
"success": true,
"message": "Médico encontrado!",
"data": {
"id": 1,
"id_prestador": 1,
"nome": "Dr. João da Silva",
"cpf": "12345678901",
"crm": "CRM/BA 12345",
"email": "joao@exemplo.com.br",
"telefone": "(71) 99999-9999",
"status": "ativo",
"data_inicio": "2026-01-01",
"data_fim": null,
"medico_administrador": false,
"participa_rateio_repasse": true,
"uuid_legado": null,
"id_usuario_created": 42,
"created_at": "2026-01-01T12:00:00Z",
"updated_at": "2026-01-01T12:00:00Z"
}
}Escopo: nfse_repasse:read
PUT /nfse-repasse/medicos/{medico_id}
Atualiza um médico existente. O body é um MedicoUpdate com campos parciais - somente o que vier preenchido é alterado. Os campos id, uuid_legado, id_usuario_created, created_at e updated_at são imutáveis e não podem ser enviados.
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
medico_id | int | path | sim | ID do médico |
Request (MedicoUpdate - todos os campos opcionais)
{
"status": "inativo",
"data_fim": "2026-12-31",
"participa_rateio_repasse": false
}Response 200 OK
{
"success": true,
"message": "Médico atualizado!",
"data": {
"id": 1,
"id_prestador": 1,
"nome": "Dr. João da Silva",
"cpf": "12345678901",
"crm": "CRM/BA 12345",
"email": "joao@exemplo.com.br",
"telefone": "(71) 99999-9999",
"status": "inativo",
"data_inicio": "2026-01-01",
"data_fim": "2026-12-31",
"medico_administrador": false,
"participa_rateio_repasse": false,
"uuid_legado": null,
"id_usuario_created": 42,
"created_at": "2026-01-01T12:00:00Z",
"updated_at": "2026-07-08T09:00:00Z"
}
}Escopo: nfse_repasse:write
DELETE /nfse-repasse/medicos/{medico_id}
Remove um médico pelo ID.
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
medico_id | int | path | sim | ID do médico |
Request
Sem corpo de requisição.
Response 200 OK
{
"success": true,
"message": "Médico removido!",
"data": null
}Escopo: nfse_repasse:write
Schemas
MedicoCreate
| Campo | Tipo | Obrigatório | Observações |
|---|---|---|---|
id_prestador | int | sim | Prestador (prestador_medico.id) ao qual o médico é vinculado. |
nome | str | sim | Nome do médico (máx. 200). |
cpf | str | não | Aceita máscara - normalizado para apenas dígitos (máx. 20). Vazio → null. |
crm | str | não | Número do CRM (máx. 30). |
email | str | não | E-mail de contato (máx. 100). |
telefone | str | não | Telefone de contato (máx. 50). |
status | str | não | ativo ou inativo. Default ativo. |
data_inicio | date | não | Data de início do vínculo (YYYY-MM-DD). |
data_fim | date | não | Data de fim do vínculo (YYYY-MM-DD). |
medico_administrador | bool | não | Se true, vê relatórios de repasse de todos os médicos do prestador. Default false. |
participa_rateio_repasse | bool | não | Se false, não entra na divisão de despesas rateadas. Default true. |
uuid_legado | str | não | UUID do registro original no Supabase (rastreabilidade da migração; máx. 36). Imutável depois. |
MedicoUpdate
Todos os campos são opcionais; apenas os enviados são atualizados. id, uuid_legado, id_usuario_created, created_at e updated_at são imutáveis (bloqueio de mass-assignment).
| Campo | Tipo | Observações |
|---|---|---|
id_prestador | int | Reatribui o médico a outro prestador. |
nome | str | Novo nome (máx. 200). |
cpf | str | Normalizado para dígitos (máx. 20). |
crm | str | Novo CRM (máx. 30). |
email | str | Novo e-mail (máx. 100). |
telefone | str | Novo telefone (máx. 50). |
status | str | ativo ou inativo. |
data_inicio | date | Data de início. |
data_fim | date | Data de fim. |
medico_administrador | bool | Alterna acesso administrativo do médico. |
participa_rateio_repasse | bool | Alterna participação no rateio. |
MedicoRead
Estende MedicoBase com campos gerenciados pelo servidor.
| Campo | Tipo | Notas |
|---|---|---|
id | int | Identificador interno do médico. |
id_prestador | int | Prestador vinculado. |
nome | str | Nome do médico. |
cpf | str? | CPF (apenas dígitos). |
crm | str? | CRM. |
email | str? | E-mail de contato. |
telefone | str? | Telefone de contato. |
status | str | ativo ou inativo. |
data_inicio | date? | Data de início do vínculo. |
data_fim | date? | Data de fim do vínculo. |
medico_administrador | bool | Acesso administrativo do médico. |
participa_rateio_repasse | bool | Participa do rateio de despesas. |
uuid_legado | str? | UUID do registro original (migração). |
id_usuario_created | int? | Usuário que criou (auditoria). |
created_at | datetime | Timestamp de criação (server-side). |
updated_at | datetime | Timestamp da última atualização. |
MedicoUsuarioVinculoCreate
| Campo | Tipo | Obrigatório | Observações |
|---|---|---|---|
id_medico | int | sim | Médico (medico.id) vinculado. |
id_usuario | int | não | Usuário interno (user.id) vinculado - opcional na carga. |
uuid_usuario_legado | str | não | UUID original do usuário no Supabase (auth.users.id; máx. 36). |
uuid_legado | str | não | UUID do registro original do vínculo (migração; máx. 36). |
MedicoUsuarioVinculoUpdate
Todos os campos opcionais; apenas os enviados são atualizados.
| Campo | Tipo | Observações |
|---|---|---|
id_medico | int | Reaponta o vínculo para outro médico. |
id_usuario | int | Reaponta o vínculo para outro usuário. |
uuid_usuario_legado | str | UUID original do usuário (máx. 36). |
MedicoUsuarioVinculoRead
| Campo | Tipo | Notas |
|---|---|---|
id | int | Identificador interno do vínculo. |
id_medico | int | Médico vinculado. |
id_usuario | int? | Usuário interno vinculado. |
uuid_usuario_legado | str? | UUID original do usuário (migração). |
uuid_legado | str? | UUID original do vínculo (migração). |
id_usuario_created | int? | Usuário que criou (auditoria). |
created_at | datetime | Timestamp de criação. |
updated_at | datetime | Timestamp da última atualização. |
Notas
- Toda resposta segue o envelope
{ success, message, data }(ou{ success: false, message, details }em erro). Códigos HTTP refletem semântica REST padrão. - Ordem de rotas no FastAPI. As rotas estáticas
POST /vinculos,GET /vinculos/by-medico/{id_medico},PUT/DELETE /vinculos/{vinculo_id}eGET /by-prestador/{id_prestador}são declaradas antes da rota dinâmicaGET /{medico_id}. Isso garante quevinculoseby-prestadorsejam resolvidos como rotas estáticas (e não interpretados como ummedico_id). - Mapeamento de erros do backend: mensagens com "não encontrado" →
404, "já existe" →409, "acesso negado" →403; caso contrário →422. - O campo
cpfé normalizado para apenas dígitos antes da persistência (o front pode enviar com máscara); string vazia viranull. id_usuario_creatednunca entra no body de criação - é preenchido pelo backend a partir do usuário autenticado.