Quibly Pay
API v3

Cobrança de cartão (transparente)

O seu servidor envia o cartão do comprador e recebe o resultado na hora.

No checkout transparente, o comprador digita o cartão na SUA página e o SEU servidor envia o cartão para a Quibly Pay. A resposta é síncrona: paid, declined ou pending. Se você não quer tocar em dados de cartão, use as sessões de checkout: o comprador paga na página hospedada e o cartão nunca passa pelo seu servidor.

PCI DSS é responsabilidade sua. Com esta rota, o número do cartão, a validade e o CVV passam pelo seu servidor. Isso coloca o seu ambiente no escopo do PCI DSS: você responde pela segurança desses dados. Nunca grave o cartão (nem em log, fila, banco ou ferramenta de erro), use só HTTPS e não repita o CVV. Do lado da Quibly Pay, o cartão fica só em memória durante a cobrança, vai ao adquirente só por conexão cifrada (TLS) e nunca é gravado. Guardamos apenas a bandeira, os 6 primeiros e os 4 últimos dígitos.

EndpointEscopoOperação
POST /v3/card/chargescashinCobra um cartão em produção
POST /v3/card/charges/retrievereadConsulta uma cobrança em produção
POST /v3/sandbox/card/chargescashinCobra um cartão de teste no sandbox
POST /v3/sandbox/card/charges/retrievereadConsulta uma cobrança no sandbox

O nome é charges de propósito: na v3, pix/payment é saque. Estas rotas aceitam só application/json. client_id e client_secret vão no mesmo corpo, como nas outras rotas v3, e valem as mesmas regras de whitelist de IP e de ambiente.

Quem pode usar. Toda conta com a verificação (KYC) aprovada e o cartão liberado. Sem KYC, a resposta é 403 KYC_REQUIRED; sem cartão liberado, 403 CARD_DISABLED.

3DS. Se a sua conta exige 3DS ("Exigir 3DS" nas configurações de cartão do painel), esta rota responde 422 CARD_3DS_REQUIRED com a mensagem "3DS só no checkout hospedado" e não cobra nada. O 3DS precisa do navegador do comprador: use as sessões de checkout. No sandbox a resposta é a mesma, para você descobrir isso no teste.

Corpo da cobrança

CampoObrigatórioRegras
amountsimReais com até 2 casas, em texto ("150.00") ou número; pelo menos o mínimo da conta
installmentsnão1 a 12 (padrão 1). Cada parcela tem de ser de pelo menos R$ 5,00
descriptionsim1 a 255 caracteres; aparece no painel
customersim{name, email, document, phone}: document é CPF ou CNPJ (com ou sem máscara) e phone é opcional
cardsim{number, exp_month, exp_year, cvv, holder_name}. exp_year com 2 ou 4 dígitos
external_idnãoO id do pedido no seu sistema, até 100 caracteres. Volta na resposta e permite a consulta
notification_urlnãoURL de webhook desta cobrança, com as mesmas regras do urlnoty de /v3/pix/qrcode
buyer_ipsimO IP público do COMPRADOR (não o do seu servidor). Vai para o antifraude. IP interno (10.x, 192.168.x, 127.0.0.1) é recusado em produção

Campos fora desta tabela são ignorados (por exemplo, billing_address, que existiu na primeira versão desta página). Se o número do cartão desta cobrança aparecer em description, customer.name, customer.phone ou external_id, a cobrança volta 400 VALIDATION_ERROR sem repetir o valor. Outros números que parecem cartão em description e customer.name (um número de pedido, por exemplo) não recusam a cobrança: são gravados mascarados, e é assim que aparecem no painel, no e-mail do comprador e no webhook. Uma sequência que é inteira um número de cartão mantém os 6 primeiros e os 4 últimos dígitos (Cartão 4111.1111.1111.1111 vira Cartão 411111******1111); quando só um trecho dela passa na verificação de cartão, todos os dígitos viram * (Pedido 2025-000123-4567 vira Pedido ****-******-****).

