docs

Customers

O recurso Customer — identificação por email, documento (CPF/CNPJ), endereço, e o que ele habilita em PaymentIntent e CustomerSubscription.

Customer é a entidade pessoa da Zhex. Cada cliente que volta para uma segunda compra, todo método salvo para cobrança recorrente, todo email de fatura — passa por aqui. Sem Customer, o PaymentIntent exige um — customer é parâmetro obrigatório no POST /v1/payment_intents.

Pense no Customer como um container leve: identidade (email, name, document), endereço, e a chave para anexar PaymentMethod e ler CustomerSubscription.

Anatomia

{
  "id": "cus_NffrFeUfNV2Hib",
  "object": "customer",
  "livemode": false,
  "email": "joao@meusite.com",
  "name": "João Silva",
  "phone": "+5511999990000",
  "document": "12345678909",
  "country": "BR",
  "address": {
    "line1": "Rua Tal, 100",
    "number": "100",
    "neighborhood": "Pinheiros",
    "city": "São Paulo",
    "state": "SP",
    "postal_code": "01000-000",
    "country": "BR"
  },
  "created": 1714060000
}

Campos opcionais; o único obrigatório no create é email e name. Email é o que vai no recibo, em cobrança recorrente falhada, no link de "atualize seu cartão". Sem email, esses fluxos quebram.

Criar customer

curl https://prometheus.zhex.io/v1/customers \
  -H "Authorization: Bearer $ZHEX_SECRET_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "joao@meusite.com",
    "name": "João Silva",
    "phone": "+5511999990000",
    "document": "12345678909",
    "address": "Rua Tal",
    "number": "100",
    "neighborhood": "Pinheiros",
    "city": "São Paulo",
    "state": "SP",
    "zipcode": "01000-000",
    "country": "BR"
  }'

Boa prática: salve customer.id na sua coluna users.zhex_customer_id no signup. Você consulta sempre via essa FK, nunca por busca por email — é mais rápido.

Idempotente por email. Chamar POST /v1/customers com um email que já existe na sua conta (no mesmo modo) retorna o customer existente — não erra. Os campos mutáveis (name, phone, document, endereço) são atualizados com o que veio no request; o id permanece o mesmo. Você pode tratar customers.create como find-or-create sem precisar fazer GET /v1/customers?email= antes.

Endereço — campos do payload vs response

No request (create/update) você manda os campos individuais:

CampoNotas
addressLogradouro (rua, avenida)
numberNúmero do endereço
neighborhoodBairro
cityCidade
stateUF
zipcodeCEP
countryISO 3166-1 alpha-2 (default BR)

No response, eles vêm aninhados em address no formato Stripe-style: address: { line1, number, neighborhood, city, state, postal_code, country }. Mapping é direto — address (request) → line1 (response), zipcodepostal_code.

Documento (CPF/CNPJ)

A Zhex aceita o documento como string plana — formate como preferir, dígitos ou com pontuação. O campo document cobre CPF, CNPJ, EIN, RFC e equivalentes; o país é inferido por country no Customer.

await zhex.customers.create({
  email: 'empresa@acme.com.br',
  name: 'ACME Comércio',
  document: '11.222.333/0001-44',  // CNPJ
  country: 'BR',
});

Para cobrar boleto no Brasil, o documento é mandatório — sem ele a CIP recusa o registro. Para cartão, é altamente recomendado (reduz fricção em verificação de risco).

Update

POST /v1/customers/:id faz shallow merge — só os campos enviados mudam:

await zhex.customers.update('cus_…', {
  city: 'Rio de Janeiro',
  state: 'RJ',
});

Stripe-style: POST no recurso, não PATCH/PUT.

Buscar e listar

// retrieve por id
const customer = await zhex.customers.retrieve('cus_…');

// busca por email (paginated, pode haver múltiplos em test mode)
for await (const c of zhex.customers.list({
  email: 'joao@meusite.com',
  limit: 5,
}).autoPagingEach()) {
  /* ... */
}

Test mode vs Live mode

A unicidade de email é por modo: (companyId, email, livemode). O mesmo email pode existir uma vez em test e uma vez em live — sem colisão.

Cross-mode lookup retorna 404 (genérico, sem confirmar existência) — uma chave de test não enxerga clientes live e vice-versa.

Anexar PaymentMethod

PaymentMethod (pm_*) é a representação persistente de um meio de pagamento — diferente do Token que é single-use. Para cobrar de novo sem pedir o cartão:

// 1. cliente preenche zhex.js → vira tok_*
// 2. front manda tok_* pro seu servidor
// 3. seu servidor cria pm_* a partir de tok_*

const pm = await zhex.paymentMethods.create({
  type: 'card',
  token: 'tok_…',
  customer: 'cus_…',
});
// pm.id → "pm_…", pm.card.{brand,last4,exp_month,exp_year}

O token é consumido atomicamente — uma segunda chamada com o mesmo tok_* falha com token_unusable.

Listar payment methods de um customer

for await (const pm of zhex.paymentMethods.list({
  customer: 'cus_…',
  limit: 10,
}).autoPagingEach()) {
  /* pm.card.brand, pm.card.last4, pm.card.exp_month, pm.card.exp_year */
}

customer é obrigatório nessa listagem — não há "list all" cross-customer.

Detach

await zhex.paymentMethods.detach('pm_…');

Marca o pm_* como inativo (soft detach). Histórico de transações que o usaram continua intacto. O cartão não pode mais ser cobrado a partir desse pm_* — para nova cobrança, gere novo tok_*.

Webhooks emitidos

Hoje a API V1 emite os seguintes events relacionados a Customer/PaymentMethod:

EventoQuando
Nenhum direto sobre Customer aindaRoadmap — emit em create/update/detach

Customer mutações ainda não disparam webhook próprio. A próxima minor de Zhex-Version adiciona customer.created, customer.updated, payment_method.attached e payment_method.detached. Acompanhe o changelog.

Para reagir a side-effects de cobrança (recorrência, falha, refund), escute os events de PaymentIntent e CustomerSubscription.

Próximos passos

Esta página foi útil?

Atualizado em

Nesta página