Voltar
Documentação da API

API ZorinPay

Esta documentação descreve todas as rotas que utilizam API Key para integração externa. Use sua chave API no header Authorization: Bearer <sua_api_key> em cada requisição.

Base URL: https://api.zorinpay.com/v1

Autenticação com API Key

Como autenticar
Todas as rotas documentadas aqui exigem uma API Key válida. Crie e gerencie suas chaves em Dashboard → API Keys (após login).

Envie a API Key no header Authorization com o esquema Bearer:

Authorization: Bearer sk_test_xxxxxxxxxxxxxxxxxxxxxxxx

Chaves de teste têm prefixo sk_test_ e podem usar simulação de pagamentos. Chaves de produção usam sk_live_.

Escopos (Scopes)

Cada API Key possui um conjunto de escopos. A rota só é autorizada se a chave tiver o escopo necessário. Os escopos disponíveis são carregados do backend quando você está logado.

Não foi possível carregar os escopos. Verifique sua conexão ou tente novamente.

Idempotência

Para rotas de criação (POST) que suportam idempotência, envie o header Idempotency-Key ou X-Idempotency-Key com um valor único (ex.: UUID). Assim, requisições duplicadas retornam o mesmo resultado sem criar registros duplicados.

Rotas da API

Todas as rotas abaixo usam o prefixo base https://api.zorinpay.com/v1.

Health Check
Base: https://api.zorinpay.com/v1/health
GET/health

Verifica se a API está online. Não requer autenticação.

Campos da resposta (data)

CampoTipoObrigatórioDescrição
statusstringSimEstado da API ("ok" quando online).
timestampstringSimData/hora da verificação (ISO 8601).

Respostas

Status: 200 OK

{
  "status": "ok",
  "timestamp": "2025-01-15T10:00:00.000Z"
}
Clientes
Base: https://api.zorinpay.com/v1/customer
POST/customer/createcustomer.create

Cria um novo cliente.

Headers

Authorization: Bearer <sua_api_key>
Content-Type: application/json

Body (JSON)

{
  "name": "João Silva",
  "cellphone": "+5511999999999",
  "email": "[email protected]",
  "taxId": "12345678900",
  "address": null
}

Campos da requisição

CampoTipoObrigatórioDescrição
namestringSimNome completo do cliente.
cellphonestringSimTelefone do cliente no formato E.164 (ex.: +5511999999999).
emailstringSimE-mail do cliente.
taxIdstringSimCPF ou CNPJ do cliente (somente dígitos).
addressobject | nullNãoEndereço do cliente (opcional).

Campos da resposta (data)

CampoTipoObrigatórioDescrição
idstringSimIdentificador do cliente gerado pela Zorinpay.
metadataobjectSimDados cadastrais do cliente.
metadata.namestringSimNome completo do cliente.
metadata.cellphonestringSimTelefone do cliente no formato E.164.
metadata.emailstringSimE-mail do cliente.
metadata.taxIdstringSimCPF ou CNPJ do cliente.

Respostas

Status: 201 Created

{
  "data": {
    "id": "d290f1ee-6c54-4b01-90e6-d701748f0851",
    "metadata": {
      "name": "João Silva",
      "cellphone": "+5511999999999",
      "email": "[email protected]",
      "taxId": "12345678900"
    }
  },
  "error": null
}

Status: 400 Bad Request

{
  "statusCode": 400,
  "message": ["Nome é obrigatório", "Email deve ser um endereço de email válido"],
  "error": "Bad Request"
}
GET/customer/listcustomer.list

Lista clientes com paginação.

Query: page?, limit?

Headers

Authorization: Bearer <sua_api_key>

Campos da requisição

CampoTipoObrigatórioDescrição
pagenumberNãoNúmero da página (começa em 1).
limitnumberNãoQuantidade de itens por página.

Campos da resposta (data)

CampoTipoObrigatórioDescrição
customers[].idstringSimIdentificador do cliente.
customers[].metadata.namestringSimNome completo do cliente.
customers[].metadata.cellphonestringSimTelefone do cliente no formato E.164.
customers[].metadata.emailstringSimE-mail do cliente.
customers[].metadata.taxIdstringSimCPF ou CNPJ do cliente.
customers[].createdAtstringSimData/hora de criação do cliente (ISO 8601).
totalnumberSimTotal de clientes encontrados.
limitnumberSimItens por página aplicado.
pagenumberSimPágina atual.

Respostas

Status: 200 OK

{
  "data": {
    "customers": [
      {
        "id": "d290f1ee-6c54-4b01-90e6-d701748f0851",
        "metadata": {
          "name": "João Silva",
          "cellphone": "+5511999999999",
          "email": "[email protected]",
          "taxId": "12345678900"
        },
        "createdAt": "2025-01-15T10:00:00.000Z"
      }
    ],
    "total": 1,
    "limit": 20,
    "page": 1
  },
  "error": null
}
PUT/customer/:idcustomer.update

Atualiza dados de um cliente.

Headers

Authorization: Bearer <sua_api_key>
Content-Type: application/json

Body (JSON)

{
  "name": "João da Silva Santos",
  "cellphone": "+5511988888888"
}

Campos da requisição

CampoTipoObrigatórioDescrição
idstringSimID do cliente a ser atualizado (parâmetro de URL).
namestringNãoNovo nome completo do cliente.
cellphonestringNãoNovo telefone do cliente no formato E.164.
emailstringNãoNovo e-mail do cliente.
taxIdstringNãoNovo CPF ou CNPJ do cliente (somente dígitos).
addressobject | nullNãoNovo endereço do cliente.

Campos da resposta (data)

CampoTipoObrigatórioDescrição
idstringSimIdentificador do cliente.
metadataobjectSimDados cadastrais atualizados do cliente.
metadata.namestringSimNome completo do cliente.
metadata.cellphonestringSimTelefone do cliente no formato E.164.
metadata.emailstringSimE-mail do cliente.
metadata.taxIdstringSimCPF ou CNPJ do cliente.

Respostas

Status: 200 OK

{
  "data": {
    "id": "d290f1ee-6c54-4b01-90e6-d701748f0851",
    "metadata": {
      "name": "João da Silva Santos",
      "cellphone": "+5511988888888",
      "email": "[email protected]",
      "taxId": "12345678900"
    }
  },
  "error": null
}

Status: 404 Not Found

{
  "statusCode": 404,
  "message": "Cliente não encontrado",
  "error": "Not Found"
}
DELETE/customer/:idcustomer.delete

Remove um cliente.

Headers

Authorization: Bearer <sua_api_key>

Campos da requisição

CampoTipoObrigatórioDescrição
idstringSimID do cliente a ser removido (parâmetro de URL).

Campos da resposta (data)

CampoTipoObrigatórioDescrição
datanullSimEm caso de sucesso, data é null (nenhum conteúdo retornado).

Respostas

Status: 200 OK

{
  "data": null,
  "error": null
}

Status: 404 Not Found

{
  "statusCode": 404,
  "message": "Cliente não encontrado",
  "error": "Not Found"
}
Cobranças
Base: https://api.zorinpay.com/v1/billings
POST/billings/one-timebilling.createIdempotency-Key

Cria cobrança avulsa (pagamento único).

Headers

Authorization: Bearer <sua_api_key>
Content-Type: application/json
Idempotency-Key: <uuid> (recomendado)

Body (JSON)

{
  "customer": {
    "name": "João Silva",
    "cellphone": "+5511999999999",
    "email": "[email protected]",
    "taxId": "12345678900"
  },
  "products": [
    {
      "name": "Plano Pro",
      "description": "Assinatura mensal",
      "quantity": 1,
      "price": 9990
    }
  ],
  "methods": ["PIX"],
  "returnUrl": "https://minhaapp.com/return",
  "completionUrl": "https://minhaapp.com/obrigado",
  "metadata": { "orderId": "pedido-123" },
  "externalId": "pedido-123"
}

Campos da requisição

CampoTipoObrigatórioDescrição
customerIdstringNãoID de um cliente já cadastrado, para reaproveitá-lo na cobrança. Alternativa ao objeto customer; se enviado, o objeto customer é ignorado.
customerobjectNãoDados do pagador, usados para cadastrar um cliente novo. Alternativa ao customerId. Se o e-mail ou o CPF/CNPJ já pertencerem a um cliente seu, a requisição falha com 409 — nesse caso envie customerId. Omitindo os dois, a cobrança é criada sem cliente vinculado.
customer.namestringNãoNome completo do pagador. Obrigatório quando customer é enviado.
customer.cellphonestringNãoTelefone do pagador no formato E.164 (ex.: +5511999999999). Obrigatório quando customer é enviado.
customer.emailstringNãoE-mail do pagador. Obrigatório quando customer é enviado.
customer.taxIdstringNãoCPF ou CNPJ do pagador (somente dígitos). Obrigatório quando customer é enviado.
productsobject[]SimLista de produtos/itens da cobrança.
products[].namestringSimNome do produto.
products[].descriptionstringNãoDescrição do produto.
products[].quantitynumberSimQuantidade do produto.
products[].pricenumberSimPreço unitário em centavos (ex.: 9990 = R$ 99,90).
methodsstring[]SimMétodos de pagamento aceitos (ex.: ["PIX"]).
returnUrlstringSimURL de retorno após o pagamento.
completionUrlstringSimURL de conclusão exibida ao final do fluxo.
metadataobjectNãoObjeto livre de dados adicionais, devolvido nos webhooks e na consulta.
externalIdstringNãoIdentificador único da cobrança no seu sistema.
allowCouponsbooleanNãoPermite aplicar cupons de desconto nesta cobrança.
couponsstring[]NãoLista de códigos de cupom aplicáveis.

Campos da resposta (data)

