Skip to content
Dashboard

Warning: Provisional contract proposal

These endpoints are not operational and no SDK is published. Examples use test identifiers only and nothing is sent anywhere.

Payments

Creating charges

A charge is a single request for money from a buyer. Create it on your server, send the buyer to its checkout_url, and follow its status until it is paid, failed or expired.

Every payment in KrokoPay is a charge: an amount in BRL, a description, the methods the buyer may use and, optionally, the customer it belongs to. You create the charge with your secret key, KrokoPay hosts the payment page, and the charge moves through a small set of statuses that you can read from the API or receive as webhooks.

Information: Provisional contract

This page describes a contract proposal. Endpoints, fields and behaviour may still change, and there is no published SDK: the examples use cURL and plain fetch. Use only test keys (kp_test_sk_…).

The charge object

A charge carries its amount, what has happened to it so far and the link to its hosted checkout. Amounts are integers in centavos (minor units): 49700 means R$497.00.

Attributes

idstring
Unique identifier, prefixed with chg_.
objectstring
Always charge.
amountinteger
Amount to collect, in centavos.
currencystring
Three-letter currency code. Currently only BRL.
statusstring
One of pending, paid, failed, expired, refunded, partially_refunded. See Statuses.
methodstring | null
pix or card once the buyer chooses; null while a pending charge has no method yet.
cardobject | null
For card payments only: brand (visa, mastercard, elo, amex) and last4. Full card numbers are never returned.
descriptionstring
Shown to the buyer on the checkout and on the receipt.
customer_idstring | null
The customer the charge belongs to.
product_idstring | null
Catalog product, when the charge comes from a price or payment link.
price_idstring | null
Catalog price, when the charge comes from a price or payment link.
link_idstring | null
The payment link that created the charge, if any.
subscription_idstring | null
The subscription this charge bills, if any.
feeinteger | null
Processing fee in centavos. Commercial terms are to be announced, so the examples on this site show null. In the demo dashboard (Developers → Logs) it carries demo values.
netinteger | null
amount − fee − refunded_amount. null in these examples while fees are to be announced.
refunded_amountinteger
Total refunded so far, in centavos.
failure_codestring | null
Why a card attempt failed: card_declined, insufficient_funds, expired_card, incorrect_cvc or processing_error.
created_atstring
ISO 8601 timestamp.
paid_atstring | null
When the payment was confirmed.
expires_atstring | null
For Pix: the moment an unpaid charge expires.
available_atstring | null
When the net amount moves from pending to available balance. Release periods are to be announced, so the examples show null.
checkout_urlstring
The hosted checkout for this charge. See Checkout.
A paid Pix chargeJSON
{  "id": "chg_4Fp9KzW1xQm7Rt",  "object": "charge",  "amount": 49700,  "currency": "BRL",  "status": "paid",  "method": "pix",  "card": null,  "description": "Curso Identidade Visual do Zero",  "customer_id": "cus_8Hq2LmZr4TxN1a",  "product_id": "prod_3Vb7QpK9sWd2Ee",  "price_id": "price_5Kd1NcR8vYq3Hm",  "link_id": "plink_2Wn6HsT9cVb4Lq",  "subscription_id": null,  "fee": null,  "net": null,  "refunded_amount": 0,  "failure_code": null,  "created_at": "2026-11-03T14:22:05.000Z",  "paid_at": "2026-11-03T14:23:41.000Z",  "expires_at": "2026-11-03T14:37:05.000Z",  "available_at": null,  "checkout_url": "https://krokopay.app/pay/chg_4Fp9KzW1xQm7Rt"}

Create a charge

Endpoint: POST/v1/charges

Create the charge from your server when the buyer is ready to pay, for example when they confirm an order. The response is a pending charge with its checkout_url.

Body parameters

amountintegerRequired
Positive integer in centavos. 1000 is R$10.00.
currencystringRequired
BRL.
descriptionstringRequired
What the buyer is paying for. Keep it short and recognisable: it appears on the checkout and receipt.
customer_idstringOptional
Attach an existing customer (cus_…). If omitted, the checkout collects the buyer's details and matches or creates a customer by email.
methodsstring[]Optional
Methods offered on the checkout: pix, card or both. The buyer picks one.
curl -X POST https://api.krokopay.app/v1/charges \  -H "Authorization: Bearer kp_test_sk_4f9a2c7e1b8d4a6f9c3e5d7b" \  -H "Idempotency-Key: order_1042" \  -H "Content-Type: application/json" \  -d '{    "amount": 49700,    "currency": "BRL",    "description": "Curso Identidade Visual do Zero",    "customer_id": "cus_8Hq2LmZr4TxN1a",    "methods": [      "pix",      "card"    ]  }'

Warning: Always send an Idempotency-Key

A timeout does not tell you whether the charge was created. Send the Idempotency-Key header with a value tied to your order, so a retry returns the same charge instead of creating a second one. See Idempotency.

There is no metadata field in the current proposal. Keep the mapping between your order and the charge on your side: store the returned id with the order. When the buyer chooses Pix, the charge receives an expires_at; in the test environment that is 15 minutes after the Pix code is generated, and the production window is to be defined.

