Collect with intents
One intent per payment — dynamic QR, retries, and exact reconciliation.
This flow declares every expected payment before the money moves: for each order or invoice, your backend creates an intent, Mono mints a dedicated Bre-B key and a dynamic QR for it, and the payment that arrives is linked back to the intent automatically. Reconciliation stops being detective work — you ask "was intent order-1042 paid?" and the API answers.
Use it for e-commerce checkout, invoice payment, or any case where amount and payer are known per payment and must match exactly.
Before you start
You will need:
- A Mono account with Core and the payins feature enabled for your program. See Methods — program configuration.
- A collection template created with
method_params.co_breb.key_per: "intent"— or the decision to create templateless intents directly against a subaccount. - A webhook endpoint subscribed to the payin events.
- The Intents concept fresh in mind.
Sequence overview
Steps
-
Create one intent per payment. Idempotent on
external_id— use your order ID, so a double-click cannot create two intents:{ "external_id": "order-1042", "template_id": "<key_per intent template>", "method": "co_breb", "merchant_amount": { "amount": 8990000, "currency": "COP" }, "method_params": { "create_qr": true } }Send exactly one of
merchant_amountorpayer_amount. With a templateless intent, replacetemplate_idwithsubaccount_id. -
Wait for
payin_intent_ready_to_pay. It deliverspayment_tokens— the per-intent key and a single-use QR carrying the exact amount — andexpires_at: for Bre-B, 30 minutes. Show the QR in your checkout with a countdown. -
The customer pays. The amount is enforced: a payment for anything other than the intent's amount is rejected (
intent_amount_mismatch). -
Handle the three endings.
- Paid —
payin_intent_successful(plus the payin's ownsubaccount_credited). Confirm the order. - Attempt failed —
payin_intent_attempt_failed: the payment bounced but the intent re-armed back toready_to_pay. Keep the QR on screen; the customer can retry against the same key while the window lasts. - Expired —
payin_intent_expired: the window closed unpaid. Theexternal_idis freed, so offering a fresh checkout for the same order is safe.
- Paid —
-
Reconcile without storing Mono IDs.
GET /v1/core/payins/intents/find_successful_by?external_id=order-1042returns the successful intent for your identifier, or nothing — a one-call answer to "was this paid?".
Template or templateless?
- With a
key_per: "intent"template — intents inherit limits, expected payers, andpayin_data; you manage one campaign configuration in one place. - Templateless — each intent stands alone against a subaccount, carrying its own configuration. Fewer moving parts when there is no shared campaign to speak of.
Next steps
- Intents — the full state machine, re-arming, and expiry.
- Payment tokens — dynamic QRs in detail.
- Collect with a template — the anonymous-payments alternative.