CampoTipoObrigatórioDescrição
idstringSimIdentificador da cobrança gerado pela Zorinpay.
frequencyenumSimFrequência da cobrança (ONE_TIME para avulsa).
recurrenceIntervalDaysnumber | nullNãoIntervalo em dias da recorrência (null para avulsa).
urlstringSimURL da página de pagamento da cobrança.
statusenumSimStatus atual da cobrança (ex.: PENDING, PAID).
devModebooleanSimIndica se a cobrança foi criada em modo de testes (sandbox).
methodsstring[]SimMétodos de pagamento aceitos.
amountnumberSimValor total da cobrança em centavos.
feeAmountnumberSimTaxa aplicada em centavos.
netAmountnumberSimValor líquido a receber em centavos.
currencystringSimMoeda da cobrança (ex.: BRL).
products[].idstringSimIdentificador do produto.
products[].namestringSimNome do produto.
products[].descriptionstringNãoDescrição do produto.
products[].quantitynumberSimQuantidade do produto.
products[].pricenumberSimPreço unitário em centavos.
customer.idstringSimIdentificador do pagador.
customer.namestringSimNome do pagador.
customer.emailstringSimE-mail do pagador.
customer.documentstringSimDocumento do pagador (CPF/CNPJ).
customer.documentTypeenumSimTipo do documento (CPF ou CNPJ).
customer.personTypeenumSimTipo de pessoa (PF ou PJ).
metadataobjectNãoMetadados da cobrança, incluindo URLs e dados livres informados.
allowCouponsbooleanSimIndica se a cobrança aceita cupons.
couponsobject[]SimCupons aplicados à cobrança.
qrCodestring | nullNãoCódigo PIX copia e cola, quando disponível.
qrCodeBase64string | nullNãoImagem do QR Code em base64, quando disponível.
paidAtstring | nullNãoData/hora do pagamento (ISO 8601), se paga.
createdAtstringSimData/hora de criação (ISO 8601).
updatedAtstringSimData/hora da última atualização (ISO 8601).

Respostas

Status: 201 Created

{
  "data": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "frequency": "ONE_TIME",
    "recurrenceIntervalDays": null,
    "url": "https://zorinpay.com/pay/a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "status": "PENDING",
    "devMode": false,
    "methods": ["PIX"],
    "amount": 9990,
    "feeAmount": 0,
    "netAmount": 9990,
    "currency": "BRL",
    "products": [
      {
        "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
        "name": "Plano Pro",
        "description": "Assinatura mensal",
        "quantity": 1,
        "price": 9990
      }
    ],
    "customer": {
      "id": "b3c4d5e6-f7a8-9012-bcde-f34567890123",
      "name": "João Silva",
      "email": "[email protected]",
      "document": "12345678900",
      "documentType": "CPF",
      "personType": "PF"
    },
    "metadata": {
      "fee": 0,
      "returnUrl": "https://minhaapp.com/return",
      "completionUrl": "https://minhaapp.com/obrigado",
      "orderId": "pedido-123"
    },
    "allowCoupons": false,
    "coupons": [],
    "qrCode": null,
    "qrCodeBase64": null,
    "paidAt": null,
    "createdAt": "2025-01-15T10:00:00.000Z",
    "updatedAt": "2025-01-15T10:00:00.000Z"
  },
  "error": null
}

Status: 400 Bad Request

{
  "statusCode": 400,
  "message": ["Produtos são obrigatórios", "URL de retorno é obrigatória"],
  "error": "Bad Request"
}
POST/billings/recurringbilling.createIdempotency-Key

Cria cobrança recorrente.

Headers

Authorization: Bearer <sua_api_key>
Content-Type: application/json
Idempotency-Key: <uuid> (recomendado)

Body (JSON)

{
  "customer": {
    "name": "João Silva",
    "cellphone": "+5511999999999",
    "email": "[email protected]",
    "taxId": "12345678900"
  },
  "products": [
    {
      "name": "Plano Pro",
      "quantity": 1,
      "price": 9990
    }
  ],
  "recurrenceIntervalDays": 30,
  "methods": ["PIX"],
  "returnUrl": "https://minhaapp.com/return",
  "completionUrl": "https://minhaapp.com/obrigado"
}

Campos da requisição

CampoTipoObrigatórioDescrição
customerIdstringNãoID de um cliente já cadastrado, para reaproveitá-lo na cobrança. Alternativa ao objeto customer; se enviado, o objeto customer é ignorado.
customerobjectNãoDados do pagador, usados para cadastrar um cliente novo. Alternativa ao customerId. Se o e-mail ou o CPF/CNPJ já pertencerem a um cliente seu, a requisição falha com 409 — nesse caso envie customerId. Omitindo os dois, a cobrança é criada sem cliente vinculado.
customer.namestringNãoNome completo do pagador. Obrigatório quando customer é enviado.
customer.cellphonestringNãoTelefone do pagador no formato E.164 (ex.: +5511999999999). Obrigatório quando customer é enviado.
customer.emailstringNãoE-mail do pagador. Obrigatório quando customer é enviado.
customer.taxIdstringNãoCPF ou CNPJ do pagador (somente dígitos). Obrigatório quando customer é enviado.
productsobject[]SimLista de produtos/itens da cobrança.
products[].namestringSimNome do produto.
products[].quantitynumberSimQuantidade do produto.
products[].pricenumberSimPreço unitário em centavos (ex.: 9990 = R$ 99,90).
recurrenceIntervalDaysnumberSimIntervalo em dias entre cada cobrança recorrente.
methodsstring[]SimMétodos de pagamento aceitos (ex.: ["PIX"]).
returnUrlstringSimURL de retorno após o pagamento.
completionUrlstringSimURL de conclusão exibida ao final do fluxo.
metadataobjectNãoObjeto livre de dados adicionais, devolvido nos webhooks e na consulta.

Campos da resposta (data)

CampoTipoObrigatórioDescrição
idstringSimIdentificador da cobrança gerado pela Zorinpay.
frequencyenumSimFrequência da cobrança (MULTIPLE_TIMES para recorrente).
recurrenceIntervalDaysnumberSimIntervalo em dias entre cada cobrança.
urlstringSimURL da página de pagamento da cobrança.
statusenumSimStatus atual da cobrança (ex.: PENDING, PAID).
devModebooleanSimIndica se a cobrança foi criada em modo de testes (sandbox).
methodsstring[]SimMétodos de pagamento aceitos.
amountnumberSimValor total da cobrança em centavos.
feeAmountnumberSimTaxa aplicada em centavos.
netAmountnumberSimValor líquido a receber em centavos.
currencystringSimMoeda da cobrança (ex.: BRL).
productsobject[]SimProdutos da cobrança (mesma estrutura enviada na criação, com id).
nextBillingstring | nullNãoData/hora da próxima cobrança (ISO 8601).
allowCouponsbooleanSimIndica se a cobrança aceita cupons.
couponsobject[]SimCupons aplicados à cobrança.
createdAtstringSimData/hora de criação (ISO 8601).
updatedAtstringSimData/hora da última atualização (ISO 8601).

Respostas

Status: 201 Created

{
  "data": {
    "id": "e5f6a7b8-c9d0-1234-ef56-789012345678",
    "frequency": "MULTIPLE_TIMES",
    "recurrenceIntervalDays": 30,
    "url": "https://zorinpay.com/pay/e5f6a7b8-c9d0-1234-ef56-789012345678",
    "status": "PENDING",
    "devMode": false,
    "methods": ["PIX"],
    "amount": 9990,
    "feeAmount": 0,
    "netAmount": 9990,
    "currency": "BRL",
    "products": [],
    "nextBilling": "2025-02-14T10:00:00.000Z",
    "allowCoupons": false,
    "coupons": [],
    "createdAt": "2025-01-15T10:00:00.000Z",
    "updatedAt": "2025-01-15T10:00:00.000Z"
  },
  "error": null
}
GET/billingsbilling.list

Lista cobranças com filtros. Paginação por offset/limit (limit padrão 50).

Query: customerId?, offset? (padrão 0), limit? (padrão 50)

Headers

Authorization: Bearer <sua_api_key>

Campos da requisição

CampoTipoObrigatórioDescrição
customerIdstringNãoFiltra cobranças de um cliente específico.
offsetnumberNãoDeslocamento de paginação (padrão 0).
limitnumberNãoQuantidade de itens por página (padrão 50).

Campos da resposta (data)

CampoTipoObrigatórioDescrição
data[].idstringSimIdentificador da cobrança.
data[].frequencyenumSimFrequência da cobrança (ONE_TIME ou MULTIPLE_TIMES).
data[].urlstringSimURL da página de pagamento.
data[].statusenumSimStatus atual da cobrança (ex.: PENDING, PAID).
data[].devModebooleanSimIndica se a cobrança é de modo de testes.
data[].methodsstring[]SimMétodos de pagamento aceitos.
data[].amountnumberSimValor total em centavos.
data[].feeAmountnumberSimTaxa aplicada em centavos.
data[].netAmountnumberSimValor líquido em centavos.
data[].currencystringSimMoeda da cobrança (ex.: BRL).
data[].productsobject[]SimProdutos/itens da cobrança.
data[].customerobjectSimDados do pagador.
data[].metadataobjectNãoMetadados da cobrança.
data[].nextBillingstring | nullNãoPróxima cobrança (ISO 8601), para recorrentes.
data[].allowCouponsbooleanSimIndica se aceita cupons.
data[].couponsobject[]SimCupons aplicados.
data[].paidAtstring | nullNãoData/hora do pagamento (ISO 8601), se paga.
data[].createdAtstringSimData/hora de criação (ISO 8601).
data[].updatedAtstringSimData/hora da última atualização (ISO 8601).
totalnumberSimTotal de cobranças encontradas.
limitnumberSimItens por página aplicado.
offsetnumberSimDeslocamento de paginação aplicado.

Respostas

Status: 200 OK

