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.
| Endpoint | Escopo | Operação |
|---|---|---|
| POST /v3/card/charges | cashin | Cobra um cartão em produção |
| POST /v3/card/charges/retrieve | read | Consulta uma cobrança em produção |
| POST /v3/sandbox/card/charges | cashin | Cobra um cartão de teste no sandbox |
| POST /v3/sandbox/card/charges/retrieve | read | Consulta 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
| Campo | Obrigatório | Regras |
|---|---|---|
| amount | sim | Reais com até 2 casas, em texto ("150.00") ou número; pelo menos o mínimo da conta |
| installments | não | 1 a 12 (padrão 1). Cada parcela tem de ser de pelo menos R$ 5,00 |
| description | sim | 1 a 255 caracteres; aparece no painel |
| customer | sim | {name, email, document, phone}: document é CPF ou CNPJ (com ou sem máscara) e phone é opcional |
| card | sim | {number, exp_month, exp_year, cvv, holder_name}. exp_year com 2 ou 4 dígitos |
| external_id | não | O id do pedido no seu sistema, até 100 caracteres. Volta na resposta e permite a consulta |
| notification_url | não | URL de webhook desta cobrança, com as mesmas regras do urlnoty de /v3/pix/qrcode |
| buyer_ip | sim | O 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
| status | O que fazer |
|---|---|
| paid | Aprovado e confirmado no adquirente. Pode entregar |
| declined | Recusado. decline_reason diz o tipo e message traz uma frase pronta para o comprador |
| pending | Em 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_ipa 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
| HTTP | error | Quando |
|---|---|---|
| 400 | VALIDATION_ERROR | Campo inválido. details.field diz qual. A mensagem nunca repete o cartão |
| 403 | KYC_REQUIRED | Conta sem a verificação aprovada |
| 403 | CARD_DISABLED | Cartão não liberado para a conta |
| 409 | IDEMPOTENCY_* | A mesma Idempotency-Key com outro corpo |
| 422 | CARD_3DS_REQUIRED | A conta exige 3DS: use as sessões de checkout |
| 422 | VALIDATION_ERROR | Cartão de teste em produção ou cartão real no sandbox |
| 429 | RATE_LIMITED | Limite de tentativas (veja acima) |
| 503 | ACQUIRER_UNAVAILABLE | Adquirente fora do ar; tente de novo ou ofereça PIX |