Z Zise Developers 简体中文

Card transactions (cursor pagination)

GET /v1/cards/{id}/transactions scope: cards:read
On behalf of a member · x-on-behalf-of required

Always read direction as well. amount is an absolute value, guaranteed nonnegative by a database CHECK. Looking only at the amount makes a refund indistinguishable from a purchase.

amount is the displayed amount in the card currency, an integer string in the smallest unit with precision scale: it uses the card balance movement when available, otherwise the authorization hold. Its meaning is unchanged.

Additive fields that do not change amount:

  • original_amount / original_currency: the upstream transaction's original amount and currency, preserving txn_amount exactly as stored. Cross-border POS transactions often use IDR/HKD, etc.; this is not the card currency.
  • bill_amount: the card-currency bill, an integer string in the smallest unit using the same currency/scale as amount. Uses only stored card-currency figures from the upstream: the settlement amount when settle_currency matches the card currency, otherwise the authorization hold, otherwise the stored card-currency figure used for amount. It never converts the original currency to dollars using a current exchange rate. Omitted when no bill amount is known (returns "0" only when amount is also "0").

Transaction updates are announced by card.transaction.updated; this endpoint also supports querying the current state. bank_fee is the bank fee; zinfra_fee is the zinfra fee (currently "0" for all cards). Both fee fields are integer strings in the smallest unit; use fee_currency for the currency and fee_scale for precision. Fees are cumulative snapshots for the transaction, not additional debits introduced by this notification. Authorization shows currently known fees; settlement may update them. Do not add fees again to card amounts that already include them.

Order is fixed: newest occurred_at first. Filters do not change that order. To find one transaction, pass id (the ctx_ value from this list and from card.transaction.updated) or auth_code (the authorization code, exact match). There is no separate transaction sequence number. One authorization code can match both the authorization and the settlement; filtered results are still paged newest-first.

from / to use the same column as the cursor (occurred_at). to is exclusive (<). Times must be ISO-8601. An unparseable time, or an illegal id / direction, is 400 invalid_fields and is never silently ignored.

kind and status are open enumerations: exact and case-sensitive, and we do not validate the value. An unrecognized value returns an empty list, not an error. direction is closed: debit / credit / none / unknown. Anything else is 400.

Path Parameters

FieldTypeRequiredDescription
id string Required Card ID

Query Parameters

FieldTypeRequiredDescription
cursor string Optional The previous page's next_cursor (an opaque string).
limit integer Optional Defaults to 20, maximum 100.
id string Optional Return only that transaction. The ctx_ prefix is optional. A value that is not this kind of id is 400 invalid_fields. A miss is an empty list, not 404.
auth_code string Optional Exact, case-sensitive match on the authorization code. This is the short code used to recognize a purchase in the list, not the transaction id. One code can match multiple rows. Longer than 64 characters is 400 invalid_fields.
kind string Optional Filter by transaction type, matching kind in the response. Exact and case-sensitive. Open enumeration, not validated; an unknown value returns an empty list.
status string Optional Filter by status, matching status in the response. Exact and case-sensitive. Open enumeration, not validated; an unknown value returns an empty list.
direction string Optional debit, credit, none, or unknown. Closed enumeration; any other value is 400 invalid_fields.
from string Optional Start time, inclusive, ISO-8601. Compared against occurred_at.
to string Optional End time, exclusive, ISO-8601. Compared against occurred_at.
FieldTypeRequiredDescription
x-on-behalf-of string Required The member on whose behalf to call.

Response

200OK (ordered by occurrence time descending).
{
  "data": [
    {
      "id": "ctx_2c9e4b10-77af-4d3a-8e51-b0d6c2f9a134",
      "kind": "auth",
      "status": "succeed",
      "direction": "debit",
      "amount": "12990000",
      "currency": "USD",
      "scale": 6,
      "original_amount": "199000.00",
      "original_currency": "IDR",
      "bill_amount": "12990000",
      "bank_fee": "30000",
      "zinfra_fee": "0",
      "fee_currency": "USD",
      "fee_scale": 6,
      "merchant_name": "NETFLIX.COM",
      "mcc": "4899",
      "auth_code": "084217",
      "occurred_at": "2026-08-09T10:55:02.000Z"
    }
  ],
  "next_cursor": null,
  "has_more": false
}
400invalid_fields when id is not a transaction id, when auth_code, kind, or status exceeds 64 characters, when direction is not debit|credit|none|unknown, or when from or to is not valid ISO-8601 (see the fields array).
404not_found: the card does not exist or does not belong to this member/merchant.
500api_error: service error.
Request
curl -X GET 'https://api.zinfra.vip/v1/cards/{id}/transactions' \
  -H 'x-auth-token: Bearer $TOKEN' \
  -H 'x-on-behalf-of: $MEMBER_ID'
const res = await fetch("https://api.zinfra.vip/v1/cards/{id}/transactions", {
  method: "GET",
  headers: {
    "x-auth-token": "Bearer $TOKEN",
    "x-on-behalf-of": "$MEMBER_ID",
  },
});
// Keep monetary amounts as strings, never numbers.
const data = await res.json();
import requests

res = requests.get(
    "https://api.zinfra.vip/v1/cards/{id}/transactions",
    headers={
        "x-auth-token": "Bearer $TOKEN",
        "x-on-behalf-of": "$MEMBER_ID",
    },
)
# Use Decimal(str(...)) for amounts, not float.
data = res.json()
req, _ := http.NewRequest("GET", "https://api.zinfra.vip/v1/cards/{id}/transactions",
    nil)
req.Header.Set("x-auth-token", "Bearer $TOKEN")
req.Header.Set("x-on-behalf-of", "$MEMBER_ID")
res, err := http.DefaultClient.Do(req)
// Decode amount fields as string, not float64.
HttpRequest req = HttpRequest.newBuilder()
    .uri(URI.create("https://api.zinfra.vip/v1/cards/{id}/transactions"))
    .header("x-auth-token", "Bearer $TOKEN")
    .header("x-on-behalf-of", "$MEMBER_ID")
    .method("GET", HttpRequest.BodyPublishers.noBody())
    .build();
// Use String / BigDecimal for amounts, not double.
$ch = curl_init('https://api.zinfra.vip/v1/cards/{id}/transactions');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    'x-auth-token: Bearer $TOKEN',
    'x-on-behalf-of: $MEMBER_ID',
  ],
]);
$res = curl_exec($ch);
// Use bcmath / strings for amounts, not floatval.
200
{
  "data": [
    {
      "id": "ctx_2c9e4b10-77af-4d3a-8e51-b0d6c2f9a134",
      "kind": "auth",
      "status": "succeed",
      "direction": "debit",
      "amount": "12990000",
      "currency": "USD",
      "scale": 6,
      "original_amount": "199000.00",
      "original_currency": "IDR",
      "bill_amount": "12990000",
      "bank_fee": "30000",
      "zinfra_fee": "0",
      "fee_currency": "USD",
      "fee_scale": 6,
      "merchant_name": "NETFLIX.COM",
      "mcc": "4899",
      "auth_code": "084217",
      "occurred_at": "2026-08-09T10:55:02.000Z"
    }
  ],
  "next_cursor": null,
  "has_more": false
}