curl -X POST https://api.quiblypay.com/v3/card/charges \
  -H 'content-type: application/json' \
  -H 'Idempotency-Key: pedido-981-tentativa-1' \
  -d '{
    "client_id": "SEU_CLIENT_ID",
    "client_secret": "SEU_CLIENT_SECRET",
    "amount": "150.00",
    "installments": 3,
    "description": "Pedido #981",
    "customer": {
      "name": "Maria Silva",
      "email": "maria@example.com",
      "document": "529.982.247-25",
      "phone": "11999990000"
    },
    "card": {
      "number": "4111111111111111",
      "exp_month": "12",
      "exp_year": "2030",
      "cvv": "123",
      "holder_name": "MARIA SILVA"
    },
    "external_id": "981",
    "notification_url": "https://loja.example.com/webhooks/quibly",
    "buyer_ip": "177.10.20.30"
  }'
{
  "statusCode": 200,
  "id": "e3c1f0a2b4d6e8f0a1b2c3d4e5f6a7b8c",
  "status": "paid",
  "amount": "150.00",
  "currency": "BRL",
  "installments": 3,
  "description": "Pedido #981",
  "external_id": "981",
  "card": { "brand": "visa", "last4": "1111" },
  "decline_reason": null,
  "message": null,
  "created_at": "2026-10-09T14:00:00.000Z",
  "paid_at": "2026-10-09T14:00:02.000Z"
}

Resultado

statusO que fazer
paidAprovado e confirmado no adquirente. Pode entregar
declinedRecusado. decline_reason diz o tipo e message traz uma frase pronta para o comprador
pendingEm análise no adquirente. Não entregue: espere o webhook transaction.paid ou consulte

Pela API, a cobrança vai a um único adquirente: uma recusa ou uma falha técnica não é reapresentada em outro. No checkout hospedado pode haver uma segunda tentativa automática.

decline_reason é soft (pode tentar de novo mais tarde), hard (peça outro cartão) ou technical (falha nossa ou do adquirente; tente de novo ou ofereça PIX). O motivo detalhado do banco emissor (saldo, CVV, cartão bloqueado) não volta na API, para não ajudar quem testa cartões roubados: ele aparece no painel, nas "Tentativas de cartão" da venda.

Duplicidade e Idempotency-Key

Envie Idempotency-Key (até 128 caracteres) em toda cobrança. Repetir a mesma chave com o mesmo corpo devolve a MESMA cobrança, sem cobrar de novo; a mesma chave com outro corpo devolve 409.

Sem a chave, o mesmo cartão com o mesmo valor e o mesmo external_id em até 10 minutos devolve a cobrança já feita (reenvio depois de timeout). Por isso mande external_id: dois pedidos diferentes do mesmo cartão e do mesmo valor, sem external_id, dentro de 10 minutos, viram UMA cobrança. Depois de uma recusa, uma nova tentativa com o mesmo external_id é uma cobrança nova.

Consulta

POST /v3/card/charges/retrieve recebe {"id": "..."} ou {"external_id": "..."} (só um dos dois) e devolve o mesmo objeto. Pelo external_id, vale a cobrança mais recente. Uma cobrança de outra conta ou do outro ambiente devolve 404. Depois de um estorno o status vira refunded.

Webhooks

A cobrança aprovada envia o mesmo transaction.paid das vendas de cartão do checkout: para a notification_url da cobrança e para os webhooks cadastrados no painel, com a mesma assinatura (veja Verificação). O transactionId do webhook é o id da resposta.

Limites contra card testing

  • até 5 tentativas com o mesmo cartão a cada 10 minutos;
  • até 10 cobranças por buyer_ip a cada 10 minutos, por conta;
  • até 60 cobranças por minuto por credencial e 120 por minuto por IP do seu servidor;
  • até 300 tentativas de cartão pela API por conta a cada 24 horas (em produção). Acima disso, use as sessões de checkout, que não entram nesse teto.

Passou do limite, a resposta é 429 RATE_LIMITED com details.retry_after em segundos. Mandar sempre o IP do seu servidor em buyer_ip faz todos os seus compradores dividirem o mesmo limite.

Sandbox

/v3/sandbox/card/charges com uma credencial SANDBOX aceita só os cartões de teste (4242 4242 4242 4242 aprovado, 4000 0000 0000 0002 recusado e os demais) e nunca fala com o adquirente. Um cartão real no sandbox, ou um cartão de teste em produção, devolve 422 VALIDATION_ERROR. As respostas do sandbox trazem mode: "sandbox".

Erros

HTTPerrorQuando
400VALIDATION_ERRORCampo inválido. details.field diz qual. A mensagem nunca repete o cartão
403KYC_REQUIREDConta sem a verificação aprovada
403CARD_DISABLEDCartão não liberado para a conta
409IDEMPOTENCY_*A mesma Idempotency-Key com outro corpo
422CARD_3DS_REQUIREDA conta exige 3DS: use as sessões de checkout
422VALIDATION_ERRORCartão de teste em produção ou cartão real no sandbox
429RATE_LIMITEDLimite de tentativas (veja acima)
503ACQUIRER_UNAVAILABLEAdquirente fora do ar; tente de novo ou ofereça PIX

On this page