Static QR Code
Create the static QR of a checkout, and receive each charge that a payer makes to it.
A static QR is a Pix QR code that belongs to one checkout. You don't set an amount: the payer enters it when paying. Its EMV is always the same, so you can print it once.
You receive the USDt at the rate of the moment the payer pays. So you don't know the amount in USDt before the payment. For an estimate of the USDt for an amount, use the Oracle with type=charge.
- No minimum amount: the payer can pay any amount, and you receive its equivalent in USDt at the rate of the moment.
- One static QR per checkout: a checkout has at most one static QR. For more static QRs, create more checkouts first.
- No delete or change, for now: a static QR can't be deleted or changed. Charges to an old static QR keep arriving, and they settle to the checkout's current wallet.
- What the payer sees: the payer's bank app shows as the receiver the legal name of the kamiPay entity that receives the charge (today, KP SERVICOS DIGITAIS LTDA), and can show your company name as additional information.
Static QR charges are eligible for blockchain batched settlement. When the checkout opts in, each charge is acknowledged immediately and paid out in one consolidated USDt transfer per window.
How a charge reaches you
A static QR has no external_id and no fixed amount, so you match each charge to its QR by the ids below.
The pay-in webhook arrives for each charge: processing, then done, as for any charge. For a static QR charge:
qr_typeis"static".kamipay_id(sqr_…) andpix_idare new for each charge. Store each charge by itskamipay_id.data.internal_pix_idis the static QR'sqr_txid. Match each charge to its QR by it.
For example, a processing webhook for a charge of R$ 37.50:
{
"pix_id": "ptxr_01kp7x3k2n8f4h6j9c3d5g7a1s",
"status": "processing",
"tx_id": null,
"timestamp": "2026-10-14 11:42:07.481203-03:00",
"type": "charge",
"qr_type": "static",
"kamipay_id": "sqr_01kp7x3m9d2q5w8e4r6t1y3v5b",
"data": {
"bank_txid": "E29384756202610141142aB3cD5eF7gH",
"bank_account_nr": "29384756-0001-0001349872",
"internal_pix_id": "8990817275KPSD12380080099",
"amount_brl": "37.50",
"amount_usdt": "6.912442",
"address_out": "0x46d52020**********1fbdcc297d",
"name": "Satoshi Nakamoto"
}
}Who receives the webhooks: the webhooks of a static QR's charges go to the API user that created it. If kamiPay created it for you, they go to your account's main API user.
Tx Status → Pay-In finds a static QR charge by its kamipay_id, its operation_id (the webhook's pix_id), its e2e_id (the webhook's bank_txid) or its tx_id. With e2e_id, only the API user that receives the webhooks finds it.
List Static QR Charges gives the charges of one static QR.
Static QR Object
Create, list and detail give each static QR as this object:
{
"qr_txid": "8990817275KPSD12380080099",
"emv": "00020126710014br.gov.bcb.pix01367f3c2a91-5d4e-4b8a-9c6f-2e1d0b3a8f540209ACME LTDA5204000053039865802BR5925KP SERVICOS DIGITAIS LTDA6009SAO PAULO622905258990817275KPSD1238008009963046716",
"store_id": 1,
"checkout_id": 2,
"address": "0x46d52020**********1fbdcc297d",
"created_at": 1791932645
}| Field | Type | Description |
|---|---|---|
| qr_txid | string | The static QR's id: 10 digits, KPSD1 and 10 digits. Each charge's internal_pix_id is this value. |
| emv | string | The QR's Pix code. Render it as a QR image. It never changes. |
| store_id | integer | The store of the checkout. |
| checkout_id | integer | The checkout the static QR belongs to. |
| address | string | The checkout's current wallet, where the USDt settle, as Wallets lists it. It follows the checkout's wallet if it changes. |
| created_at | integer | When the static QR was created, as an epoch in seconds. |
Create Static QR
POST /v2/static_qrs
Creates the static QR of a checkout. If the checkout already has a static QR, you get it with 200, and nothing is created. So the same request again gets the same static QR.
The checks of the request come first, also when the checkout has a static QR. An address that isn't the checkout's wallet, or a wallet that isn't on Polygon, gets its 400.
Create the checkout first, with Create Checkout. To find your stores and checkouts, see Stores and Checkouts.
Body Parameters
| Name | Type | Description |
|---|---|---|
| store_id | integer | Required. The store of the checkout. |
| checkout_id | integer | Required. The checkout that gets the static QR. |
| address | string | Optional. A check, not a choice of wallet: if you send it, it must be the checkout's wallet, or the request is rejected with 400. Without it, the static QR uses the checkout's wallet. |
Example Request
const url = `${baseURL}/v2/static_qrs`;
const body = {
store_id: 1,
checkout_id: 2,
};
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/static_qrs"
body = {
"store_id": 1,
"checkout_id": 2,
}
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/static_qrs"
body := map[string]interface{}{
"store_id": 1,
"checkout_id": 2,
}
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
The static QR was created. The body is the static QR object:
{
"qr_txid": "8990817275KPSD12380080099",
"emv": "00020126710014br.gov.bcb.pix01367f3c2a91-5d4e-4b8a-9c6f-2e1d0b3a8f540209ACME LTDA5204000053039865802BR5925KP SERVICOS DIGITAIS LTDA6009SAO PAULO622905258990817275KPSD1238008009963046716",
"store_id": 1,
"checkout_id": 2,
"address": "0x46d52020**********1fbdcc297d",
"created_at": 1791932645
}The checkout already has a static QR. The body is that static QR object, and nothing is created:
{
"qr_txid": "8990817275KPSD12380080099",
"emv": "00020126710014br.gov.bcb.pix01367f3c2a91-5d4e-4b8a-9c6f-2e1d0b3a8f540209ACME LTDA5204000053039865802BR5925KP SERVICOS DIGITAIS LTDA6009SAO PAULO622905258990817275KPSD1238008009963046716",
"store_id": 1,
"checkout_id": 2,
"address": "0x46d52020**********1fbdcc297d",
"created_at": 1791932645
}{
"detail": "Incorrect data Address, Store, Checkout: checkout 99 not found in store 1"
}The detail you can get, each with one example (the ids in it vary). The first three are the same as in QR Code Creation:
Example detail | When |
|---|---|
"Incorrect data Address, Store, Checkout: checkout 99 not found in store 1" | The store has no checkout with that checkout_id. |
"Incorrect data Address, Store, Checkout: address doesn't match the wallet of checkout 2" | The address you sent isn't the checkout's wallet. |
"Incorrect data Address, Store, Checkout: user has no access to store 2" | The user your credentials belong to has no access to that store. |
"Wallet network deprecated" | The checkout's wallet isn't on Polygon (see Wallets). |
Without a token:
{
"detail": "Not authenticated"
}With an invalid or expired token:
{
"detail": "Could not validate credentials"
}store_id or checkout_id is missing. For example, a request without checkout_id:
{
"detail": [
{
"type": "missing",
"loc": ["body", "checkout_id"],
"msg": "Field required",
"input": {
"store_id": 1
}
}
]
}{
"detail": "Internal Server Error"
}The detail can also be another text, for example "Failed to register the static QR". Send the same request again: if the static QR was created, you get it with 200.
{
"detail": "Unable to determine PIX key ownership"
}kamiPay can't create the static QR now, and nothing is created. Send the same request again later.
List Static QRs
GET /v2/static_qrs
Returns all your static QRs, newest first, as an array of the static QR object.
Example Request
const url = `${baseURL}/v2/static_qrs`;
const response = await fetch(url, {
method: "GET",
headers: {
Authorization: `Bearer ${access_token}`,
},
});import requests
url = f"{base_url}/v2/static_qrs"
headers = {
"Authorization": f"Bearer {access_token}",
}
response = requests.get(url, headers=headers)package main
import (
"fmt"
"net/http"
)
func main() {
url := baseURL + "/v2/static_qrs"
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
[
{
"qr_txid": "8990817275KPSD12380080099",
"emv": "00020126710014br.gov.bcb.pix01367f3c2a91-5d4e-4b8a-9c6f-2e1d0b3a8f540209ACME LTDA5204000053039865802BR5925KP SERVICOS DIGITAIS LTDA6009SAO PAULO622905258990817275KPSD1238008009963046716",
"store_id": 1,
"checkout_id": 2,
"address": "0x46d52020**********1fbdcc297d",
"created_at": 1791932645
}
]Without a token:
{
"detail": "Not authenticated"
}With an invalid or expired token:
{
"detail": "Could not validate credentials"
}{
"detail": "Internal Server Error"
}Get Static QR
GET /v2/static_qrs/{qr_txid}
Returns one static QR, as the static QR object.
Path Parameters
| Name | Type | Description |
|---|---|---|
| qr_txid | string | Required. The static QR's qr_txid. |
Example Request
const qr_txid = "8990817275KPSD12380080099";
const url = `${baseURL}/v2/static_qrs/${qr_txid}`;
const response = await fetch(url, {
method: "GET",
headers: {
Authorization: `Bearer ${access_token}`,
},
});import requests
qr_txid = "8990817275KPSD12380080099"
url = f"{base_url}/v2/static_qrs/{qr_txid}"
headers = {
"Authorization": f"Bearer {access_token}",
}
response = requests.get(url, headers=headers)package main
import (
"fmt"
"net/http"
)
func main() {
qrTxid := "8990817275KPSD12380080099"
url := fmt.Sprintf("%s/v2/static_qrs/%s", baseURL, qrTxid)
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
{
"qr_txid": "8990817275KPSD12380080099",
"emv": "00020126710014br.gov.bcb.pix01367f3c2a91-5d4e-4b8a-9c6f-2e1d0b3a8f540209ACME LTDA5204000053039865802BR5925KP SERVICOS DIGITAIS LTDA6009SAO PAULO622905258990817275KPSD1238008009963046716",
"store_id": 1,
"checkout_id": 2,
"address": "0x46d52020**********1fbdcc297d",
"created_at": 1791932645
}Without a token:
{
"detail": "Not authenticated"
}With an invalid or expired token:
{
"detail": "Could not validate credentials"
}Your account has no static QR with that qr_txid:
{
"detail": "Static QR not found"
}{
"detail": "Internal Server Error"
}List Static QR Charges
GET /v2/static_qrs/{qr_txid}/charges
Returns the charges of one static QR, a page at a time:
- Each item is the charge object of Tx Status → Pay-In, with the same fields and formats; read their description there. Its
qr_typeis"static". - It lists the charges from
processingon, newest first. Each charge has its current status:doneorfailedwins overprocessing, as for the webhooks.timestampis when the charge reached that status. - A
failedcharge has onlystatusandtimestamp, as Tx Status gives it.
Path Parameters
| Name | Type | Description |
|---|---|---|
| qr_txid | string | Required. The static QR's qr_txid. |
Query Parameters
| Name | Type | Description |
|---|---|---|
| from_date | string | Optional. ISO 8601 date and time with its offset, for example 2026-10-13T00:00:00-03:00. Only the charges that arrived at this time or after it. |
| to_date | string | Optional. ISO 8601 date and time with its offset, for example 2026-10-13T23:59:59-03:00. Only the charges that arrived at this time or before it. |
| page | integer | Optional. The page number, from 1. Default: 1. |
| page_size | integer | Optional. The number of charges on each page, from 1 to 100. Default: 20. |
from_date and to_date filter on when the charge arrived, not on its timestamp. Send them with their offset: a value without one isn't read in your time zone. A page or page_size out of range is rejected with 422.
Example Request
const qr_txid = "8990817275KPSD12380080099";
const url = `${baseURL}/v2/static_qrs/${qr_txid}/charges?page=1&page_size=20`;
const response = await fetch(url, {
method: "GET",
headers: {
Authorization: `Bearer ${access_token}`,
},
});import requests
qr_txid = "8990817275KPSD12380080099"
url = f"{base_url}/v2/static_qrs/{qr_txid}/charges"
params = {
"page": 1,
"page_size": 20,
}
headers = {
"Authorization": f"Bearer {access_token}",
}
response = requests.get(url, headers=headers, params=params)package main
import (
"fmt"
"net/http"
)
func main() {
qrTxid := "8990817275KPSD12380080099"
url := fmt.Sprintf("%s/v2/static_qrs/%s/charges?page=1&page_size=20", baseURL, qrTxid)
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": 2,
"page": 1,
"page_size": 20,
"items": [
{
"status": "processing",
"qr_type": "static",
"kamipay_id": "sqr_01kp7x3m9d2q5w8e4r6t1y3v5b",
"operation_id": "ptxr_01kp7x3k2n8f4h6j9c3d5g7a1s",
"bank_txid": "E29384756202610141142aB3cD5eF7gH",
"bank_account_nr": "29384756-0001-0001349872",
"internal_pix_id": "8990817275KPSD12380080099",
"amount_brl": "37.50",
"amount_usdt": "6.912442",
"tx_id": null,
"address_out": "0x46d52020**********1fbdcc297d",
"name": "Satoshi Nakamoto",
"timestamp": "2026-10-14 11:42:07.481203-03:00"
},
{
"status": "done",
"qr_type": "static",
"kamipay_id": "sqr_01kp6r4b8c2d9e5f3g7h1j6k2m",
"operation_id": "ptxr_01kp6r4a6x3z8y2w5v9t4s7q3n",
"bank_txid": "E41736582202610141015kM2nP4qR6sT",
"bank_account_nr": "41736582-1234-0000567890",
"internal_pix_id": "8990817275KPSD12380080099",
"amount_brl": "120.00",
"amount_usdt": "22.119816",
"tx_id": "0xbeb75238a35bbed5fc780c5dae1c68be918b20015e528579014a5a2944f7a358",
"address_out": "0x46d52020**********1fbdcc297d",
"name": "Hal Finney",
"timestamp": "2026-10-14 10:18:33.207915-03:00"
}
]
}Without a token:
{
"detail": "Not authenticated"
}With an invalid or expired token:
{
"detail": "Could not validate credentials"
}Your account has no static QR with that qr_txid:
{
"detail": "Static QR not found"
}A query parameter is out of range. For example, page_size=101:
{
"detail": [
{
"type": "less_than_equal",
"loc": ["query", "page_size"],
"msg": "Input should be less than or equal to 100",
"input": "101",
"ctx": {
"le": 100
}
}
]
}{
"detail": "Internal Server Error"
}Response Fields
| Field | Type | Description |
|---|---|---|
| total | integer | The number of charges on all pages. |
| page | integer | The page number. |
| page_size | integer | The maximum number of charges on each page. |
| items | array | The charges on this page, newest first. Each one is the charge object of Tx Status → Pay-In. |