{
  "data": [
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "frequency": "ONE_TIME",
      "url": "https://zorinpay.com/pay/a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "status": "PAID",
      "devMode": false,
      "methods": ["PIX"],
      "amount": 9990,
      "feeAmount": 199,
      "netAmount": 9791,
      "currency": "BRL",
      "products": [],
      "customer": {  },
      "metadata": {  },
      "nextBilling": null,
      "allowCoupons": false,
      "coupons": [],
      "paidAt": "2025-01-15T10:05:00.000Z",
      "createdAt": "2025-01-15T10:00:00.000Z",
      "updatedAt": "2025-01-15T10:05:00.000Z"
    }
  ],
  "total": 1,
  "limit": 50,
  "offset": 0,
  "error": null
}
GET/billings/search/metadatabilling.search

Busca cobranças por chave/valor em metadata. Paginação por offset/limit (limit padrão 50).

Query: key, value, offset? (padrão 0), limit? (padrão 50)

Headers

Authorization: Bearer <sua_api_key>

Campos da requisição

CampoTipoObrigatórioDescrição
keystringSimChave a buscar dentro do metadata da cobrança (ex.: orderId).
valuestringSimValor correspondente à chave informada.
offsetnumberNãoDeslocamento de paginação (padrão 0).
limitnumberNãoQuantidade de itens por página (padrão 50).

Campos da resposta (data)

CampoTipoObrigatórioDescrição
data[]objectSimCobrança encontrada (mesma estrutura do item de GET /billings).
totalnumberSimTotal de cobranças encontradas.
limitnumberSimItens por página aplicado.
offsetnumberSimDeslocamento de paginação aplicado.

Respostas

Status: 200 OK

{
  "data": [],
  "total": 5,
  "limit": 50,
  "offset": 0,
  "error": null
}
GET/billings/:idbilling.read

Retorna uma cobrança pelo ID.

Headers

Authorization: Bearer <sua_api_key>

Campos da requisição

CampoTipoObrigatórioDescrição
idstringSimID da cobrança (parâmetro de URL).

Campos da resposta (data)

CampoTipoObrigatórioDescrição
idstringSimIdentificador da cobrança.
frequencyenumSimFrequência da cobrança (ONE_TIME ou MULTIPLE_TIMES).
urlstringSimURL da página de pagamento.
statusenumSimStatus atual da cobrança (ex.: PENDING, PAID).
devModebooleanSimIndica se a cobrança é de modo de testes.
methodsstring[]SimMétodos de pagamento aceitos.
amountnumberSimValor total em centavos.
feeAmountnumberSimTaxa aplicada em centavos.
netAmountnumberSimValor líquido em centavos.
currencystringSimMoeda da cobrança (ex.: BRL).
productsobject[]SimProdutos/itens da cobrança.
customerobjectSimDados do pagador.
metadataobjectNãoMetadados da cobrança.
qrCodestring | nullNãoCódigo PIX copia e cola, quando disponível.
qrCodeBase64string | nullNãoImagem do QR Code em base64, quando disponível.
e2eIdstring | nullNãoIdentificador end-to-end da transação PIX, quando paga.
clientNamestring | nullNãoNome do pagador (capturado via adquirente), quando pago.
clientDocumentstring | nullNãoDocumento (CPF/CNPJ) do pagador, quando pago.
paidAtstring | nullNãoData/hora do pagamento (ISO 8601), se paga.
createdAtstringSimData/hora de criação (ISO 8601).
updatedAtstringSimData/hora da última atualização (ISO 8601).

Respostas

Status: 200 OK

{
  "data": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "frequency": "ONE_TIME",
    "url": "https://zorinpay.com/pay/a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "status": "PAID",
    "devMode": false,
    "methods": ["PIX"],
    "amount": 9990,
    "feeAmount": 199,
    "netAmount": 9791,
    "currency": "BRL",
    "products": [],
    "customer": {  },
    "metadata": {  },
    "qrCode": "00020126...",
    "qrCodeBase64": "data:image/png;base64,...",
    "e2eId": "E12345678202401151005TESTPIXBR01",
    "clientName": "João Silva",
    "clientDocument": "12345678900",
    "paidAt": "2025-01-15T10:05:00.000Z",
    "createdAt": "2025-01-15T10:00:00.000Z",
    "updatedAt": "2025-01-15T10:05:00.000Z"
  },
  "error": null
}

Status: 404 Not Found

{
  "statusCode": 404,
  "message": "Cobrança não encontrada",
  "error": "Not Found"
}
POST/billings/:id/refundbilling.refund

Reembolsa uma cobrança paga (disponível apenas para cobranças elegíveis a reembolso PIX). O valor bruto é debitado da carteira do cliente e devolvido ao pagador via PIX. A taxa de processamento NÃO é restituída — o cliente assume esse custo. Dispara o webhook billing.refunded (ou pixqrcode.refunded para PIX QR Code).

Headers

Authorization: Bearer <sua_api_key>
Content-Type: application/json

Campos da requisição

CampoTipoObrigatórioDescrição
idstringSimID da cobrança a ser reembolsada (parâmetro de URL).
reasonstringNãoMotivo do reembolso (opcional), para registro.

Campos da resposta (data)

CampoTipoObrigatórioDescrição
billingIdstringSimIdentificador da cobrança reembolsada.
statusenumSimNovo status da cobrança (REFUNDED).
refundIdstringSimIdentificador do reembolso PIX (endToEndId).
refundedAtstringSimData/hora do reembolso (ISO 8601).
amountRefundednumberSimValor reembolsado em centavos.

Respostas

Status: 200 OK

{
  "billingId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "REFUNDED",
  "refundId": "E18236120202610061226...",
  "refundedAt": "2026-05-13T17:25:31.000Z",
  "amountRefunded": 9990
}

Status: 400 Bad Request

{
  "statusCode": 400,
  "message": "Apenas cobranças pagas podem ser reembolsadas (status atual: PENDING)",
  "error": "Bad Request"
}

Status: 403 Forbidden

{
  "statusCode": 403,
  "message": "Você não tem permissão para reembolsar esta cobrança",
  "error": "Forbidden"
}

Status: 404 Not Found

{
  "statusCode": 404,
  "message": "Cobrança não encontrada",
  "error": "Not Found"
}
POST/billings/one-time-splitbilling.createIdempotency-Key

Cria cobrança avulsa (pagamento único) com split de pagamento entre múltiplos recebedores.

Headers

Authorization: Bearer <sua_api_key>
Content-Type: application/json
Idempotency-Key: <uuid> (recomendado)

Body (JSON)

{
  "customer": {
    "name": "João Silva",
    "cellphone": "+5511999999999",
    "email": "[email protected]",
    "taxId": "12345678900"
  },
  "products": [
    {
      "name": "Plano Pro",
      "description": "Assinatura mensal",
      "quantity": 1,
      "price": 9990
    }
  ],
  "splits": [
    {
      "recipientEmail": "[email protected]",
      "type": "percentage",
      "value": 30
    }
  ],
  "methods": ["PIX"],
  "returnUrl": "https://minhaapp.com/return",
  "completionUrl": "https://minhaapp.com/obrigado",
  "metadata": { "orderId": "pedido-123" }
}

Campos da requisição

CampoTipoObrigatórioDescrição
customerIdstringNãoID de um cliente já cadastrado, para reaproveitá-lo na cobrança. Alternativa ao objeto customer; se enviado, o objeto customer é ignorado.
customerobjectNãoDados do pagador, usados para cadastrar um cliente novo. Alternativa ao customerId. Se o e-mail ou o CPF/CNPJ já pertencerem a um cliente seu, a requisição falha com 409 — nesse caso envie customerId. Omitindo os dois, a cobrança é criada sem cliente vinculado.
customer.namestringNãoNome completo do pagador. Obrigatório quando customer é enviado.
customer.cellphonestringNãoTelefone do pagador no formato E.164 (ex.: +5511999999999). Obrigatório quando customer é enviado.
customer.emailstringNãoE-mail do pagador. Obrigatório quando customer é enviado.
customer.taxIdstringNãoCPF ou CNPJ do pagador (somente dígitos). Obrigatório quando customer é enviado.
productsobject[]SimLista de produtos/itens da cobrança.
products[].namestringSimNome do produto.
products[].descriptionstringNãoDescrição do produto.
products[].quantitynumberSimQuantidade do produto.
products[].pricenumberSimPreço unitário em centavos (ex.: 9990 = R$ 99,90).
splitsobject[]SimRegras de divisão do pagamento entre recebedores.
splits[].recipientEmailstringSimE-mail do recebedor do split (deve ser uma conta Zorinpay).
splits[].typeenumSimTipo do split: "percentage" (percentual) ou "fixed" (valor fixo).
splits[].valuenumberSimValor do split: percentual (ex.: 30) ou valor fixo em centavos.
methodsstring[]SimMétodos de pagamento aceitos (ex.: ["PIX"]).
returnUrlstringSimURL de retorno após o pagamento.
completionUrlstringSimURL de conclusão exibida ao final do fluxo.
metadataobjectNãoObjeto livre de dados adicionais, devolvido nos webhooks e na consulta.
externalIdstringNãoIdentificador único da cobrança no seu sistema.
allowCouponsbooleanNãoPermite aplicar cupons de desconto nesta cobrança.
couponsstring[]NãoLista de códigos de cupom aplicáveis.

Campos da resposta (data)