Send the buyer to the checkout

Return the checkout_url to the browser and redirect. The secret key stays on your server; the browser only ever sees the URL.

Create on the server, redirect in the browserTypeScript
// A fetch-style route handler on your server (Request in, Response out).// The secret key never reaches the browser.export async function POST(request: Request): Promise<Response> {  const order = (await request.json()) as { id: string; amount: number; customerId: string };​  const response = await fetch("https://api.krokopay.app/v1/charges", {    method: "POST",    headers: {      Authorization: `Bearer ${process.env.KROKOPAY_SECRET_KEY}`, // kp_test_sk_…      "Idempotency-Key": `order_${order.id}`,      "Content-Type": "application/json",    },    body: JSON.stringify({      amount: order.amount, // centavos      currency: "BRL",      description: `Order ${order.id}`,      customer_id: order.customerId,      methods: ["pix", "card"],    }),  });​  if (!response.ok) return new Response("Could not create the charge", { status: 502 });  const charge = (await response.json()) as { id: string; checkout_url: string };  // Store charge.id with the order, then hand the URL to the browser.  return Response.json({ checkout_url: charge.checkout_url });}

Retrieve a charge

Endpoint: GET/v1/charges/{id}

Fetch the current state of a charge by id. Use it to confirm a status after a webhook, or when the buyer returns to your site and you want to show the right page.

curl https://api.krokopay.app/v1/charges/chg_4Fp9KzW1xQm7Rt \  -H "Authorization: Bearer kp_test_sk_4f9a2c7e1b8d4a6f9c3e5d7b"
Information: An unknown id answers 404. A missing or invalid key answers 401. Both are described in Errors.

List charges

Endpoint: GET/v1/charges

Returns your charges, newest first, wrapped in a list object.

Query parameters

limitintegerOptional
How many charges to return. The maximum is to be defined.
curl https://api.krokopay.app/v1/charges?limit=20 \  -H "Authorization: Bearer kp_test_sk_4f9a2c7e1b8d4a6f9c3e5d7b"

Information: Filters and pagination

Filtering by status, customer or date and cursor-based pagination are part of the proposal still to be defined. Until then, rely on webhooks to keep your records current instead of polling the list.

Statuses and transitions

A charge starts as pending and ends in exactly one outcome. Only a paid charge can later be refunded.

FromToWhenEvent
—pendingThe charge is created.charge.created
pendingpaidThe buyer pays by Pix or the card is approved.charge.paid
pendingfailedA card attempt is declined. failure_code says why.charge.failed
pendingexpiredA Pix charge is not paid before expires_at.charge.expired
paidpartially_refundedPart of the amount is refunded.charge.refunded
paid / partially_refundedrefundedRefunds reach the full amount.charge.refunded

Warning: Failed and expired charges are closed

A charge that failed or expired does not accept another attempt. To let the buyer try again, create a new charge (with a new idempotency key) or send them back to the payment link it came from.
A declined card chargeJSON
{  "id": "chg_7Lc3PvN8yHd2Ws",  "object": "charge",  "amount": 49700,  "currency": "BRL",  "status": "failed",  "method": "card",  "card": {    "brand": "visa",    "last4": "0002"  },  "description": "Curso Identidade Visual do Zero",  "customer_id": "cus_8Hq2LmZr4TxN1a",  "product_id": "prod_3Vb7QpK9sWd2Ee",  "price_id": "price_5Kd1NcR8vYq3Hm",  "link_id": null,  "subscription_id": null,  "fee": null,  "net": null,  "refunded_amount": 0,  "failure_code": "card_declined",  "created_at": "2026-11-03T16:02:19.000Z",  "paid_at": null,  "expires_at": null,  "available_at": null,  "checkout_url": "https://krokopay.app/pay/chg_7Lc3PvN8yHd2Ws"}

To reproduce each outcome without real money, use the test cards listed in Test environment.

Refunds

Endpoint: POST/v1/charges/{id}/refunds

Refund all or part of a paid charge. You can refund several times until the refunded total reaches the charge amount. The response is the updated charge.

Body parameters

amountintegerRequired
Centavos to refund. Positive, and no more than amount − refunded_amount.
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  }'
curl -X POST https://api.krokopay.app/v1/charges/chg_4Fp9KzW1xQm7Rt/refunds \  -H "Authorization: Bearer kp_test_sk_4f9a2c7e1b8d4a6f9c3e5d7b" \  -H "Idempotency-Key: refund_1042_full" \  -H "Content-Type: application/json" \  -d '{    "amount": 49700  }'
  • Only paid and partially_refunded charges can be refunded.
  • Each refund lowers net and emits charge.refunded. Refunds are paid from your available balance; if it is not enough, the refund is refused.
  • Use a distinct Idempotency-Key per refund operation, so a retried request cannot refund twice.

Next steps

  • Checkout: what the buyer sees at checkout_url and how payment links work.
  • Webhooks: get charge.paid instead of polling.
  • Customers: attach charges to the people who pay.
  • Errors: status codes and how to handle them.