Magic QRs
Create fixed, printable QR codes and attach per-sale charges to them.
Magic QRs are permanent, printable QR codes designed for physical points of sale. A single Magic QR is created once and placed at a checkout — it never changes. When the merchant is ready to charge a customer, the standard QR Code Creation endpoint automatically attaches a charge to it: the customer scans the same printed QR and their banking app shows the amount to pay.
Charges expire in 5 minutes.
Recommended flow: use the QR Code Creation endpoint (create_dynamic_pix_b2b) with the checkout_id and store_id of the checkout that has a Magic QR configured. kamiPay will automatically assign the charge to the Magic QR and return a linked dynamic QR. Both can be scanned to complete the same payment — whichever the customer scans first settles the transaction.
How charges work
Charges are managed automatically — you don't call a separate charge endpoint. Instead, you configure which checkouts use a Magic QR as their default, and from that point the standard create_dynamic_pix_b2b call handles everything:
- kamiPay detects that the
checkout_id+store_idhas a Magic QR as its default. - A charge is created and attached to the printed QR — the customer scanning it will see the amount.
- A standard dynamic QR is also returned in the response, linked to the same charge.
- Either QR can be used to pay. Once one is paid, the other is invalidated.
Merchant POS kamiPay Gateway Customer
│ │ │ │
│ POST │ │ │
│ create_dynamic_ │ │ │
│ pix_b2b │ │ │
│ (checkout_id, │ │ │
│ store_id, amount) │ │ │
│─────────────────────►│ │ │
│ │ │ │
│ │ Checkout has Magic QR │ │
│ │ → attach charge to QR │ │
│ │────────────────────────►│ │
│ │◄────────────────────────│ │
│ │ │ │
│◄─────────────────────│ │ │
│ { emv, │ │ │
│ magic_qr_emv, │ │ │
│ operation_id, … } │ │ │
│ │ │ │
│ Show dynamic QR │ │ │
│ (or customer scans │ │ │
│ the printed one) │ │ │
│ │ │◄──── Scans QR ────│
│ │ │ Payment settled │
│ │◄──────── Webhook ───────│ │
│◄──── Notification ───│ │ │
│ │ │ │Checkout configuration
To enable Magic QRs for a checkout, contact the kamiPay team. We will configure the checkout_id and store_id mapping on our end. Once set up, no changes are needed in your integration — the existing create_dynamic_pix_b2b call will pick up the Magic QR automatically.
Create Magic QR
POST /v2/magic_qrs
Registers a new permanent QR code linked to a specific checkout and store. If a Magic QR already exists for the given checkout_id, the existing one is returned with HTTP 200 instead of 201.
Body Parameters
| Name | Type | Description |
|---|---|---|
| checkout_id | integer | Required. Identifies the checkout terminal where the QR will be placed. |
| store_id | integer | Required. Identifies the store that owns the checkout. |
Example Request
const url = `${baseURL}/v2/magic_qrs`;
const body = {
checkout_id: 1,
store_id: 1,
};
const response = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${access_token}`,
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});import requests
url = f"{base_url}/v2/magic_qrs"
body = {
"checkout_id": 1,
"store_id": 1,
}
headers = {
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json",
}
response = requests.post(url, headers=headers, json=body)package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
)
func main() {
url := baseURL + "/v2/magic_qrs"
body := map[string]interface{}{
"checkout_id": 1,
"store_id": 1,
}
requestBody, _ := json.Marshal(body)
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(requestBody))
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", accessToken))
req.Header.Add("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Println("Error:", err)
return
}
defer resp.Body.Close()
}Response
{
"kamipay_id": "mqr_a1b2c3d4e5f6",
"qr_emvcode": "00020101021226930014br.gov.bcb.pix...",
"qr_location_id": "loc_xyz789",
"address": "0x46d52020**********1fbdcc297d",
"checkout_id": 1,
"merchant_id": 42,
"store_id": 1,
"network_id": 1,
"created_at": "2024-11-01T10:00:00Z"
}{
"kamipay_id": "mqr_a1b2c3d4e5f6",
"qr_emvcode": "00020101021226930014br.gov.bcb.pix...",
"qr_location_id": "loc_xyz789",
"address": "0x46d52020**********1fbdcc297d",
"checkout_id": 1,
"merchant_id": 42,
"store_id": 1,
"network_id": 1,
"created_at": "2024-10-15T08:30:00Z"
}{
"detail": "Invalid checkout_id or store_id"
}{
"detail": "Unauthorized"
}{
"detail": "Internal Server Error during magic QR creation"
}Response Fields
| Field | Type | Description |
|---|---|---|
| kamipay_id | string | Unique identifier for this Magic QR. |
| qr_emvcode | string | The EMV string to render as the permanent, printable QR code. |
| qr_location_id | string | Gateway-side location identifier for this QR. |
| address | string | Merchant wallet address associated with this QR. |
| checkout_id | integer | The checkout this QR belongs to. |
| merchant_id | integer | The merchant that owns this QR. |
| store_id | integer | The store this QR belongs to. |
| network_id | integer | Blockchain network identifier. |
| created_at | string | ISO 8601 timestamp of when the Magic QR was created. |
HTTP 200 means a Magic QR already existed for the given checkout_id. The existing record is returned unchanged — no new QR is created.