CampoTipoObrigatórioDescrição
idstringSimIdentificador da cobrança gerado pela Zorinpay.
frequencyenumSimFrequência da cobrança (ONE_TIME para avulsa).
recurrenceIntervalDaysnumber | nullNãoIntervalo em dias da recorrência (null para avulsa).
urlstringSimURL da página de pagamento da cobrança.
statusenumSimStatus atual da cobrança (ex.: PENDING, PAID).
devModebooleanSimIndica se a cobrança é de modo de testes.
methodsstring[]SimMétodos de pagamento aceitos.
amountnumberSimValor total em centavos.
feeAmountnumberSimTaxa aplicada em centavos.
netAmountnumberSimValor líquido em centavos.
currencystringSimMoeda da cobrança (ex.: BRL).
productsobject[]SimProdutos da cobrança (com id).
customerobjectSimDados do pagador.
metadataobjectNãoMetadados da cobrança.
allowCouponsbooleanSimIndica se a cobrança aceita cupons.
couponsobject[]SimCupons aplicados à cobrança.
qrCodestring | nullNãoCódigo PIX copia e cola, quando disponível.
qrCodeBase64string | nullNãoImagem do QR Code em base64, quando disponível.
paidAtstring | nullNãoData/hora do pagamento (ISO 8601), se paga.
createdAtstringSimData/hora de criação (ISO 8601).
updatedAtstringSimData/hora da última atualização (ISO 8601).

Respostas

Status: 201 Created

{
  "data": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "frequency": "ONE_TIME",
    "recurrenceIntervalDays": null,
    "url": "https://zorinpay.com/pay/a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "status": "PENDING",
    "devMode": false,
    "methods": ["PIX"],
    "amount": 9990,
    "feeAmount": 0,
    "netAmount": 9990,
    "currency": "BRL",
    "products": [
      {
        "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
        "name": "Plano Pro",
        "description": "Assinatura mensal",
        "quantity": 1,
        "price": 9990
      }
    ],
    "customer": {
      "id": "b3c4d5e6-f7a8-9012-bcde-f34567890123",
      "name": "João Silva",
      "email": "[email protected]",
      "document": "12345678900",
      "documentType": "CPF",
      "personType": "PF"
    },
    "metadata": { "orderId": "pedido-123" },
    "allowCoupons": false,
    "coupons": [],
    "qrCode": "00020126...",
    "qrCodeBase64": "data:image/png;base64,...",
    "paidAt": null,
    "createdAt": "2025-01-15T10:00:00.000Z",
    "updatedAt": "2025-01-15T10:00:00.000Z"
  },
  "error": null
}

Status: 400 Bad Request

{
  "statusCode": 400,
  "message": "Não é possível incluir a si mesmo como recebedor do split.",
  "error": "Bad Request"
}
POST/billings/recurring-splitbilling.createIdempotency-Key

Cria cobrança recorrente com split de pagamento entre múltiplos recebedores.

Headers

Authorization: Bearer <sua_api_key>
Content-Type: application/json
Idempotency-Key: <uuid> (recomendado)

Body (JSON)

{
  "customer": {
    "name": "João Silva",
    "cellphone": "+5511999999999",
    "email": "[email protected]",
    "taxId": "12345678900"
  },
  "products": [
    {
      "name": "Plano Pro",
      "quantity": 1,
      "price": 9990
    }
  ],
  "splits": [
    {
      "recipientEmail": "[email protected]",
      "type": "percentage",
      "value": 30
    },
    {
      "recipientEmail": "[email protected]",
      "type": "fixed",
      "value": 500
    }
  ],
  "recurrenceIntervalDays": 30,
  "methods": ["PIX"],
  "returnUrl": "https://minhaapp.com/return",
  "completionUrl": "https://minhaapp.com/obrigado"
}

Campos da requisição

CampoTipoObrigatórioDescrição
customerIdstringNãoID de um cliente já cadastrado, para reaproveitá-lo na cobrança. Alternativa ao objeto customer; se enviado, o objeto customer é ignorado.
customerobjectNãoDados do pagador, usados para cadastrar um cliente novo. Alternativa ao customerId. Se o e-mail ou o CPF/CNPJ já pertencerem a um cliente seu, a requisição falha com 409 — nesse caso envie customerId. Omitindo os dois, a cobrança é criada sem cliente vinculado.
customer.namestringNãoNome completo do pagador. Obrigatório quando customer é enviado.
customer.cellphonestringNãoTelefone do pagador no formato E.164 (ex.: +5511999999999). Obrigatório quando customer é enviado.
customer.emailstringNãoE-mail do pagador. Obrigatório quando customer é enviado.
customer.taxIdstringNãoCPF ou CNPJ do pagador (somente dígitos). Obrigatório quando customer é enviado.
productsobject[]SimLista de produtos/itens da cobrança.
products[].namestringSimNome do produto.
products[].quantitynumberSimQuantidade do produto.
products[].pricenumberSimPreço unitário em centavos (ex.: 9990 = R$ 99,90).
splitsobject[]SimRegras de divisão do pagamento entre recebedores.
splits[].recipientEmailstringSimE-mail do recebedor do split (deve ser uma conta Zorinpay).
splits[].typeenumSimTipo do split: "percentage" (percentual) ou "fixed" (valor fixo).
splits[].valuenumberSimValor do split: percentual (ex.: 30) ou valor fixo em centavos.
recurrenceIntervalDaysnumberSimIntervalo em dias entre cada cobrança recorrente.
methodsstring[]SimMétodos de pagamento aceitos (ex.: ["PIX"]).
returnUrlstringSimURL de retorno após o pagamento.
completionUrlstringSimURL de conclusão exibida ao final do fluxo.
metadataobjectNãoObjeto livre de dados adicionais, devolvido nos webhooks e na consulta.

Campos da resposta (data)

CampoTipoObrigatórioDescrição
idstringSimIdentificador da cobrança gerado pela Zorinpay.
frequencyenumSimFrequência da cobrança (MULTIPLE_TIMES para recorrente).
recurrenceIntervalDaysnumberSimIntervalo em dias entre cada cobrança.
urlstringSimURL da página de pagamento da cobrança.
statusenumSimStatus atual da cobrança (ex.: PENDING, PAID).
devModebooleanSimIndica se a cobrança é de modo de testes.
methodsstring[]SimMétodos de pagamento aceitos.
amountnumberSimValor total em centavos.
feeAmountnumberSimTaxa aplicada em centavos.
netAmountnumberSimValor líquido em centavos.
currencystringSimMoeda da cobrança (ex.: BRL).
productsobject[]SimProdutos da cobrança (com id).
allowCouponsbooleanSimIndica se a cobrança aceita cupons.
couponsobject[]SimCupons aplicados à cobrança.
createdAtstringSimData/hora de criação (ISO 8601).
updatedAtstringSimData/hora da última atualização (ISO 8601).

Respostas

Status: 201 Created

{
  "data": {
    "id": "e5f6a7b8-c9d0-1234-ef56-789012345678",
    "frequency": "MULTIPLE_TIMES",
    "recurrenceIntervalDays": 30,
    "url": "https://zorinpay.com/pay/e5f6a7b8-c9d0-1234-ef56-789012345678",
    "status": "PENDING",
    "devMode": false,
    "methods": ["PIX"],
    "amount": 9990,
    "feeAmount": 0,
    "netAmount": 9990,
    "currency": "BRL",
    "products": [],
    "allowCoupons": false,
    "coupons": [],
    "createdAt": "2025-01-15T10:00:00.000Z",
    "updatedAt": "2025-01-15T10:00:00.000Z"
  },
  "error": null
}
Carteira
Base: https://api.zorinpay.com/v1/wallet
GET/walletwallet.read

Resumo da carteira (saldo, moeda).

Query: currency?

Headers

Authorization: Bearer <sua_api_key>

Campos da requisição

CampoTipoObrigatórioDescrição
currencystringNãoMoeda da carteira a consultar (ex.: BRL). Padrão: BRL.

Campos da resposta (data)

CampoTipoObrigatórioDescrição
availableBalancenumberSimSaldo disponível em centavos.
lockedBalancenumberSimSaldo bloqueado/em liberação em centavos.
currencystringSimMoeda da carteira (ex.: BRL).

Respostas

Status: 200 OK

{
  "data": {
    "availableBalance": 150000,
    "lockedBalance": 25000,
    "currency": "BRL"
  },
  "error": null
}
GET/wallet/balancewallet.read

Saldo detalhado por moeda.

Query: currency?

Headers

Authorization: Bearer <sua_api_key>

Campos da requisição

CampoTipoObrigatórioDescrição
currencystringNãoMoeda da carteira a consultar (ex.: BRL). Padrão: BRL.

Campos da resposta (data)

CampoTipoObrigatórioDescrição
availableBalancenumberSimSaldo disponível em centavos.
lockedBalancenumberSimSaldo bloqueado/em liberação em centavos.
totalBalancenumberSimSaldo total (disponível + bloqueado) em centavos.
currencystringSimMoeda da carteira (ex.: BRL).

Respostas

Status: 200 OK

{
  "data": {
    "availableBalance": 150000,
    "lockedBalance": 25000,
    "totalBalance": 175000,
    "currency": "BRL"
  },
  "error": null
}
GET/wallet/releaseswallet.read

Lista de liberações de saldo.

Query: currency?

Headers

Authorization: Bearer <sua_api_key>

Campos da requisição

CampoTipoObrigatórioDescrição
currencystringNãoMoeda da carteira a consultar (ex.: BRL). Padrão: BRL.

Campos da resposta (data)

CampoTipoObrigatórioDescrição
releases[].amountnumberSimValor a ser liberado em centavos.
releases[].releaseAtstringSimData/hora da liberação do saldo (ISO 8601).
releases[].billingIdstringSimIdentificador da cobrança que originou a liberação.

Respostas

Status: 200 OK

{
  "data": {
    "releases": [
      {
        "amount": 10000,
        "releaseAt": "2025-01-16T10:00:00.000Z",
        "billingId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
      }
    ]
  },
  "error": null
}
GET/wallet/historywallet.read

Histórico de movimentações.

Query: page?, limit?

Headers

Authorization: Bearer <sua_api_key>

Campos da requisição

