Skip to content
KrokoPay

Card · Products

Card payments that explain every decline

The checkout validates the card while the buyer types, shows the brand and, when a payment fails, tells the buyer what to do next. You receive the same reason as a failure_code in the charge.failed webhook.

Test mode only on this site: use the test cards below, no real card is charged.

  • Validation while typing
  • Brand detection
  • 5 documented failure codes

Test cards

Pick a card to fill in the number. Any future expiry and any CVC work.

What your system sees

Pendingchg_7Lc3PvN8yHd2Ws
{
  "status": "pending",
  "failure_code": null
}

Fictional data. No real payment is made.

While the buyer types

Mistakes caught before the payment

Most typing errors never reach a payment attempt. The checkout formats the number, detects the brand and checks the length and the checksum as the buyer types.

  • Groups of four digits, formatted automatically.
  • Brand detected from the first digits.
  • Length and checksum checked before submitting.
  • Security code length matches the brand.

Try it: type a card number

Try 4242 4242 4242 4242 or change one digit.

Brand
Not detected yet
Digits
0 of 16
Checksum
Waiting for all digits
Security code
0 of 3 digits

What you type stays in this browser tab, in memory only. This demo never stores card numbers.

When a payment fails

Every decline has a reason

A failed card payment is not a dead end. The buyer sees what happened and what to try next. You receive the same reason as a failure_code, so support does not have to guess.

What the buyer sees

Your card was declined. Try another card or pay by Pix.

What you receive

failure_code: "card_declined"Card declined

The card issuer refused the payment without giving a more specific reason.

What you can do

Offer Pix or another card. Retrying the same card right away usually gives the same result.

Test card4000 0000 0000 0002
charge.failedJSON
{  "id": "evt_7Pp8Qq9Rr0Ss1T",  "object": "event",  "type": "charge.failed",  "api_version": "2026-11-01",  "created_at": "2026-11-03T16:02:24.000Z",  "data": {    "object": {      "id": "chg_7Lc3PvN8yHd2Ws",      "object": "charge",      "amount": 49700,      "currency": "BRL",      "status": "failed",      "method": "card",      "card": {        "brand": "visa",        "last4": "0002"      },      "failure_code": "card_declined"    }  }}
All error codes

Test cards

Trigger each outcome on purpose

Use these numbers in the demo checkout. Any future expiry date and any security code work.

Fictional numbers that only work in test mode.

Test environment docs
Test card numbers and the outcome each one produces
Number
4242 4242 4242 4242Approved
4000 0000 0000 0002Card declinedcard_declined
4000 0000 0000 9995Insufficient fundsinsufficient_funds
4000 0000 0000 0069Expired cardexpired_card
4000 0000 0000 0127Incorrect security codeincorrect_cvc

Refunds

Refund in full or in part

Refund a paid card charge from the dashboard or with the API proposal. The charge keeps its history and reports the refund with an event.

  • Full refund

    Refunded

    The whole amount goes back. The charge status becomes refunded.

  • Partial refund

    Partially refunded

    Part of the amount goes back. The status becomes partially_refunded and refunded_amount shows how much.

charge.refunded Each refund triggers charge.refunded.

When the buyer sees the money backTo be announcedSee pricing
curl -X POST https://api.krokopay.app/v1/charges/chg_4Fp9KzW1xQm7Rt/refunds \  -H "Authorization: Bearer kp_test_sk_4f9a2c7e1b8d4a6f9c3e5d7b" \  -H "Idempotency-Key: refund_1042" \  -H "Content-Type: application/json" \  -d '{    "amount": 9900  }'
ResponseJSON
{  "id": "chg_4Fp9KzW1xQm7Rt",  "object": "charge",  "amount": 49700,  "currency": "BRL",  "status": "partially_refunded",  "refunded_amount": 9900}

Provisional API contract proposal. These are examples, not an operational endpoint.

About card data

This demo never stores card numbers. Production security terms will be published.

Card questions, answered plainly

Including what is not defined yet.

Still undefined

  • FeesTo be announced
  • When funds become availableTo be announced
  • When refunds reach the buyerTo be announced

Shown as “To be announced” until the terms are final.

See pricing

The demo checkout detects Visa, Mastercard, Elo and Amex from the first digits and adjusts the number and security code length to the brand.

The buyer sees a short explanation and can try another card or switch to Pix on the same page. You receive charge.failed with a failure_code: card_declined, insufficient_funds, expired_card, incorrect_cvc or processing_error.

The buyer can try again in the checkout. On the API side, a retry should use an idempotency key so it never creates a duplicate charge.

Yes, fully or partially, from the dashboard or with the refunds endpoint of the API proposal. Each refund triggers charge.refunded.

Commercial terms, including fees and when funds become available, are still to be announced. We do not quote numbers before they are final.

This demo never stores card numbers. Production security terms will be published.

Test every card outcome before you go live

Create an account, open a checkout in the demo dashboard and try the test cards.

No real card is charged.