Contatos
Contatos representam clientes (customer) e fornecedores (supplier) da sua conta. Para cobranças individuais (billing_issue_type=individual), o contact_id do cliente é obrigatório.
Veja conventions.md para paginação, autenticação, erros, rate limit e regras de isolamento entre contas.
Modelo
| Campo | Tipo | Observações |
|---|---|---|
id | integer | |
contact_type | string | "customer" ou "supplier". Singular — não confundir com o plural usado em grupos |
group_id | integer | null | FK para Group. Quando informado, o grupo precisa ser da mesma conta |
code | string | null | Identificador livre, até 20 chars |
active | boolean | Default true |
email | string | null | Formato de email válido, até 160 chars |
legal_entity | boolean | true = pessoa jurídica (CNPJ); false = pessoa física (CPF) |
full_name | string | Pessoa física: obrigatório, até 255 chars, regex de nome completo (mínimo nome + sobrenome). Pessoa jurídica: opcional |
company_name | string | Obrigatório se legal_entity=true, até 255 chars |
trademark | string | Nome fantasia, até 255 chars, opcional para PJ |
birth_date | date | Pessoa precisa ter ≥ 18 anos no momento do cadastro |
cpf | string | Pessoa física: obrigatório, exatamente 11 dígitos, CPF válido. Único por (conta, contact_type) |
cnpj | string | Pessoa jurídica: obrigatório, 14 caracteres (números ou letras A-Z; CNPJ alfanumérico válido a partir de jul/2026). Único por (conta, contact_type) |
business_phone_area, business_phone_number | string | DDD 2 dígitos; número 8 ou 9 dígitos |
cell_phone_area, cell_phone_number | string | Idem |
address_postal_code | string | CEP com 9 caracteres (formato 00000-000) |
address_street | string | 5..255 chars |
address_number | string | 1..10 chars |
address_complement | string | até 255 chars |
address_district | string | 3..255 chars |
address_city | string | 2..255 chars |
address_state | string | Sigla de UF (SP, RJ, …). Normalizada para maiúsculas no servidor |
observation | string | null | Texto livre |
description | string | Derivado: company_name se PJ, full_name se PF. Não enviar — calculado pelo Sacador |
document | string | Derivado: cnpj se PJ, cpf se PF |
created_at, updated_at | ISO-8601 |
Regras de PF vs PJ
O campo legal_entity controla quais validações são aplicadas:
legal_entity=false(PF): exigecpf, exigefull_nameno formato regex;cnpjecompany_namesão opcionais/ignorados na validação cruzada.legal_entity=true(PJ): exigecnpj, exigecompany_name.
Em ambos os casos, endereço completo é obrigatório (CEP, rua, número, bairro, cidade, UF) e o telefone (qualquer um dos pares) é opcional.
Endpoints
GET/v1/contacts
Lista os contatos da conta autenticada, ordenados por description ascendente.
Query params:
| Param | Tipo | Comportamento |
|---|---|---|
contact_type | customer | supplier | Filtra por tipo |
group_id | integer | "0" | Filtra por grupo. Use "0" para listar contatos sem grupo (group_id IS NULL) |
active | true | false | Filtra por status |
filter | string | Define o campo da busca: contact (default, busca por description), document (busca por CPF/CNPJ — só dígitos), email (busca por email começando com s), code (igualdade exata) |
s | string | Termo da busca, interpretado conforme filter |
page, per_page | int | Padrão de paginação |
Exemplo cURL:
curl -X GET 'https://api.sacador.com.br/v1/contacts?contact_type=customer&active=true&page=1' \
-H 'Authorization: Bearer sct_seu_token_aqui'
Resposta 200 OK:
{
"contacts": [
{
"id": 101,
"group_id": 12,
"contact_type": "customer",
"code": "C-0042",
"active": true,
"email": "cliente@exemplo.com",
"legal_entity": false,
"full_name": "Maria Silva",
"company_name": null,
"trademark": null,
"birth_date": "1990-03-15",
"cpf": "12345678901",
"cnpj": null,
"business_phone_area": "11",
"business_phone_number": "30001234",
"cell_phone_area": "11",
"cell_phone_number": "999998888",
"address_postal_code": "01310-100",
"address_street": "Avenida Paulista",
"address_number": "1000",
"address_complement": "Apto 42",
"address_district": "Bela Vista",
"address_city": "São Paulo",
"address_state": "SP",
"observation": null,
"description": "Maria Silva",
"document": "12345678901",
"created_at": "2026-04-01T10:00:00.000Z",
"updated_at": "2026-04-01T10:00:00.000Z"
}
]
}
GET/v1/contacts/:id
Exemplo cURL:
curl -X GET 'https://api.sacador.com.br/v1/contacts/101' \
-H 'Authorization: Bearer sct_seu_token_aqui'
Resposta 200 OK: objeto idêntico ao item da listagem.
Erros: 404 se inexistente ou de outra conta.
POST/v1/contacts
Cria um contato.
Body (envelopado em contact):
{
"contact": {
"contact_type": "customer",
"legal_entity": false,
"full_name": "Maria Silva",
"cpf": "123.456.789-01",
"email": "maria@exemplo.com",
"address_postal_code": "01310-100",
"address_street": "Avenida Paulista",
"address_number": "1000",
"address_district": "Bela Vista",
"address_city": "São Paulo",
"address_state": "sp"
}
}
Campos aceitos (qualquer outro campo enviado é ignorado, incluindo account_id):
contact_type, group_id, code, active, email, legal_entity, full_name, birth_date, cpf, cnpj, company_name, trademark, business_phone_area, business_phone_number, cell_phone_area, cell_phone_number, address_postal_code, address_street, address_number, address_complement, address_district, address_city, address_state, observation.
Normalização aplicada pelo servidor
cpf: removidos todos os caracteres não-dígito.cnpj: removidos caracteres fora de[A-Z0-9]e convertido para maiúsculas.email: minúsculo e sem espaços.address_state: maiúsculo.full_name,company_name,trademark,address_*: espaços em excesso são colapsados (squishize).
Exemplo cURL (pessoa física):
curl -X POST 'https://api.sacador.com.br/v1/contacts' \
-H 'Authorization: Bearer sct_seu_token_aqui' \
-H 'Content-Type: application/json' \
-d '{
"contact": {
"contact_type": "customer",
"legal_entity": false,
"full_name": "Maria Silva",
"cpf": "123.456.789-01",
"email": "maria@exemplo.com",
"cell_phone_area": "11",
"cell_phone_number": "999998888",
"address_postal_code": "01310-100",
"address_street": "Avenida Paulista",
"address_number": "1000",
"address_district": "Bela Vista",
"address_city": "São Paulo",
"address_state": "SP"
}
}'
Exemplo cURL (pessoa jurídica):
curl -X POST 'https://api.sacador.com.br/v1/contacts' \
-H 'Authorization: Bearer sct_seu_token_aqui' \
-H 'Content-Type: application/json' \
-d '{
"contact": {
"contact_type": "customer",
"legal_entity": true,
"company_name": "Acme Comércio Ltda",
"trademark": "Acme",
"cnpj": "12.345.678/0001-90",
"email": "financeiro@acme.com.br",
"address_postal_code": "04538-132",
"address_street": "Rua Funchal",
"address_number": "263",
"address_district": "Vila Olímpia",
"address_city": "São Paulo",
"address_state": "SP"
}
}'
Resposta 201 Created: corpo idêntico a um item de GET/v1/contacts (todos os campos do Modelo).
Erros 422:
- CPF/CNPJ inválido ou já cadastrado (mesma conta + mesmo contact_type)
- full_name fora do regex (PF)
- company_name fora do regex (PJ)
- Endereço incompleto
- Email mal formado
- group_id aponta para grupo de outra conta
PATCH/v1/contacts/:id
Atualiza um contato. Mesmos campos do POST. Campos omitidos preservam o valor atual.
Exemplo cURL:
curl -X PATCH 'https://api.sacador.com.br/v1/contacts/101' \
-H 'Authorization: Bearer sct_seu_token_aqui' \
-H 'Content-Type: application/json' \
-d '{
"contact": {
"email": "novo-email@exemplo.com",
"cell_phone_number": "988887777"
}
}'
Resposta 200 OK: corpo idêntico a um item de GET/v1/contacts.
Erros: 404 (conta errada), 422 (validação).
DELETE/v1/contacts/:id
Exemplo cURL:
curl -X DELETE 'https://api.sacador.com.br/v1/contacts/101' \
-H 'Authorization: Bearer sct_seu_token_aqui'
Resposta 204 No Content.
Erros:
- 404 — contato inexistente ou de outra conta
- 422 — contato possui cobranças (billings), contas a pagar/receber (bills) ou lançamentos de caixa (cashiers) associados. A exclusão é bloqueada (restrict_with_error)