Member purchases
Read stored purchases for the current member, including their transaction and item relationships. Use transaction state when explaining payment outcome; a purchase row is not independent proof of settlement or content permission.
| Task | Operation |
|---|---|
| Read joined purchase history | List purchases |
Read the member's purchases
GET /api/v1/user/purchases
Lists this member's purchases joined to transactions and resources. The query does not limit transactions to the header’s resource. It also returns records without filtering for successful transaction statuses. Ordinary token resolution still needs its existing resource context. This is a cross-resource account read, unlike the resource-restricted transaction list.
Before you call
Establish member identity in the supplied resource; use the configured Firebase identity if applicable. Only joined records with existing transaction/resource produce items. No purchase is created by this read.
Request
GET with no body or request Content-Type. User role/inherited permission and active/unlocked member context. The controller requires user without a dedicated resource guard.
| Name | Location | Type | Requirement / default | Meaning |
|---|---|---|---|---|
resource | header | string | ordinary member context | Public resource key selecting the member session and operation context. |
token | header | string | member context | Existing Wallkit token; user role or inherited permission. |
firebase-token | header | string | Firebase-enabled context | Configured provider ID token alongside Wallkit token; see credentials. |
page | query | integer | optional, examples pass 1 | No explicit omitted-page default in the paginator call. |
limit | query | integer | optional, 10 | Page size; no universal maximum specified. |
filter | query | object, bracket fields | optional | Model-field criteria across Purchases/Resources; this action casts query filter to an array, unlike the CriteriaFilter JSON-string transport. Text substring, scalar numeric/comma-separated numeric values, booleans/dates depend on field type. |
by | query | string | optional, Purchases.id | Sort field. No order override in this action. |
sort | query | string | optional, DESC | Ordinary direction ASC/DESC. |
Results are grouped by purchase ID and default to newest ID first. Filter failures do not have a stable handler-specific error mapping; use supported fields and preserve request context rather than treating an error as an empty collection.
Result
HTTP 200 JSON items[] plus paginator. Exact purchase-list projection includes base fields, global user, ordinary transaction and conditional item expansions. Its sub_total field copies discount, not the actual payable subtotal; do not use it for amount display.
Example: inspect a recorded Pricing purchase
Use sample runtimes. Purchase 5001 belongs to this member and names Pricing 2001/transaction 4001. The purchase can come from another resource.
cURL
curl "${WALLKIT_API_BASE}/api/v1/user/purchases?page=1&limit=10" \
-H "resource: ${RESOURCE_KEY}" \
-H "token: ${USER_TOKEN}"
JavaScript
// Node.js 18+; built-in fetch.
async function main() {
const url = new URL("/api/v1/user/purchases", process.env.WALLKIT_API_BASE);
url.searchParams.set("page", "1");
url.searchParams.set("limit", "10");
const response = await fetch(url, { method: "GET", headers: {
resource: process.env.RESOURCE_KEY, token: process.env.USER_TOKEN
}});
console.log(response.status, await response.json());
}
main().catch(console.error);
Python
# Python 3; standard library only.
import json
import os
from urllib.error import HTTPError
from urllib.parse import urlencode, urljoin
from urllib.request import Request, urlopen
url = urljoin(os.environ["WALLKIT_API_BASE"], "/api/v1/user/purchases") + "?" + urlencode({'page': '1', 'limit': '10'})
headers = {"resource": os.environ["RESOURCE_KEY"], "token": os.environ["USER_TOKEN"]}
request = Request(url, headers=headers, method="GET")
try:
with urlopen(request) as response:
print(response.status, json.load(response))
except HTTPError as error:
print(error.code, json.load(error))
HTTP 200 response excerpt:
{"items":[{"id":5001,"item_type":"subscription","item_key":"2001","item_id":2001,"price":1200,"discount":0,"sub_total":0,"currency":"USD","renewal":false,"transaction":{"id":4001,"status":"succeeded","amount":1200,"currency":"USD"},"relation_model":"user_plan_relationships","relation_id":6001}]}
The zero sub_total here reflects the projection's copied discount, not a free transaction. The excerpt omits user/item/relation and conditional Pricing details defined in the field page. Inspect transaction.id/status/amount, then current membership/access separately.
Consequential alternate: empty history
HTTP 200 excerpt:
{"items":[]}
No joined records match this member/filter selection. Check filters before describing the member as never having purchased; missing joined records can affect visibility.
Recovery
| HTTP | Code / response | Cause | Next action |
|---|---|---|---|
| 401 | auth_failed / auth_access_fail | Identity/context restrictions. | Check existing member session/resource or administrator restrictions. |
| 200 | items:[] | No matching joined history. | Check filters and selected account; show an empty state, not a payment failure. |
Next task
Use nested transaction.id for transaction detail and read memberships for current state. Request content access before serving an article.