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

CampoTipoObservações
idinteger
contact_typestring"customer" ou "supplier". Singular — não confundir com o plural usado em grupos
group_idinteger | nullFK para Group. Quando informado, o grupo precisa ser da mesma conta
codestring | nullIdentificador livre, até 20 chars
activebooleanDefault true
emailstring | nullFormato de email válido, até 160 chars
legal_entitybooleantrue = pessoa jurídica (CNPJ); false = pessoa física (CPF)
full_namestringPessoa física: obrigatório, até 255 chars, regex de nome completo (mínimo nome + sobrenome). Pessoa jurídica: opcional
company_namestringObrigatório se legal_entity=true, até 255 chars
trademarkstringNome fantasia, até 255 chars, opcional para PJ
birth_datedatePessoa precisa ter ≥ 18 anos no momento do cadastro
cpfstringPessoa física: obrigatório, exatamente 11 dígitos, CPF válido. Único por (conta, contact_type)
cnpjstringPessoa 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_numberstringDDD 2 dígitos; número 8 ou 9 dígitos
cell_phone_area, cell_phone_numberstringIdem
address_postal_codestringCEP com 9 caracteres (formato 00000-000)
address_streetstring5..255 chars
address_numberstring1..10 chars
address_complementstringaté 255 chars
address_districtstring3..255 chars
address_citystring2..255 chars
address_statestringSigla de UF (SP, RJ, …). Normalizada para maiúsculas no servidor
observationstring | nullTexto livre
descriptionstringDerivado: company_name se PJ, full_name se PF. Não enviar — calculado pelo Sacador
documentstringDerivado: cnpj se PJ, cpf se PF
created_at, updated_atISO-8601

Regras de PF vs PJ

O campo legal_entity controla quais validações são aplicadas:

  • legal_entity=false (PF): exige cpf, exige full_name no formato regex; cnpj e company_name são opcionais/ignorados na validação cruzada.
  • legal_entity=true (PJ): exige cnpj, exige company_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:

ParamTipoComportamento
contact_typecustomer | supplierFiltra por tipo
group_idinteger | "0"Filtra por grupo. Use "0" para listar contatos sem grupo (group_id IS NULL)
activetrue | falseFiltra por status
filterstringDefine 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)
sstringTermo da busca, interpretado conforme filter
page, per_pageintPadrã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)