CampoTipoObrigatórioDescrição
pagenumberNãoNúmero da página (começa em 1).
limitnumberNãoQuantidade de itens por página.

Campos da resposta (data)

CampoTipoObrigatórioDescrição
transactions[].idstringSimIdentificador da movimentação.
transactions[].typeenumSimTipo da movimentação (ex.: CREDIT, DEBIT).
transactions[].amountnumberSimValor da movimentação em centavos.
transactions[].descriptionstringSimDescrição da movimentação.
transactions[].createdAtstringSimData/hora da movimentação (ISO 8601).
totalnumberSimTotal de movimentações encontradas.
limitnumberSimItens por página aplicado.
pagenumberSimPágina atual.

Respostas

Status: 200 OK

{
  "data": {
    "transactions": [
      {
        "id": "c4d5e6f7-a8b9-0123-cdef-456789012345",
        "type": "CREDIT",
        "amount": 10000,
        "description": "Pagamento recebido",
        "createdAt": "2025-01-15T10:05:00.000Z"
      }
    ],
    "total": 1,
    "limit": 20,
    "page": 1
  },
  "error": null
}
GET/wallet/statementwallet.read

Extrato detalhado.

Query: page?, limit?

Headers

Authorization: Bearer <sua_api_key>

Campos da requisição

CampoTipoObrigatórioDescrição
pagenumberNãoNúmero da página (começa em 1).
limitnumberNãoQuantidade de itens por página.

Campos da resposta (data)

CampoTipoObrigatórioDescrição
entries[].idstringSimIdentificador do lançamento.
entries[].typeenumSimTipo do lançamento (ex.: CREDIT, DEBIT).
entries[].amountnumberSimValor do lançamento em centavos.
entries[].balanceAfternumberSimSaldo resultante após o lançamento em centavos.
entries[].descriptionstringSimDescrição do lançamento.
entries[].createdAtstringSimData/hora do lançamento (ISO 8601).
totalnumberSimTotal de lançamentos encontrados.
limitnumberSimItens por página aplicado.
pagenumberSimPágina atual.

Respostas

Status: 200 OK

{
  "data": {
    "entries": [
      {
        "id": "d5e6f7a8-b9c0-1234-def5-678901234567",
        "type": "CREDIT",
        "amount": 10000,
        "balanceAfter": 160000,
        "description": "Pagamento recebido",
        "createdAt": "2025-01-15T10:05:00.000Z"
      }
    ],
    "total": 1,
    "limit": 20,
    "page": 1
  },
  "error": null
}
Saques
Base: https://api.zorinpay.com/v1/withdrawals
POST/withdrawalswithdrawal.createIdempotency-Key

Cria um saque. Não permitido em devMode.

Headers

Authorization: Bearer <sua_api_key>
Content-Type: application/json
Idempotency-Key: <uuid> (recomendado)

Body (JSON)

{
  "amount": 50000,
  "pixKey": "[email protected]",
  "pixKeyType": "EMAIL",
  "externalId": "saque-001"
}

Campos da requisição

CampoTipoObrigatórioDescrição
amountnumberSimValor do saque em centavos (ex.: 50000 = R$ 500,00).
pixKeystringSimChave PIX de destino do saque.
pixKeyTypeenumSimTipo da chave PIX (ex.: EMAIL, CPF, CNPJ, PHONE, EVP).
externalIdstringNãoIdentificador único do saque no seu sistema.
metadataobjectNãoObjeto livre de dados adicionais.

Campos da resposta (data)

CampoTipoObrigatórioDescrição
idstringSimIdentificador do saque gerado pela Zorinpay.
amountnumberSimValor do saque em centavos.
statusenumSimStatus do saque (ex.: PROCESSING, COMPLETED, FAILED).
pixKeystringSimChave PIX de destino do saque.
pixKeyTypeenumSimTipo da chave PIX.
externalIdstring | nullNãoO externalId informado na criação, se houver.
createdAtstringSimData/hora de criação (ISO 8601).
updatedAtstringSimData/hora da última atualização (ISO 8601).

Respostas

Status: 201 Created

{
  "data": {
    "id": "7a8b9c0d-1e2f-3456-789a-bcdef0123456",
    "amount": 50000,
    "status": "PROCESSING",
    "pixKey": "[email protected]",
    "pixKeyType": "EMAIL",
    "externalId": "saque-001",
    "createdAt": "2025-01-15T12:00:00.000Z",
    "updatedAt": "2025-01-15T12:00:00.000Z"
  },
  "error": null
}

Status: 400 Bad Request

{
  "statusCode": 400,
  "message": "Saques não são permitidos em modo de teste",
  "error": "Bad Request"
}
GET/withdrawalswithdrawal.list

Lista saques.

Query: page?, limit?

Headers

Authorization: Bearer <sua_api_key>

Campos da requisição

CampoTipoObrigatórioDescrição
pagenumberNãoNúmero da página (começa em 1).
limitnumberNãoQuantidade de itens por página.

Campos da resposta (data)

CampoTipoObrigatórioDescrição
withdrawals[].idstringSimIdentificador do saque.
withdrawals[].amountnumberSimValor do saque em centavos.
withdrawals[].statusenumSimStatus do saque (ex.: PROCESSING, COMPLETED, FAILED).
withdrawals[].pixKeystringSimChave PIX de destino do saque.
withdrawals[].pixKeyTypeenumSimTipo da chave PIX.
withdrawals[].createdAtstringSimData/hora de criação (ISO 8601).
withdrawals[].updatedAtstringSimData/hora da última atualização (ISO 8601).
totalnumberSimTotal de saques encontrados.
limitnumberSimItens por página aplicado.
pagenumberSimPágina atual.

Respostas

Status: 200 OK

{
  "data": {
    "withdrawals": [
      {
        "id": "7a8b9c0d-1e2f-3456-789a-bcdef0123456",
        "amount": 50000,
        "status": "COMPLETED",
        "pixKey": "[email protected]",
        "pixKeyType": "EMAIL",
        "createdAt": "2025-01-15T12:00:00.000Z",
        "updatedAt": "2025-01-15T12:01:00.000Z"
      }
    ],
    "total": 1,
    "limit": 20,
    "page": 1
  },
  "error": null
}
GET/withdrawals/:idwithdrawal.read

Consulta um saque pelo ID.

Headers

Authorization: Bearer <sua_api_key>

Campos da requisição

CampoTipoObrigatórioDescrição
idstringSimID do saque (parâmetro de URL).

Campos da resposta (data)

CampoTipoObrigatórioDescrição
idstringSimIdentificador do saque.
amountnumberSimValor do saque em centavos.
statusenumSimStatus do saque (ex.: PROCESSING, COMPLETED, FAILED).
pixKeystringSimChave PIX de destino do saque.
pixKeyTypeenumSimTipo da chave PIX.
externalIdstring | nullNãoO externalId informado na criação, se houver.
e2eIdstring | nullNãoIdentificador end-to-end da transação PIX (presente quando concluído).
clientNamestring | nullNãoNome de quem recebeu o valor.
clientDocumentstring | nullNãoDocumento (CPF/CNPJ) de quem recebeu o valor.
metadataobject | nullNãoMetadados informados na criação, se houver.
createdAtstringSimData/hora de criação (ISO 8601).
updatedAtstringSimData/hora da última atualização (ISO 8601).

Respostas

Status: 200 OK

{
  "data": {
    "id": "7a8b9c0d-1e2f-3456-789a-bcdef0123456",
    "amount": 50000,
    "status": "COMPLETED",
    "pixKey": "[email protected]",
    "pixKeyType": "EMAIL",
    "externalId": "saque-001",
    "e2eId": "E12345678202401151201TESTPIXBR01",
    "clientName": "João da Silva",
    "clientDocument": "12345678900",
    "metadata": null,
    "createdAt": "2025-01-15T12:00:00.000Z",
    "updatedAt": "2025-01-15T12:01:00.000Z"
  },
  "error": null
}

Status: 404 Not Found

{
  "statusCode": 404,
  "message": "Saque não encontrado",
  "error": "Not Found"
}
MED (infrações PIX)
Base: https://api.zorinpay.com/v1/meds
GET/medsmed.list

Lista infrações MED (Mecanismo Especial de Devolução) do titular da API Key, com paginação por offset/limit.

Query: limit? (padrão 50), offset? (padrão 0), status? (ex.: WAITING_PSP, DEFENDED)

Headers

Authorization: Bearer <sua_api_key>

Campos da requisição

CampoTipoObrigatórioDescrição
limitnumberNãoQuantidade de itens por página (padrão 50).
offsetnumberNãoDeslocamento de paginação (padrão 0).
statusstringNãoFiltra por status da infração (ex.: WAITING_PSP, DEFENDED).

Campos da resposta (data)

CampoTipoObrigatórioDescrição
data[].idstringSimIdentificador da infração MED.
data[].userIdstringSimIdentificador do titular da conta.
data[].externalIdstring | nullNãoIdentificador da infração no provedor PIX.
data[].transactionIdstring | nullNãoIdentificador da transação relacionada.
data[].billingIdstring | nullNãoIdentificador da cobrança relacionada.
data[].accountIdnumber | nullNãoIdentificador da conta no provedor.
data[].typeenumSimTipo da infração (ex.: FRAUD).
data[].reportedBystring | nullNãoParticipante que reportou a infração.
data[].reportDetailsstring | nullNãoDetalhes do relato do pagador.
data[].statusenumSimStatus da infração (ex.: WAITING_PSP, DEFENDED, CLOSED).
data[].debitParticipantstring | nullNãoParticipante de débito.
data[].creditParticipantstring | nullNãoParticipante de crédito.
data[].analysisResultstring | nullNãoResultado da análise da infração.
data[].analysisDetailsstring | nullNãoDetalhes da análise da infração.
data[].payerNamestring | nullNãoNome do pagador.
data[].payerDocumentstring | nullNãoDocumento do pagador (mascarado).
data[].msgEndToEndIdstring | nullNãoendToEndId da transação PIX.
data[].fraudTypestring | nullNãoTipo de fraude, quando aplicável.
data[].contactEmailstring | nullNãoE-mail de contato relacionado à infração.
data[].contactPhonestring | nullNãoTelefone de contato relacionado à infração.
data[].infractionAmountnumberSimValor da infração em centavos.
data[].createdAtstringSimData/hora de criação (ISO 8601).
data[].updatedAtstringSimData/hora da última atualização (ISO 8601).
data[].defensesobject[]SimDefesas enviadas para a infração.
meta.totalnumberSimTotal de infrações encontradas.
meta.pagenumberSimPágina atual.
meta.limitnumberSimItens por página aplicado.
meta.totalPagesnumberSimTotal de páginas disponíveis.

