Point of sale
Self-invoicing for card payments, for acquirers, payment apps and checkouts.
Live Merchants and charges are served by the v1 API: build against the development environment with your own credentials today.
Each approved card payment gets a single-use QR. The customer scans it and invoices themselves; the merchant does nothing.
Add the merchant
POST /merchants returns onboarding.url: a page hosted by heru with your brand, valid for 7 days. Send it to the merchant from your app or by email. The merchant uploads their CSD there; heru validates it and keeps it encrypted. You never receive or store it. The merchant.activated webhook tells you when the merchant can invoice.
If your terminal only knows the amount of a sale, register the merchant with default_item: the product code, description and VAT rate of what it sells, such as 90101500 "Consumo de alimentos" at 16% for a restaurant, or 51101500 "Medicamentos" at 0% for a pharmacy. Charges without items are invoiced as one line with it. If a merchant sells at different VAT rates, send items in every charge.
If the link expires, or the CSD is about to expire, POST /merchants/{id}/onboarding creates a new one. If you already hold the merchant's CSD, upload it from your back end with PUT /merchants/{id}/csd instead.
Create a charge for each approved card payment
From your back end, call POST /charges with the merchant_id you got when you added the merchant, the amount, the payment form (credit card 04 or debit card 28, from c_FormaPago) and your transaction id. You get back the link and its QR.
Show the QR
On the terminal screen or on the receipt. The QR holds invoice_url, a link like https://invoice.heru.app/cafeteria-la-esquina/c/9fK2wQ7xLm4TbR8vZp3N with the merchant's slug and a token that is not the charge id. It works once and expires on the date you choose with expires_in_days (30 days by default). Print your transaction id on the receipt too: it is the external_id you sent, and customers will be able to type it with the amount at invoice.heru.app/{slug}.
The customer invoices themselves
They see the merchant and the amount, enter their RFC, name and postal code, and heru validates them with the SAT before stamping. The charge.invoiced webhook tells you it is done.
Create a charge
curl -X POST https://api.dev.b2b.heru.app/v1/charges \
-H "Authorization: Bearer $TOKEN" \
-H "Idempotency-Key: TXN-0001845122" \
-H "Content-Type: application/json" \
-d '{
"merchant_id": "mer_01m4ra8wsyfh3s0tr4nrq3y96j",
"external_id": "TXN-0001845122",
"occurred_at": "2026-10-11T13:42:10-06:00",
"amount": "250.00",
"payment_form": "04",
"location": "SUC-01"
}'Rules built in
- Only the card amount is invoiced. An invoice carries a single payment form, so if part of the sale was paid in cash, that part does not go through the charge. The merchant invoices it from their own system or includes it in their global invoice.
- Reversals. Before the customer invoices, call
POST /charges/{id}/void. After they invoice, the invoice has to be cancelled. - Global invoice. Charges nobody invoiced can go into the merchant's monthly global invoice. A charge that was invoiced never does.