Pular para o conteúdo principal

Receber por cartão

Há dois caminhos:

CaminhoPara quemO número do cartão passa pelo seu servidor?
Página hospedada (POST /charges com method: card)Todo mundoNão. Você manda o portador para a nossa página
Cartão cru (POST /charges/card-raw)Só conta liberada para isso, com certificação PCISim, e o escopo de PCI passa a ser seu

Comece pela página hospedada. É ela que mantém o seu escopo de PCI onde ele está.

Página hospedada​

Criar​

POST /integration/v1/charges
{
"amount": "250.00",
"method": "card",
"description": "Pedido 1234",
"returnUrl": "https://loja.exemplo.com.br/pedido/1234/obrigado",
"callbackUrl": "https://loja.exemplo.com.br/webhooks/pedido/1234"
}

Campos opcionais que mudam a cobrança:

CampoO que faz
currencyBRL (padrão), ou USD e EUR no cartão internacional, quando a sua conta tem essas moedas ligadas. Fora disso, 422 card_currency_not_supported com a lista aceita em error.details.supported
walletapple_pay ou google_pay: a página mostra só essa carteira, sem campo de cartão. Nome, e-mail, telefone e país vêm da carteira e completam os payer* que você não mandou. Uma recusa encerra a cobrança (declined)
payerCountryO país de quem paga (ISO 3166-1, duas letras). Muda o valor cobrado quando há preço por país; sem ele, vale a regra geral

returnUrl é obrigatória no cartão. É para onde o portador volta quando termina. Sem ela, ele fica preso na página de pagamento com uma compra concluída e nenhum caminho de volta — e o seu suporte recebe a ligação.

A resposta traz checkoutUrl​

Redirecione o portador para lá. A página hospedada trata os dados do cartão e o 3-D Secure.

{
"id": "c41a8f02-5d6e-4b7a-8c9d-0e1f2a3b4c5d",
"method": "card",
"status": "pending",
"amount": "250.00",
"netAmount": "238.75",
"currency": "BRL",
"wallet": null,
"checkoutUrl": "https://minhaloja-pay.connectionpay.io/a1b2c3d4..."
}

Quando a compra é aprovada, a resposta de consulta passa a trazer cardBrand, cardLast4 e installments.

returnUrl não é confirmação​

O portador voltando para a sua returnUrl significa que ele terminou o fluxo, não que o pagamento foi aprovado. Ele pode ter voltado de uma recusa, ou ter fechado e reaberto a aba.

Confirme pelo webhook. Liberar mercadoria no retorno do navegador é o erro mais comum — e o mais caro — de integração de cartão.

Cartão cru​

Só para conta liberada para cartão cru. Peça a liberação ao suporte; sem ela, a rota recusa. Com ela, o número e o CVV passam pelo seu servidor e o escopo de PCI é seu: guarde só o que a norma permite (nunca o CVV).

POST /integration/v1/charges/card-raw
Idempotency-Key: 7b6f0c8e-pedido-1234
{
"amount": "120.00",
"currency": "USD",
"card": { "number": "4242424242424242", "expMonth": 12, "expYear": 2028, "cvc": "123" },
"payerName": "Jane Doe",
"payerEmail": "jane@example.com",
"returnUrl": "https://loja.exemplo.com.br/pedido/1234/obrigado",
"callbackUrl": "https://loja.exemplo.com.br/webhooks/pedido/1234"
}

O cartão cru é do cartão internacional: currency é USD ou EUR. O número e o CVV vão ao processador do cartão e não ficam guardados aqui. A resposta é a cobrança com cardStatus:

cardStatusO que fazer
okNada: a captura chega pelo webhook charge.paid
requires_actionO banco pediu 3-D Secure. Conclua no navegador do comprador com action.clientSecret e action.publishableKey, e depois chame POST /integration/v1/charges/{id}/card-raw/confirm
processingEspere o webhook

Recusa: 422, com o código do emissor em error.code e em error.details.declineCode. Aceita Idempotency-Key: repita a mesma chave numa nova tentativa do mesmo pedido.

Dois eventos, dois fatos diferentes​

EventoO que aconteceu
charge.paida compra foi aprovada — pode liberar a mercadoria
charge.settledo dinheiro ficou disponível no saldo

Entre um e outro passam cerca de 30 dias. Para você são dois fatos distintos: um libera a entrega, o outro entra no caixa.

Até charge.settled, o valor aparece em receivable no saldo, não em available.

Reserva​

Uma parcela do líquido fica retida como reserva contra contestação, e é liberada depois do prazo. Os campos reserveAmount e reserveReleaseDate na cobrança dizem quanto e até quando.

Ela aparece em reserve no saldo. Não é uma taxa: é o seu dinheiro, com data para ficar disponível.

Devolver​

POST /integration/v1/charges/{id}/refund
{ "amount": "50.00" }

Sem amount, devolve o que resta. Devoluções parciais somam: o que ainda pode ser devolvido é amount − refundedAmount.

Contestação​

Uma contestação chega como charge.refunded com data.refund.isChargeback: true.

Ela pode deixar o seu saldo negativo se não houver lastro. Recusá-la não faria a contestação deixar de existir — ela já aconteceu do lado do emissor.