Printed Dynamic QRs
Create fixed, printable QR codes and attach per-sale charges to them.
Printed Dynamic QRs are permanent, printable QR codes designed for physical points of sale. A single Printed Dynamic 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) with the checkout_id and store_id of the checkout that has a Printed Dynamic QR configured. kamiPay will automatically assign the charge to the Printed Dynamic 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 Printed Dynamic QR as their default, and from that point the standard create_dynamic_pix call handles everything:
- kamiPay detects that the
checkout_id+store_idhas a Printed Dynamic 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 │ │ │
│ (checkout_id, │ │ │
│ store_id, amount) │ │ │
│─────────────────────►│ │ │
│ │ │ │
│ │ Checkout has Printed │ │
│ │ Dynamic QR │ │
│ │ → attach charge to QR │ │
│ │────────────────────────►│ │
│ │◄────────────────────────│ │
│ │ │ │
│◄─────────────────────│ │ │
│ { emv, │ │ │
│ printed_dynamic_ │ │ │
│ qr_emv, │ │ │
│ operation_id, … } │ │ │
│ │ │ │
│ Show dynamic QR │ │ │
│ (or customer scans │ │ │
│ the printed one) │ │ │
│ │ │◄──── Scans QR ────│
│ │ │ Payment settled │
│ │◄──────── Webhook ───────│ │
│◄──── Notification ───│ │ │
│ │ │ │Checkout configuration
To enable Printed Dynamic 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 call will pick up the Printed Dynamic QR automatically.
Create Printed Dynamic QR
POST /v2/printed_dynamic_qrs
Registers a new permanent QR code linked to a specific checkout and store. If a Printed Dynamic 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. When auto_create_checkout is true, this is the checkout_id that will be assigned to the newly created checkout (not auto-incremented). |
| store_id | integer | Optional. Identifies the store that owns the checkout. Defaults to 1. |
| auto_create_checkout | boolean | Optional. Defaults to false. When true, kamiPay creates the checkout (using the provided checkout_id) and wires default_qr=printed_dynamic_qr on it before generating the printed QR — letting you provision a checkout and its printed QR in a single call. See the warning below. |
auto_create_checkout wallet & store defaults. When you set auto_create_checkout: true, the new checkout inherits its wallet from checkout 1 of the same store_id you sent in the request — not from a generic merchant wallet. If you don't send store_id, it defaults to 1, so the wallet is taken from checkout (store_id=1, checkout_id=1). If you'd rather configure the store, checkout or wallet yourself, use the Stores and Checkouts endpoints instead and then call this endpoint with auto_create_checkout: false (or omitted).
Example Request
const url = `${baseURL}/v2/printed_dynamic_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/printed_dynamic_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/printed_dynamic_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
{
"printed_dynamic_qr_id": "pqr_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": 1730455200
}{
"printed_dynamic_qr_id": "pqr_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": 1728981000
}{
"detail": "Invalid checkout_id or store_id"
}{
"detail": "Unauthorized"
}{
"detail": "Internal Server Error during printed dynamic QR creation"
}Response Fields
| Field | Type | Description |
|---|---|---|
| printed_dynamic_qr_id | string | Unique identifier for this Printed Dynamic QR (prefixed with pqr_). |
| 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 | integer | Unix timestamp (epoch seconds) of when the Printed Dynamic QR was created. |
HTTP 200 means a Printed Dynamic QR already existed for the given checkout_id. The existing record is returned unchanged — no new QR is created.
Auto-creating the checkout in one call
Send auto_create_checkout: true to provision the checkout, wire default_qr=printed_dynamic_qr on it, and generate the printed QR in a single request. If the checkout you point to already exists, kamiPay reuses it silently and only ensures the default_qr config is set.
const response = await fetch(`${baseURL}/v2/printed_dynamic_qrs`, {
method: "POST",
headers: {
Authorization: `Bearer ${access_token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
checkout_id: 500, // the id you want the new checkout to have
auto_create_checkout: true, // store_id omitted → defaults to 1
}),
});The created checkout's wallet is inherited from checkout 1 of the same store_id. Subsequent calls to create_dynamic_pix for that (store_id, checkout_id) will automatically dispatch to the Printed Dynamic QR flow.
The block (checkout creation + default_qr config) is committed before the gateway call, so a transient gateway failure leaves your checkout and config in place — a retry just needs to finish generating the printed QR.
List Printed Dynamic QRs
GET /v2/printed_dynamic_qrs
Returns the merchant's Printed Dynamic QRs grouped as stores → checkouts → printed_dynamic_qrs. Useful to audit which checkouts already have a printed QR provisioned.
Query Parameters
| Name | Type | Description |
|---|---|---|
| store_id | integer | Optional. Filter by store. |
| checkout_id | integer | Optional. Filter by checkout. When provided without store_id, store_id=1 is assumed. |
| page | integer | Optional. Defaults to 1. |
| page_size | integer | Optional. Defaults to 100 (also the maximum). |
Example Request
const url = `${baseURL}/v2/printed_dynamic_qrs?page=1&page_size=100`;
const response = await fetch(url, {
method: "GET",
headers: {
Authorization: `Bearer ${access_token}`,
},
});import requests
url = f"{base_url}/v2/printed_dynamic_qrs"
headers = {"Authorization": f"Bearer {access_token}"}
params = {"page": 1, "page_size": 100}
response = requests.get(url, headers=headers, params=params)package main
import (
"fmt"
"net/http"
)
func main() {
url := baseURL + "/v2/printed_dynamic_qrs?page=1&page_size=100"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", accessToken))
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Println("Error:", err)
return
}
defer resp.Body.Close()
}Response
{
"total": 3,
"page": 1,
"page_size": 100,
"stores": [
{
"store_id": 1,
"checkouts": [
{
"checkout_id": 4,
"printed_dynamic_qrs": [
{
"printed_dynamic_qr_id": "pqr_a1b2c3d4e5f6",
"qr_emvcode": "00020101021226930014br.gov.bcb.pix...",
"address": "0x46d52020**********1fbdcc297d"
}
]
},
{
"checkout_id": 500,
"printed_dynamic_qrs": [
{
"printed_dynamic_qr_id": "pqr_belo500abcdef",
"qr_emvcode": "00020101021226930014br.gov.bcb.pix...",
"address": "0x46d52020**********1fbdcc297d"
}
]
}
]
}
]
}Response Fields
| Field | Type | Description |
|---|---|---|
| total | integer | Total number of Printed Dynamic QRs that match the filters (unpaginated). |
| page | integer | Current page (echoes the request). |
| page_size | integer | Items per page (echoes the request). |
| stores | array | Stores that have at least one matching Printed Dynamic QR, each containing its checkouts. |
| stores[].store_id | integer | The store identifier. |
| stores[].checkouts | array | Checkouts within the store that have at least one matching Printed Dynamic QR. |
| stores[].checkouts[].checkout_id | integer | The checkout identifier. |
| stores[].checkouts[].printed_dynamic_qrs | array | Printed Dynamic QRs assigned to the checkout. |
| stores[].checkouts[].printed_dynamic_qrs[].printed_dynamic_qr_id | string | Unique identifier for the QR. |
| stores[].checkouts[].printed_dynamic_qrs[].qr_emvcode | string | EMV string for the printed QR. |
| stores[].checkouts[].printed_dynamic_qrs[].address | string | Merchant wallet address linked to the QR. |
Need to set or inspect the default_qr config (or any other checkout config) directly? See Checkout Configs under Account Administration.