PDV — My sales
History of the PDV's own charges — unifies both methods (printed QR + PIN and dynamic QR/NFC) into one list, ordered by date. Self-service: always your own sales, never another PDV's — identified from your own token, no parameter to see someone else's.
| Endpoint | What it does |
|---|---|
GET /v1/events/{eventId}/pdv/transactions | Lists this PDV's sales/attempts, cursor-paginated. |
- curl
- JavaScript
- Python
curl "http://127.0.0.1:8787/v1/events/{eventId}/pdv/transactions?limit=20" \
-H "Authorization: Bearer <PDV accessToken>"
const response = await fetch(
`http://127.0.0.1:8787/v1/events/${eventId}/pdv/transactions?limit=20`,
{ headers: { Authorization: `Bearer ${pdvAccessToken}` } },
);
const { items, nextCursor } = await response.json();
import requests
response = requests.get(
f"http://127.0.0.1:8787/v1/events/{event_id}/pdv/transactions",
headers={"Authorization": f"Bearer {pdv_access_token}"},
params={"limit": 20},
)
result = response.json()
{
"items": [
{
"transactionId": "018f26d7-...",
"channel": "dynamic_qr",
"amountMinor": 2500,
"status": "approved",
"declineReason": null,
"occurredAt": "2026-09-10T18:30:00.000Z",
"resolvedAt": "2026-09-10T18:30:12.000Z"
},
{
"transactionId": "018f26d7-...",
"channel": "printed_qr_pin",
"amountMinor": 1200,
"status": "declined",
"declineReason": "CREDENTIAL_LOCKED",
"occurredAt": "2026-09-10T18:25:00.000Z",
"resolvedAt": "2026-09-10T18:25:00.000Z"
}
],
"nextCursor": null
}
channel tells which of the two methods produced that row — dynamic_qr
(dynamic QR/NFC) or printed_qr_pin (printed QR + PIN). status is
pending | approved | declined | expired; only dynamic_qr can
ever be pending — a printed-QR sale is already resolved (approved or
declined) the moment it's created, there's no intermediate state in that
flow. declineReason is only set when status is declined, using the
same codes already documented on each method's own page
(INSUFFICIENT_BALANCE, CREDENTIAL_LOCKED, CREDENTIAL_EXPIRED,
CREDENTIAL_NOT_ACTIVE, WALLET_NOT_ACTIVE).
resolvedAt is only null while a dynamic_qr transaction is still
pending (waiting on the participant) — everything else already has it
set. An intent nobody ever resolved takes up to ~15 seconds after
expiresAt to show up here as expired — that's when an internal process
notices it's overdue (see Dynamic payment via
QR/NFC for the detail).
What doesn't show up here
- A printed QR with a wrong PIN that hasn't locked the credential yet
(attempts 1 through 4 of 5) doesn't create a row at all — only the
attempt that actually locks the credential (the 5th wrong one) shows up,
as
declined/CREDENTIAL_LOCKED. - A QR (printed or dynamic) for the wrong or an unknown event also doesn't show up — that case stays deliberately ambiguous for security reasons (see Payment via printed QR + PIN).
Filters and pagination
Cursor-paginated (not numbered pages): when nextCursor comes back
non-null, call again with ?cursor=<value> for the next batch — keep the
same sortDirection/filters as the original call, or the API rejects with
PDV_TRANSACTIONS_CURSOR_SORT_MISMATCH.
| Parameter | What it does |
|---|---|
channel | dynamic_qr or printed_qr_pin — one method at a time. |
status | pending, approved, declined, or expired. |
occurredAfter / occurredBefore | Date range, ISO 8601, inclusive on both ends. |
sortDirection | asc or desc (default: desc, newest first). |
limit | 1 to 100 (default 50). |
All optional and combinable — with no filter at all, returns everything (both methods), newest first.