Respostas

Status: 200 OK

{
  "data": [
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "userId": "user-uuid",
      "externalId": "ext-123",
      "transactionId": "tx-uuid",
      "billingId": "billing-uuid",
      "accountId": 987654,
      "type": "FRAUD",
      "reportedBy": "Participante XYZ",
      "reportDetails": "Relato do pagador",
      "status": "WAITING_PSP",
      "debitParticipant": null,
      "creditParticipant": null,
      "analysisResult": null,
      "analysisDetails": null,
      "payerName": "Maria Pagadora",
      "payerDocument": "***",
      "msgEndToEndId": "E123456782024...",
      "fraudType": null,
      "contactEmail": null,
      "contactPhone": null,
      "infractionAmount": 10050,
      "createdAt": "2025-01-15T10:00:00.000Z",
      "updatedAt": "2025-01-15T10:00:00.000Z",
      "defenses": []
    }
  ],
  "meta": {
    "total": 1,
    "page": 1,
    "limit": 50,
    "totalPages": 1
  }
}
GET/meds/:idmed.read

Retorna o detalhe de uma infração MED pelo ID (apenas se pertencer à sua conta).

Headers

Authorization: Bearer <sua_api_key>

Campos da requisição

CampoTipoObrigatórioDescrição
idstringSimID da infração MED (parâmetro de URL).

Campos da resposta (data)

CampoTipoObrigatórioDescrição
idstringSimIdentificador da infração MED.
userIdstringSimIdentificador do titular da conta.
externalIdstring | nullNãoIdentificador da infração no provedor PIX.
transactionIdstring | nullNãoIdentificador da transação relacionada.
billingIdstring | nullNãoIdentificador da cobrança relacionada.
accountIdnumber | nullNãoIdentificador da conta no provedor.
typeenumSimTipo da infração (ex.: FRAUD).
statusenumSimStatus da infração (ex.: WAITING_PSP, DEFENDED, CLOSED).
infractionAmountnumberSimValor da infração em centavos.
createdAtstringSimData/hora de criação (ISO 8601).
updatedAtstringSimData/hora da última atualização (ISO 8601).
defensesobject[]SimDefesas enviadas para a infração.

Respostas

Status: 200 OK

{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "userId": "user-uuid",
  "externalId": "ext-123",
  "transactionId": "tx-uuid",
  "billingId": "billing-uuid",
  "accountId": 987654,
  "type": "FRAUD",
  "status": "WAITING_PSP",
  "infractionAmount": 10050,
  "createdAt": "2025-01-15T10:00:00.000Z",
  "updatedAt": "2025-01-15T10:00:00.000Z",
  "defenses": []
}

Status: 404 Not Found

{
  "statusCode": 404,
  "message": "Infração não encontrada",
  "error": "Not Found"
}
POST/meds/:id/defensemed.respond

Envia defesa à adquirente. Exige infração em status WAITING_PSP, sem defesa já enviada. O corpo usa URLs públicas em proofs (1 a 10), como no dashboard.

Headers

Authorization: Bearer <sua_api_key>
Content-Type: application/json

Body (JSON)

{
  "analise": "rejeitado",
  "justificativa": "O serviço foi entregue conforme combinado com o cliente.",
  "proofs": [
    "https://exemplo.com/comprovante-entrega.pdf"
  ]
}

Campos da requisição

CampoTipoObrigatórioDescrição
idstringSimID da infração MED a defender (parâmetro de URL).
analiseenumSimPosição da defesa: "rejeitado" (contesta) ou "aceito" (aceita a infração).
justificativastringSimTexto da justificativa da defesa (mínimo 10 caracteres).
proofsstring[]SimLista de URLs públicas das provas (1 a 10).
proofs[]stringSimURL pública de um documento de prova.

Campos da resposta (data)

CampoTipoObrigatórioDescrição
infraction.idstringSimIdentificador da infração.
infraction.statusenumSimNovo status da infração (ex.: DEFENDED).
infraction.infractionAmountnumberSimValor da infração em centavos.
infraction.updatedAtstringSimData/hora da última atualização da infração (ISO 8601).
defense.idstringSimIdentificador da defesa criada.
defense.infractionIdstringSimIdentificador da infração defendida.
defense.externalIdstring | nullNãoIdentificador da defesa no provedor PIX.
defense.statusenumSimStatus da defesa (ex.: DEFENDED).
defense.defensestringSimTexto da justificativa enviada.
defense.attachmentsobject[]SimAnexos da defesa.
defense.attachments[].urlstringSimURL do anexo enviado.
defense.attachments[].fileNamestringSimNome do anexo.
defense.attachments[].mimeTypestringSimTipo do anexo (ex.: url).
defense.createdAtstringSimData/hora de criação da defesa (ISO 8601).
defense.updatedAtstringSimData/hora da última atualização da defesa (ISO 8601).

Respostas

Status: 201 Created

{
  "infraction": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "status": "DEFENDED",
    "infractionAmount": 10050,
    "updatedAt": "2025-01-15T11:00:00.000Z"
  },
  "defense": {
    "id": "defense-uuid",
    "infractionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "externalId": "12345",
    "status": "DEFENDED",
    "defense": "O serviço foi entregue conforme combinado com o cliente.",
    "attachments": [
      { "url": "https://exemplo.com/comprovante-entrega.pdf", "fileName": "prova-1", "mimeType": "url" }
    ],
    "createdAt": "2025-01-15T11:00:00.000Z",
    "updatedAt": "2025-01-15T11:00:00.000Z"
  }
}

Status: 400 Bad Request

{
  "statusCode": 400,
  "message": "Não é possível responder infração com status \"CLOSED\". Apenas infrações com status WAITING_PSP podem ser respondidas.",
  "error": "Bad Request"
}

Status: 409 Conflict

{
  "statusCode": 409,
  "message": "Já existe uma defesa enviada para esta infração",
  "error": "Conflict"
}
PIX QR Code
Base: https://api.zorinpay.com/v1/pixQrCode
POST/pixQrCodepixqrcode.createIdempotency-Key

Gera um QR Code PIX para pagamento. No objeto customer, apenas name e taxId são obrigatórios; cellphone e email são opcionais.

Headers

Authorization: Bearer <sua_api_key>
Content-Type: application/json
Idempotency-Key: <uuid> (recomendado)

Body (JSON)

{
  "amount": 5000,
  "customer": {
    "name": "João Silva",
    "cellphone": "+5511999999999",
    "email": "[email protected]",
    "taxId": "12345678900"
  },
  "expiresIn": 3600,
  "description": "Pagamento de pedido",
  "externalId": "pix-001"
}

Campos da requisição

CampoTipoObrigatórioDescrição
amountnumberSimValor da cobrança em centavos (ex.: 5000 = R$ 50,00).
customerobjectSimDados do pagador da cobrança.
customer.namestringSimNome completo do pagador.
customer.taxIdstringSimCPF ou CNPJ do pagador (somente dígitos).
customer.cellphonestringNãoTelefone do pagador no formato E.164 (ex.: +5511999999999).
customer.emailstringNãoE-mail do pagador.
expiresInnumberNãoTempo de expiração do QR Code em segundos. Padrão: 3 dias.
descriptionstringNãoDescrição livre da cobrança, exibida no extrato.
externalIdstringNãoIdentificador único da cobrança no seu sistema (idempotência por usuário).
metadataobjectNãoObjeto livre de dados adicionais, devolvido nos webhooks e na consulta.

Campos da resposta (data)

CampoTipoObrigatórioDescrição
idstringSimIdentificador da cobrança (billingId) gerado pela Zorinpay.
amountnumberSimValor da cobrança em centavos.
statusstringSimStatus atual da cobrança (ex.: PENDING, PAID, EXPIRED).
devModebooleanSimIndica se a cobrança foi criada em modo de testes (sandbox).
copyPastestringSimCódigo PIX copia e cola (BR Code) para pagamento.
qrCodeBase64stringSimImagem do QR Code em base64 (data URI) para exibição.
platformFeenumberSimTaxa da plataforma em centavos aplicada nesta cobrança.
externalIdstring | nullNãoO externalId informado na criação, se houver.
metadataobject | nullNãoO metadata informado na criação, se houver.
createdAtstringSimData/hora de criação (ISO 8601).
updatedAtstringSimData/hora da última atualização (ISO 8601).
expiresAtstringSimData/hora de expiração do QR Code (ISO 8601).

Respostas

Status: 201 Created

{
  "data": {
    "id": "8b9c0d1e-2f3a-4567-89ab-cdef01234567",
    "amount": 5000,
    "status": "PENDING",
    "devMode": false,
    "copyPaste": "00020126360014BR.GOV.BCB.PIX...",
    "qrCodeBase64": "data:image/png;base64,...",
    "platformFee": 49,
    "externalId": "pix-001",
    "metadata": null,
    "createdAt": "2025-01-15T11:00:00.000Z",
    "updatedAt": "2025-01-15T11:00:00.000Z",
    "expiresAt": "2025-01-15T12:00:00.000Z"
  },
  "error": null
}

