Sessions
Create a PIX charge from a product and get a hosted URL plus a raw PIX code for a transparent checkout.
A session creates one PIX charge from an active PIX product and returns two presentations of that same charge: a Dolafy-hosted checkoutUrl and the raw PIX Copia e Cola string in pix.code. Render the code as your own QR image for a transparent checkout, or redirect the buyer to the URL. Switching between them never creates a second charge.
Create a session
POST /v1/checkout/sessions
x-api-key: dlfy_live_...
Idempotency-Key: session:txn_1048
content-type: application/json
Provide exactly one of productId (≤ 120 chars) or externalProductId (≤ 200 chars). Optional fields: transactionReference (≤ 200), userId (≤ 200), buyerEmail (valid email, ≤ 320), description (≤ 500), and discountPercent. The discount may be a number or numeric string greater than 0 and less than 100, with at most two decimal places. It changes only this session’s charge; the reusable product and its rail remain unchanged. If transactionReference is omitted, Dolafy generates txn_<uuid>.
Request
{
"externalProductId": "curso-pro",
"transactionReference": "txn_1048",
"userId": "user_42",
"buyerEmail": "ana.silva@example.com",
"description": "Curso Pro checkout",
"discountPercent": "20.00"
}
Response
Returns 201 Created on first creation, 200 OK on an identical replay.
{
"session": {
"id": "310ace43-4c69-4fd2-acd8-94645dbe1938",
"transactionReference": "txn_1048",
"status": "created",
"checkoutUrl": "https://dolafy.com/checkout/c-8f41a2d9?dolafy_session_id=310ace43-4c69-4fd2-acd8-94645dbe1938",
"expiresAt": "2026-07-22T12:30:00.000Z",
"product": {
"id": "6a713a92-350a-4cc6-a996-1e55e97d3a36",
"externalProductId": "curso-pro",
"slug": "c-8f41a2d9",
"name": "Curso Pro",
"amount": "39.92",
"currency": "BRL"
},
"pricing": {
"originalAmount": "49.90",
"discountPercent": "20.00",
"discountAmount": "9.98",
"finalAmount": "39.92",
"currency": "BRL"
},
"pix": {
"code": "000201...6304ABCD",
"amount": "39.92",
"currency": "BRL",
"expiresAt": "2026-07-22T12:30:00.000Z"
}
}
}
Notes
session.idis the checkout charge id.pix.codeis the payable Copia e Cola payload — not a bank PIX key.- The hosted URL uses the reserved
dolafy_session_idparameter to load and poll that already-created charge; opening it never creates a second charge. This parameter is not copied into your attribution, webhookdata.urlParams, or success redirects. Treat the full hosted URL as payment-session data — do not expose it in logs. session.statusis the current normalized status — normallycreatedon first response; a replay can return a laterpending,paid,expired, orfailed.pricingmakes the one-off adjustment auditable.product.amountandpricing.finalAmountare the final charge total;pix.amountis the exact BRL amount the buyer must pay.- When
discountPercentis omitted,pricing.discountPercentisnull,discountAmountis0.00, and the original and final amounts are equal. transactionReferenceis persisted astxn_idanduserIdas the chargeexternalId; both are returned by the Transactions reads and included in webhook data.- Confirmation is driven by webhooks —
checkout.payment.completedorcheckout.payment.failed. It never depends on a success page or browser redirect. Fulfil only aftercheckout.payment.completed.
Idempotency & conflicts
An identical retry with the same Idempotency-Key returns the same charge, hosted URL, and PIX code. Replaying a completed session still works even after its product is archived.
- Reusing an idempotency key with a different body →
409 idempotency_key_conflict. - Changing
discountPercentchanges the body. Equivalent forms such as20,"20", and"20.00"normalize identically. - Assigning the same
transactionReferenceto another session →409 transaction_reference_conflict.
Rate limits
Session creation is limited per customer and per organization: 3 new sessions per customer per 10 minutes, and 30 per organization per minute. Exceeding a limit returns 429 with a Retry-After header and either checkout_session_customer_rate_limit_exceeded or checkout_session_organization_rate_limit_exceeded. Customer identity is derived from userId, then buyerEmail, then transactionReference. Identical idempotent replays do not consume the limit.
Errors
| Status | Code | Meaning |
|---|---|---|
400 | invalid_idempotency_key | The required key is missing or malformed. |
400 | invalid_body | Invalid fields, or not exactly one product identifier. |
400 | invalid_discount_percent | Percentage is not greater than 0 and less than 100, or has more than two decimals. |
400 | checkout_session_pix_only | The selected product is not PIX-only. |
400 | checkout_pix_invalid_amount | The product has an invalid payable amount. |
404 | product_not_found | No active organization-owned product matched. |
409 | idempotency_key_conflict | The key was reused with another body. |
409 | transaction_reference_conflict | Another session already reserved the reference. |
409 | checkout_session_in_progress | Retry the identical request with the same key shortly. |
429 | checkout_session_*_rate_limit_exceeded | Wait for Retry-After. |
503 | checkout_pix_not_available | Your organization’s PIX route is unavailable. |
Rare edge-case codes are listed under Advanced.
Advanced
Discount rounding and limits
The discount is calculated with exact basis-point arithmetic and rounded half-up to cents. A discount that rounds to less than one cent, or that produces a PIX total below R$1.00, is rejected before payment instructions are created — see the codes below. Discounts are accepted only by this authenticated session endpoint; do not add discount query parameters to reusable hosted product links.
Rare errors
| Status | Code | Meaning |
|---|---|---|
400 | checkout_session_discount_too_small | The discount rounds to less than one cent. |
400 | checkout_session_amount_below_minimum | The final PIX total would be below R$1.00. |
409 | checkout_session_creation_failed | Do not blindly retry with a new key; contact support. |
502 | checkout_pix_missing_payment_instructions | A payable PIX code could not be generated; retry shortly. |
503 | checkout_session_discount_unavailable | Discounted charge persistence is temporarily unavailable; retry after deployment completes. |