NFS-e/Repasse: Tomadores
Endpoints da WebApiAlcance para gerenciar os tomadores de serviço do produto NFS-e/Repasse Médico - as clínicas, hospitais e demais entidades para quem os profissionais prestam serviço e emitem nota fiscal. Cobrem criação, listagem geral com filtros, listagem por cliente associado, detalhamento por ID, atualização e exclusão.
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 por todo o produto NFS-e/Repasse
O escopo deriva do 1º segmento após /api/v1/, que aqui é nfse-repasse → nfse_repasse. Portanto os escopos nfse_repasse:read e nfse_repasse:write são compartilhados por TODO o produto NFS-e/Repasse - Tomadores e todos os demais subdomínios do produto usam os mesmos dois escopos. Uma API Key com nfse_repasse:write pode escrever em qualquer subdomínio do produto; dimensione a emissão de chaves com esse alcance em mente.
Base path
/api/v1/nfse-repasse/tomadoresEscopos necessários
nfse_repasse:read- listagem, listagem por cliente e detalhamentonfse_repasse:write- criação, atualização e exclusão
O escopo é derivado do primeiro segmento da rota após /api/v1/: nfse-repasse vira o recurso nfse_repasse (hífen → underscore), e o método HTTP define a ação (read para GET, write para POST/PUT/DELETE). Esses escopos valem para todos os subdomínios do produto NFS-e/Repasse, não só para Tomadores.
Endpoints
POST /nfse-repasse/tomadores/
Cria um novo tomador de serviço. O id_usuario_created é preenchido a partir do usuário autenticado - não é aceito no corpo. Exige perfil administrador.
Parâmetros
Este endpoint não recebe parâmetros de rota ou query - os dados vão no corpo da requisição (TomadorCreate). O único campo obrigatório é razao_social; os demais são opcionais. status tem default "ativo" e só aceita "ativo" ou "inativo".
Request
{
"razao_social": "Clínica Exemplo LTDA",
"nome_fantasia": "Clínica Exemplo",
"cpfecnpj": "12.345.678/0001-99",
"inscricao_municipal": "1234567",
"email": "contato@clinicaexemplo.com.br",
"telefone": "(11) 3000-0000",
"municipio": "São Paulo",
"uf": "SP",
"status": "ativo",
"id_customer": 1
}Response 201 Created
{
"success": true,
"message": "Tomador criado com sucesso!",
"data": {
"id": 1,
"razao_social": "Clínica Exemplo LTDA",
"nome_fantasia": "Clínica Exemplo",
"cpfecnpj": "12345678000199",
"inscricao_municipal": "1234567",
"email": "contato@clinicaexemplo.com.br",
"telefone": "(11) 3000-0000",
"endereco": null,
"municipio": "São Paulo",
"uf": "SP",
"status": "ativo",
"id_customer": 1,
"uuid_legado": null,
"id_usuario_created": 42,
"created_at": "2026-07-03T12:00:00Z",
"updated_at": "2026-07-03T12:00:00Z"
}
}Conflitos (registro já existente) retornam 409 Conflict; validações de negócio retornam 422 Unprocessable Entity. Escopo: nfse_repasse:write
GET /nfse-repasse/tomadores/by-customer/{customer_id}
Lista os tomadores associados a um cliente (customer.id), com filtro opcional por status e paginação. Lista vazia é um estado válido - retorna 200 OK com data: [].
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
customer_id | int | path | sim | ID do cliente associado (customer.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": "Tomadores recuperados com sucesso!",
"data": [
{
"id": 1,
"razao_social": "Clínica Exemplo LTDA",
"nome_fantasia": "Clínica Exemplo",
"cpfecnpj": "12345678000199",
"status": "ativo",
"id_customer": 1,
"id_usuario_created": 42,
"created_at": "2026-07-03T12:00:00Z",
"updated_at": "2026-07-03T12:00:00Z"
}
]
}Escopo: nfse_repasse:read
GET /nfse-repasse/tomadores/
Lista os tomadores com filtros opcionais (visão compartilhada single-company). Lista vazia é um estado válido - retorna 200 OK com data: [].
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
status | str | query | não | Filtro por status: ativo ou inativo. |
id_customer | int | query | não | Filtro por cliente associado (customer.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": "Tomadores recuperados com sucesso!",
"data": [
{
"id": 1,
"razao_social": "Clínica Exemplo LTDA",
"nome_fantasia": "Clínica Exemplo",
"cpfecnpj": "12345678000199",
"status": "ativo",
"id_customer": 1,
"id_usuario_created": 42,
"created_at": "2026-07-03T12:00:00Z",
"updated_at": "2026-07-03T12:00:00Z"
}
]
}Escopo: nfse_repasse:read
GET /nfse-repasse/tomadores/{tomador_id}
Detalha um tomador pelo ID inteiro. Quando não encontrado, retorna 404 Not Found.
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
tomador_id | int | path | sim | ID interno do tomador |
Request
Sem corpo de requisição.
Response 200 OK
{
"success": true,
"message": "Tomador encontrado!",
"data": {
"id": 1,
"razao_social": "Clínica Exemplo LTDA",
"nome_fantasia": "Clínica Exemplo",
"cpfecnpj": "12345678000199",
"inscricao_municipal": "1234567",
"email": "contato@clinicaexemplo.com.br",
"telefone": "(11) 3000-0000",
"endereco": null,
"municipio": "São Paulo",
"uf": "SP",
"status": "ativo",
"id_customer": 1,
"uuid_legado": null,
"id_usuario_created": 42,
"created_at": "2026-07-03T12:00:00Z",
"updated_at": "2026-07-03T12:00:00Z"
}
}Escopo: nfse_repasse:read
PUT /nfse-repasse/tomadores/{tomador_id}
Atualiza um tomador existente. O body é um TomadorUpdate com campos parciais - somente o que vier preenchido é alterado. Campos como id, uuid_legado, id_usuario_created, created_at e updated_at são imutáveis e não aparecem no schema (proteção contra mass-assignment). Exige perfil administrador.
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
tomador_id | int | path | sim | ID do tomador |
Request (TomadorUpdate - todos os campos opcionais)
{
"nome_fantasia": "Clínica Exemplo Matriz",
"status": "inativo"
}Response 200 OK
{
"success": true,
"message": "Tomador atualizado!",
"data": {
"id": 1,
"razao_social": "Clínica Exemplo LTDA",
"nome_fantasia": "Clínica Exemplo Matriz",
"cpfecnpj": "12345678000199",
"status": "inativo",
"id_customer": 1,
"id_usuario_created": 42,
"created_at": "2026-07-03T12:00:00Z",
"updated_at": "2026-07-03T14:30:00Z"
}
}Escopo: nfse_repasse:write
DELETE /nfse-repasse/tomadores/{tomador_id}
Remove um tomador pelo ID. Exige perfil administrador.
Parâmetros
| Parâmetro | Tipo | Local | Obrigatório | Descrição |
|---|---|---|---|---|
tomador_id | int | path | sim | ID do tomador |
Request
Sem corpo de requisição.
Response 200 OK
{
"success": true,
"message": "Tomador removido!",
"data": null
}Escopo: nfse_repasse:write
Schemas
TomadorCreate
| Campo | Tipo | Obrigatório | Observações |
|---|---|---|---|
razao_social | str | sim | Razão social do tomador. Máx. 200 caracteres. |
nome_fantasia | str | não | Nome fantasia. Máx. 200. |
cpfecnpj | str | não | CPF ou CNPJ. Front pode enviar com máscara - é normalizado para só dígitos. Máx. 20. |
inscricao_municipal | str | não | Inscrição municipal. Máx. 50. |
email | str | não | E-mail de contato. Máx. 100. |
telefone | str | não | Telefone de contato. Máx. 50. |
endereco | str | não | Endereço. Máx. 200. |
municipio | str | não | Município. Máx. 100. |
uf | str | não | UF (sigla de 2 letras). |
status | str | não | ativo (default) ou inativo. Outros valores são rejeitados. |
id_customer | int | não | ID do cliente (customer.id) associado. Associação de negócio, não isolamento. |
uuid_legado | str | não | UUID do registro original no Supabase (rastreabilidade da migração). Imutável após criação. Máx. 36. |
TomadorUpdate
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 e não aparecem aqui (bloqueio de mass-assignment).
| Campo | Tipo | Observações |
|---|---|---|
razao_social | str | Nova razão social. Máx. 200. |
nome_fantasia | str | Máx. 200. |
cpfecnpj | str | Normalizado para só dígitos. Máx. 20. |
inscricao_municipal | str | Máx. 50. |
email | str | Máx. 100. |
telefone | str | Máx. 50. |
endereco | str | Máx. 200. |
municipio | str | Máx. 100. |
uf | str | Sigla de 2 letras. |
status | str | ativo ou inativo. |
id_customer | int | Reassocia o tomador a outro cliente. |
TomadorRead
Estende TomadorBase com campos gerenciados pelo servidor.
| Campo | Tipo | Notas |
|---|---|---|
id | int | Identificador interno do tomador. |
razao_social | str | Razão social. |
nome_fantasia | str | Nome fantasia. |
cpfecnpj | str | CPF/CNPJ (apenas dígitos, sem máscara). |
inscricao_municipal | str | Inscrição municipal. |
email | str | E-mail de contato. |
telefone | str | Telefone de contato. |
endereco | str | Endereço. |
municipio | str | Município. |
uf | str | UF. |
status | str | ativo ou inativo. |
id_customer | int | Cliente associado (customer.id). |
uuid_legado | str | UUID do registro original no Supabase. |
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. |
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 (404não encontrado,409conflito,403acesso negado,422validação). - Ordem de rotas (FastAPI). A rota estática
GET /by-customer/{customer_id}é declarada antes da rota dinâmicaGET /{tomador_id}. Isso é intencional: invertê-las faria o router casarby-customercomo umtomador_idinválido. - O
cpfecnpjé normalizado para apenas dígitos antes da persistência - o front pode enviar com máscara. Não há validação de comprimento (aceita CPF de 11 ou CNPJ de 14 dígitos). uuid_legadoé metadado da migração single-company (appwebapp-nfs-repasse-medico, Supabase): aceito no Create para correlação com o registro de origem, mas imutável depois.id_usuario_createdé preenchido pelo servidor a partir do usuário autenticado - nunca vem no corpo do Create.