Status: 400 Bad Request

{
  "statusCode": 400,
  "message": ["Valor é obrigatório", "Dados do cliente são obrigatórios"],
  "error": "Bad Request"
}
POST/pixQrCode-splitpixqrcode.createIdempotency-Key

Gera QR Code PIX com split de pagamento entre múltiplos recebedores. No objeto customer, apenas name e taxId são obrigatórios; cellphone e email são opcionais.

Headers

Authorization: Bearer <sua_api_key>
Content-Type: application/json
Idempotency-Key: <uuid> (recomendado)

Body (JSON)

{
  "amount": 15000,
  "splits": [
    {
      "recipientEmail": "[email protected]",
      "type": "percentage",
      "value": 40
    }
  ],
  "customer": {
    "name": "Maria Santos",
    "cellphone": "+5511988888888",
    "email": "[email protected]",
    "taxId": "98765432100"
  },
  "description": "Pagamento com split",
  "expiresIn": 3600,
  "metadata": { "ref": "abc-123" }
}

Campos da requisição

CampoTipoObrigatórioDescrição
amountnumberSimValor da cobrança em centavos (ex.: 15000 = R$ 150,00).
splitsobject[]SimRegras de divisão do pagamento entre recebedores.
splits[].recipientEmailstringSimE-mail do recebedor do split (deve ser uma conta Zorinpay).
splits[].typeenumSimTipo do split: "percentage" (percentual) ou "fixed" (valor fixo).
splits[].valuenumberSimValor do split: percentual (ex.: 40) ou valor fixo em centavos.
customerobjectSimDados do pagador da cobrança.
customer.namestringSimNome completo do pagador.
customer.taxIdstringSimCPF ou CNPJ do pagador (somente dígitos).
customer.cellphonestringNãoTelefone do pagador no formato E.164 (ex.: +5511999999999).
customer.emailstringNãoE-mail do pagador.
descriptionstringNãoDescrição livre da cobrança, exibida no extrato.
externalIdstringNãoIdentificador único da cobrança no seu sistema (idempotência por usuário).
metadataobjectNãoObjeto livre de dados adicionais, devolvido nos webhooks e na consulta.
expiresInnumberNãoTempo de expiração do QR Code em segundos. Padrão: 3 dias.

Campos da resposta (data)

CampoTipoObrigatórioDescrição
idstringSimIdentificador da cobrança (billingId) gerado pela Zorinpay.
amountnumberSimValor da cobrança em centavos.
statusstringSimStatus atual da cobrança (ex.: PENDING, PAID, EXPIRED).
devModebooleanSimIndica se a cobrança foi criada em modo de testes (sandbox).
copyPastestringSimCódigo PIX copia e cola (BR Code) para pagamento.
qrCodeBase64stringSimImagem do QR Code em base64 (data URI) para exibição.
platformFeenumberSimTaxa da plataforma em centavos aplicada nesta cobrança.
externalIdstring | nullNãoO externalId informado na criação, se houver.
metadataobject | nullNãoO metadata informado na criação, se houver.
createdAtstringSimData/hora de criação (ISO 8601).
updatedAtstringSimData/hora da última atualização (ISO 8601).
expiresAtstringSimData/hora de expiração do QR Code (ISO 8601).

Respostas

Status: 201 Created

{
  "data": {
    "id": "f1a2b3c4-d5e6-7890-abcd-123456789012",
    "amount": 15000,
    "status": "PENDING",
    "devMode": false,
    "copyPaste": "00020126...",
    "qrCodeBase64": "data:image/png;base64,...",
    "platformFee": 300,
    "externalId": null,
    "metadata": { "ref": "abc-123" },
    "createdAt": "2025-01-15T14:00:00.000Z",
    "updatedAt": "2025-01-15T14:00:00.000Z",
    "expiresAt": "2025-01-15T15:00:00.000Z"
  },
  "error": null
}

Status: 404 Not Found

{
  "statusCode": 404,
  "message": "Recebedor do split não encontrado: [email protected]",
  "error": "Not Found"
}
GET/pixQrCode/check/:idpixqrcode.check

Verifica status do pagamento PIX (billingId).

Headers

Authorization: Bearer <sua_api_key>

Campos da requisição

CampoTipoObrigatórioDescrição
idstringSimID da cobrança PIX (billingId) a consultar (parâmetro de URL).

Campos da resposta (data)

CampoTipoObrigatórioDescrição
idstringSimIdentificador da cobrança (billingId).
statusstringSimStatus atual da cobrança (ex.: PENDING, PAID, EXPIRED).
amountnumberSimValor da cobrança em centavos.
e2eIdstring | nullNãoIdentificador end-to-end da transação PIX, quando paga.
clientNamestring | nullNãoNome do pagador (capturado via adquirente), quando pago.
clientDocumentstring | nullNãoDocumento (CPF/CNPJ) do pagador, quando pago.
paidAtstring | nullNãoData/hora do pagamento (ISO 8601), se paga.

Respostas

Status: 200 OK

{
  "data": {
    "id": "8b9c0d1e-2f3a-4567-89ab-cdef01234567",
    "status": "PAID",
    "amount": 5000,
    "e2eId": "E12345678202401151105TESTPIXBR01",
    "clientName": "João Silva",
    "clientDocument": "12345678900",
    "paidAt": "2025-01-15T11:05:00.000Z"
  },
  "error": null
}
POST/pixQrCode/:id/refundpixqrcode.refund

Reembolsa um PIX QR Code já pago (disponível apenas para cobranças elegíveis a reembolso PIX). O valor bruto é debitado da carteira do cliente e devolvido ao pagador via PIX. A taxa de processamento NÃO é restituída — o cliente assume esse custo. Dispara o webhook pixqrcode.refunded.

Headers

Authorization: Bearer <sua_api_key>
Content-Type: application/json

Campos da requisição

CampoTipoObrigatórioDescrição
idstringSimID do PIX QR Code (billingId) a ser reembolsado (parâmetro de URL).
reasonstringNãoMotivo do reembolso (opcional), para registro.

Campos da resposta (data)

CampoTipoObrigatórioDescrição
billingIdstringSimIdentificador da cobrança reembolsada.
statusenumSimNovo status da cobrança (REFUNDED).
refundIdstringSimIdentificador do reembolso PIX (endToEndId).
refundedAtstringSimData/hora do reembolso (ISO 8601).
amountRefundednumberSimValor reembolsado em centavos.

Respostas

Status: 200 OK

{
  "billingId": "8b9c0d1e-2f3a-4567-89ab-cdef01234567",
  "status": "REFUNDED",
  "refundId": "E18236120202610061226...",
  "refundedAt": "2026-05-13T17:25:31.000Z",
  "amountRefunded": 5000
}

Status: 400 Bad Request

{
  "statusCode": 400,
  "message": "Este recurso não é um PIX QR Code. Use POST /v1/billings/:id/refund.",
  "error": "Bad Request"
}

Status: 403 Forbidden

{
  "statusCode": 403,
  "message": "Você não tem permissão para reembolsar esta cobrança",
  "error": "Forbidden"
}

Status: 404 Not Found

{
  "statusCode": 404,
  "message": "Cobrança não encontrada",
  "error": "Not Found"
}
Cupons
Base: https://api.zorinpay.com/v1/coupons
POST/couponscoupon.createIdempotency-Key

Cria um cupom de desconto.

Headers

Authorization: Bearer <sua_api_key>
Content-Type: application/json
Idempotency-Key: <uuid> (recomendado)

Body (JSON)

{
  "data": {
    "code": "PROMO10",
    "discountKind": "PERCENTAGE",
    "discount": 10,
    "notes": "Promo de lançamento",
    "maxRedeems": 100
  }
}

Campos da requisição

CampoTipoObrigatórioDescrição
dataobjectSimObjeto que envolve os dados do cupom.
data.codestringSimCódigo do cupom; também é usado como identificador (id).
data.discountKindenumSimTipo do desconto: PERCENTAGE (percentual) ou FIXED (valor fixo).
data.discountnumberSimValor do desconto: percentual de 0 a 100 (PERCENTAGE) ou valor fixo em centavos (FIXED).
data.notesstringNãoObservações livres sobre o cupom.
data.maxRedeemsnumberNãoNúmero máximo de resgates. Padrão: -1 (ilimitado).
data.metadataobjectNãoObjeto livre de dados adicionais.

Campos da resposta (data)

CampoTipoObrigatórioDescrição
idstringSimIdentificador do cupom (igual ao code informado).
discountKindenumSimTipo do desconto (PERCENTAGE ou FIXED).
discountnumberSimValor do desconto (percentual ou valor fixo em centavos).
statusenumSimStatus do cupom (ex.: ACTIVE).
createdAtstringSimData/hora de criação (ISO 8601).
updatedAtstringSimData/hora da última atualização (ISO 8601).
notesstring | nullNãoObservações do cupom, se houver.
maxRedeemsnumberSimNúmero máximo de resgates (-1 = ilimitado).
redeemsCountnumberSimQuantidade de resgates já realizados.
devModebooleanSimIndica se o cupom é de modo de testes (sandbox).
metadataobject | nullNãoMetadata informado na criação, se houver.

Respostas

Status: 201 Created

{
  "data": {
    "id": "PROMO10",
    "discountKind": "PERCENTAGE",
    "discount": 10,
    "status": "ACTIVE",
    "createdAt": "2025-01-15T10:00:00.000Z",
    "updatedAt": "2025-01-15T10:00:00.000Z",
    "notes": "Promo de lançamento",
    "maxRedeems": 100,
    "redeemsCount": 0,
    "devMode": false,
    "metadata": null
  },
  "error": null
}
GET/couponscoupon.list

Lista os cupons da conta, com paginação por limit/offset.

Query: limit? (padrão 50), offset? (padrão 0)

Headers

Authorization: Bearer <sua_api_key>

Campos da requisição

CampoTipoObrigatórioDescrição
limitnumberNãoQuantidade de itens por página (padrão 50).
offsetnumberNãoDeslocamento de paginação (padrão 0).

Campos da resposta (data)

CampoTipoObrigatórioDescrição
data[].idstringSimIdentificador do cupom (igual ao code).
data[].discountKindenumSimTipo do desconto (PERCENTAGE ou FIXED).
data[].discountnumberSimValor do desconto (percentual ou valor fixo em centavos).
data[].statusenumSimStatus do cupom (ex.: ACTIVE).
data[].createdAtstringSimData/hora de criação (ISO 8601).
data[].updatedAtstringSimData/hora da última atualização (ISO 8601).
data[].notesstring | nullNãoObservações do cupom, se houver.
data[].maxRedeemsnumberSimNúmero máximo de resgates (-1 = ilimitado).
data[].redeemsCountnumberSimQuantidade de resgates já realizados.
data[].devModebooleanSimIndica se o cupom é de modo de testes (sandbox).
data[].metadataobject | nullNãoMetadata do cupom, se houver.

Respostas

Status: 200 OK

{
  "data": [
    {
      "id": "PROMO10",
      "discountKind": "PERCENTAGE",
      "discount": 10,
      "status": "ACTIVE",
      "createdAt": "2025-01-15T10:00:00.000Z",
      "updatedAt": "2025-01-15T10:00:00.000Z",
      "notes": "Promo de lançamento",
      "maxRedeems": 100,
      "redeemsCount": 5,
      "devMode": false,
      "metadata": null
    }
  ],
  "error": null
}
Taxas
Base: https://api.zorinpay.com/v1/fees
GET/feesfees.read

Retorna a configuração de taxas da conta. A alteração de taxas é restrita ao admin.

Headers

Authorization: Bearer <sua_api_key>

Campos da resposta (data)

CampoTipoObrigatórioDescrição
fees[].typeenumSimTipo da taxa (ex.: PIX_CASH_IN, PIX_CASH_OUT).
fees[].percentagenumberSimPercentual aplicado sobre o valor da transação (ex.: 1.99 = 1,99%).
fees[].fixednumberSimValor fixo cobrado por transação em centavos.

Respostas

Status: 200 OK

{
  "data": {
    "fees": [
      {
        "type": "PIX_CASH_IN",
        "percentage": 1.99,
        "fixed": 0
      },
      {
        "type": "PIX_CASH_OUT",
        "percentage": 0,
        "fixed": 200
      }
    ]
  },
  "error": null
}

Exemplo de requisição

Exemplo completo para POST /customer/create (criar cliente): requisição com headers, body e resposta da API.

Requisição

Método e URL: POST https://api.zorinpay.com/v1/customer/create

Headers obrigatórios:

  • Authorization: Bearer <sua_api_key>
  • Content-Type: application/json
  • Idempotency-Key: <uuid> (recomendado em criações)

Body (JSON):

{
  "name": "João Silva",
  "cellphone": "+5511999999999",
  "email": "[email protected]",
  "taxId": "12345678900"
}
curl -X POST https://api.zorinpay.com/v1/customer/create \
  -H "Authorization: Bearer sk_test_sua_chave_aqui" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
  -d '{"name":"João Silva","cellphone":"+5511999999999","email":"[email protected]","taxId":"12345678900"}'

Resposta (sucesso)

Status: 201 Created

{
  "data": {
    "id": "d290f1ee-6c54-4b01-90e6-d701748f0851",
    "metadata": {
      "name": "João Silva",
      "cellphone": "+5511999999999",
      "email": "[email protected]",
      "taxId": "12345678900"
    }
  },
  "error": null
}

Resposta (erro — ex.: API Key inválida)

Status: 401 Unauthorized

{
  "statusCode": 401,
  "message": "Chave API não existe",
  "error": "Unauthorized"
}

Webhooks

Webhooks permitem que sua aplicação receba notificações em tempo real quando eventos ocorrem na sua conta (cobrança paga, saque concluído, cliente criado, etc.). Configure a URL de destino no Dashboard e escolha os eventos que deseja receber.

Para testar a integração, crie um webhook no Dashboard apontando para a URL do seu backend e aguarde eventos reais ou utilize ferramentas de teste como curl para simular chamadas. Todas as notificações incluem o header X-Webhook-Signature com assinatura HMAC-SHA256 hex.

Eventos disponíveis

Você pode assinar os seguintes eventos por webhook. Cada evento é enviado como POST para a URL configurada.

Cobranças (billing)

billing.createdbilling.updatedbilling.paidbilling.failedbilling.refundedbilling.cancelled

PIX QR Code (pixqrcode)

pixqrcode.createdpixqrcode.updatedpixqrcode.deletedpixqrcode.paidpixqrcode.failedpixqrcode.refundedpixqrcode.cancelled

Saques (withdraw)

withdraw.createdwithdraw.updatedwithdraw.donewithdraw.failed

Clientes (customer)

customer.createdcustomer.updatedcustomer.deleted

API Key (apiKey)

apiKey.createdapiKey.updatedapiKey.deleted

Usuário (user)

user.createduser.updated

MED (infrações PIX)

med.createdmed.updated

Formato do payload

Todo webhook segue o mesmo envelope. O campo data contém uma única chave por recurso: billing, pixqrcode, transaction, customer, apiKey, user ou med (infrações MED / PIX).

Em eventos pixqrcode.*, o objeto em data.pixqrcode pode incluir campos adicionais quando existirem na cobrança, por exemplo externalId, copyPaste (código PIX copia e cola) e qrCodeBase64.

  • id — identificador único do evento (use para idempotência)
  • event — tipo do evento (ex.: billing.paid, pixqrcode.created)
  • data — objeto com os dados do recurso afetado
  • devMode — indica se o evento ocorreu em ambiente de teste
  • createdAt — data/hora do disparo (ISO 8601)

Nos eventos billing.paid, pixqrcode.paid e withdraw.done, o recurso em data inclui e2eId (identificador end-to-end do PIX) quando o provedor informa esse valor; caso contrário vem null. Nos eventos billing.paid e pixqrcode.paid, o objeto payer traz o nome e o documento do pagador informados pela adquirente (ou null em cada campo quando não disponíveis); isso é distinto do customer da cobrança, quando existir.

Exemplos de payload por evento

Abaixo estão exemplos do payload enviado para cada tipo de evento. Use o campo data conforme o recurso: billing, pixqrcode, transaction (saques), customer, apiKey, user ou med.

Boas práticas

  • Responda com status 2xx o mais rápido possível; processe tarefas pesadas em background.
  • Use o campo id do evento para evitar processar o mesmo webhook mais de uma vez (idempotência).
  • Verifique devMode se precisar tratar eventos de teste de forma diferente.
  • Configure retentativas no Dashboard conforme a necessidade da sua aplicação.

Verificação de assinatura

Toda notificação enviada pelo ZorinPay inclui o header X-Webhook-Signature contendo a assinatura HMAC-SHA256 (hex) do body da requisição. Você deve verificar essa assinatura no seu endpoint para garantir que a notificação é legítima e não foi alterada em trânsito.

Como funciona

  1. Ao criar um webhook no Dashboard, você recebe um secret (exibido apenas uma vez). Guarde-o com segurança no seu servidor (ex.: variável de ambiente).
  2. A cada notificação, o ZorinPay gera um HMAC-SHA256 do body JSON usando o seu secret como chave e envia o resultado hexadecimal no header X-Webhook-Signature.
  3. No seu endpoint, recalcule o HMAC-SHA256 do body recebido usando o mesmo secret e compare com o valor do header. Se forem iguais, a requisição é autêntica.

Importante: Use comparação de tempo constante (timing-safe comparison) para evitar ataques de temporização. Nunca compare as strings diretamente com ===.

Exemplos de implementação

// Node.js (Express / Fastify / qualquer framework)
const crypto = require('crypto');

const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;
// ex.: "a1B2c3D4e5F6g7H8i9J0..."

function verifyWebhookSignature(rawBody, signatureHeader) {
  const expected = crypto
    .createHmac('sha256', WEBHOOK_SECRET)
    .update(rawBody, 'utf8')
    .digest('hex');

  // Comparação timing-safe para evitar ataques de temporização
  const a = Buffer.from(expected, 'utf8');
  const b = Buffer.from(signatureHeader, 'utf8');

  if (a.length !== b.length) return false;
  return crypto.timingSafeEqual(a, b);
}

// Exemplo com Express (use express.raw para obter o body como Buffer)
app.post('/webhooks', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-webhook-signature'];
  const rawBody = req.body.toString('utf8');

  if (!signature || !verifyWebhookSignature(rawBody, signature)) {
    return res.status(401).json({ error: 'Assinatura inválida' });
  }

  const payload = JSON.parse(rawBody);
  console.log('Evento recebido:', payload.event);
  // Processar o evento...

  res.status(200).json({ received: true });
});

Resumo dos headers

HeaderValorDescrição
Content-Typeapplication/jsonFormato do body
X-Webhook-SignatureHMAC-SHA256 (hex)Assinatura do body usando o secret do webhook. Compare com o HMAC que você calcular localmente.

Respostas de erro

A API retorna JSON com statusCode, message e opcionalmente error.

  • 401 Unauthorized — API Key ausente, inválida, revogada ou expirada.
  • 403 Forbidden — API Key válida mas sem o escopo necessário para a rota.
  • 400 Bad Request — Dados de entrada inválidos ou regra de negócio (ex.: saque em devMode).
  • 404 Not Found — Recurso não encontrado ou não pertence à sua conta.