Wallet Transactions API

Read the history behind your advocates’ wallet balances: every credit, debit and reset, with the balance it left behind, who made it, and what earned it. The current balances are on the advocate record; this is how they got there.

Requires the wallet_transactions permission. The balances on the advocate record only need advocates, but the history also carries the reasons admins write, so it has a permission of its own.

Endpoint Returns
GET /api/v1/wallet_transactions A paginated list of wallet transactions
GET /api/v1/wallet_transactions/:id One wallet transaction

List wallet transactions

GET https://integrations.stokedhq.com/api/v1/wallet_transactions

With no filters, the list contains every transaction on every wallet in your community, deactivated advocates included. Transactions are never edited after they are made, so updated_at is the time the transaction happened.

Parameters

Parameter Description
filter[advocate] Only transactions on this advocate’s wallets, by advocate id
filter[created_since] Only transactions made at or after this time
filter[updated_since] The same as filter[created_since], since transactions never change. Use it for incremental syncing like on every other endpoint.
page[size] Records per page. Defaults to 50, maximum 200.
page[after] The cursor from a previous response’s links.next. See Pagination.
page[number] A page to jump to. Defaults to 1.

An advocate id that doesn’t belong to your community returns a 400 error rather than an empty list. Any other parameter returns 400. Transactions come back oldest first.

Request

GET /api/v1/wallet_transactions

cURL

curl -G "https://integrations.stokedhq.com/api/v1/wallet_transactions" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/vnd.api+json" \
--data-urlencode "filter[updated_since]=2026-09-01T00:00:00Z"

Ruby

require "net/http"
require "json"
uri = URI("https://integrations.stokedhq.com/api/v1/wallet_transactions")
uri.query = URI.encode_www_form("filter[updated_since]" => "2026-09-01T00:00:00Z")
request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer YOUR_API_KEY"
request["Accept"] = "application/vnd.api+json"
response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(request) }
raise "HTTP #{response.code}: #{response.body}" unless response.is_a?(Net::HTTPSuccess)
puts JSON.parse(response.body)["data"]

Python

import requests
response = requests.get(
"https://integrations.stokedhq.com/api/v1/wallet_transactions",
headers={
"Authorization": "Bearer YOUR_API_KEY",
"Accept": "application/vnd.api+json",
},
params={"filter[updated_since]": "2026-09-01T00:00:00Z"},
)
response.raise_for_status()
print(response.json()["data"])

C#

using System.Net.Http.Headers;
using System.Text.Json;
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "YOUR_API_KEY");
client.DefaultRequestHeaders.Accept.ParseAdd("application/vnd.api+json");
using var response = await client.GetAsync("https://integrations.stokedhq.com/api/v1/wallet_transactions?filter[updated_since]=2026-09-01T00:00:00Z");
response.EnsureSuccessStatusCode();
using var document = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
Console.WriteLine(document.RootElement.GetProperty("data"));

JavaScript

const url = new URL("https://integrations.stokedhq.com/api/v1/wallet_transactions");
url.searchParams.set("filter[updated_since]", "2026-09-01T00:00:00Z");
const response = await fetch(url, {
headers: {
Authorization: "Bearer YOUR_API_KEY",
Accept: "application/vnd.api+json",
},
});
if (!response.ok) throw new Error(`HTTP ${response.status}: ${await response.text()}`);
const { data } = await response.json();
console.log(data);

Response

Response wallet-transactions-index.json Download
{
"data": [
{
"type": "wallet_transactions",
"id": "01k5examplewallettxn000001",
"attributes": {
"kind": "credit",
"amount": 25.0,
"balance_after": 150.0,
"lifetime_after": 325.0,
"currency_code": "PTS",
"wallet_id": "01k5examplewallet000000001",
"reason": "Test ride completed",
"automatic": true,
"created_at": "2026-09-06T18:00:00Z",
"updated_at": "2026-09-06T18:00:00Z"
},
"relationships": {
"advocate": {
"data": {
"type": "advocates",
"id": "01k5exampleadv0cate0000001"
},
"links": {
"related": "https://integrations.stokedhq.com/api/v1/advocates/01k5exampleadv0cate0000001"
}
},
"performed_by": {
"data": null
},
"subject": {
"data": {
"type": "conversations",
"id": "01k5examplec0nversat10n001"
},
"links": {
"related": "https://integrations.stokedhq.com/api/v1/conversations/01k5examplec0nversat10n001"
}
}
},
"links": {
"self": "https://integrations.stokedhq.com/api/v1/wallet_transactions/01k5examplewallettxn000001"
}
},
{
"type": "wallet_transactions",
"id": "01k5examplewallettxn000002",
"attributes": {
"kind": "debit",
"amount": 50.0,
"balance_after": 100.0,
"lifetime_after": 325.0,
"currency_code": "PTS",
"wallet_id": "01k5examplewallet000000001",
"reason": "Redeemed for a Squad hoodie",
"automatic": false,
"created_at": "2026-09-12T10:00:00Z",
"updated_at": "2026-09-12T10:00:00Z"
},
"relationships": {
"advocate": {
"data": {
"type": "advocates",
"id": "01k5exampleadv0cate0000001"
},
"links": {
"related": "https://integrations.stokedhq.com/api/v1/advocates/01k5exampleadv0cate0000001"
}
},
"performed_by": {
"data": {
"type": "admins",
"id": "01k5exampleadm1n0000000001"
}
},
"subject": {
"data": null
}
},
"links": {
"self": "https://integrations.stokedhq.com/api/v1/wallet_transactions/01k5examplewallettxn000002"
}
}
],
"links": {
"self": "https://integrations.stokedhq.com/api/v1/wallet_transactions?filter%5Bupdated_since%5D=2026-09-01T00%3A00%3A00Z&page%5Bnumber%5D=1&page%5Bsize%5D=50",
"first": "https://integrations.stokedhq.com/api/v1/wallet_transactions?filter%5Bupdated_since%5D=2026-09-01T00%3A00%3A00Z&page%5Bnumber%5D=1&page%5Bsize%5D=50",
"prev": null,
"next": null,
"last": "https://integrations.stokedhq.com/api/v1/wallet_transactions?filter%5Bupdated_since%5D=2026-09-01T00%3A00%3A00Z&page%5Bnumber%5D=1&page%5Bsize%5D=50"
},
"meta": {
"page": 1,
"per_page": 50,
"total_count": 2,
"total_pages": 1,
"wallets": [
{
"id": "01k5examplewallet000000001",
"name": "Squad Points",
"unit_name": "points",
"currency_code": "PTS"
}
]
}
}

Get a wallet transaction

GET https://integrations.stokedhq.com/api/v1/wallet_transactions/:id

Returns the same record as the list. An ID that doesn’t exist in your community returns 404.

GET /api/v1/wallet_transactions/01k5examplewallettxn000001

cURL

curl "https://integrations.stokedhq.com/api/v1/wallet_transactions/01k5examplewallettxn000001" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/vnd.api+json"

Ruby

require "net/http"
require "json"
uri = URI("https://integrations.stokedhq.com/api/v1/wallet_transactions/01k5examplewallettxn000001")
request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer YOUR_API_KEY"
request["Accept"] = "application/vnd.api+json"
response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(request) }
raise "HTTP #{response.code}: #{response.body}" unless response.is_a?(Net::HTTPSuccess)
puts JSON.parse(response.body)["data"]

Python

import requests
response = requests.get(
"https://integrations.stokedhq.com/api/v1/wallet_transactions/01k5examplewallettxn000001",
headers={
"Authorization": "Bearer YOUR_API_KEY",
"Accept": "application/vnd.api+json",
},
)
response.raise_for_status()
print(response.json()["data"])

C#

using System.Net.Http.Headers;
using System.Text.Json;
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "YOUR_API_KEY");
client.DefaultRequestHeaders.Accept.ParseAdd("application/vnd.api+json");
using var response = await client.GetAsync("https://integrations.stokedhq.com/api/v1/wallet_transactions/01k5examplewallettxn000001");
response.EnsureSuccessStatusCode();
using var document = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
Console.WriteLine(document.RootElement.GetProperty("data"));

JavaScript

const url = new URL("https://integrations.stokedhq.com/api/v1/wallet_transactions/01k5examplewallettxn000001");
const response = await fetch(url, {
headers: {
Authorization: "Bearer YOUR_API_KEY",
Accept: "application/vnd.api+json",
},
});
if (!response.ok) throw new Error(`HTTP ${response.status}: ${await response.text()}`);
const { data } = await response.json();
console.log(data);

Attributes

Records with "type": "wallet_transactions".

Attribute Type Description
kind string credit (points added), debit (points spent or removed), or reset (an admin set the balance and lifetime directly)
amount number or null How much was credited or debited, in whole units: 25.0 is 25 points, or $25.00 in a cash wallet. Always positive. null for a reset, which sets the totals instead.
balance_after number The wallet’s balance right after this transaction
lifetime_after number The wallet’s lifetime total right after this transaction. A debit leaves it unchanged.
currency_code string PTS for a points wallet, or an ISO 4217 code (USD, CAD) for a cash wallet
wallet_id string Which wallet: its entry in meta.wallets, and the same id as in the advocate’s wallets array.
reason string The reason shown to the advocate, such as Test ride completed. Free text written by an admin or by the reward that made the credit.
automatic boolean true when Stoked made the transaction itself (an auto-approved reward, for example), false when an admin did
created_at timestamp When the transaction happened
updated_at timestamp The same as created_at

Every response carries the community’s wallets in its top-level meta.wallets: an array of {id, name, unit_name, currency_code}, one per wallet, in Settings order. Look up a transaction’s wallet_id there to show 25 Squad Points without fetching an advocate.

To rebuild a wallet’s balance on any date, take the balance_after of its last transaction before that date. For transactions made before this endpoint launched in October 2026, balance_after and lifetime_after were worked out afterwards by replaying the wallet’s history in order.


Relationships

Relationship Type Description
advocate advocates The advocate whose wallet it is
performed_by admins The admin who made the transaction. null when automatic is true.
subject conversations, private_events, prospects, … What the reward was for, when the transaction came from an approved reward (or its reversal) about a record the API serves: for a test ride reward, usually the conversation. null for transactions an admin entered by hand and for resets.

A relationship carries only a type, id and link. Admins have no endpoint, so an admins identifier has no link. Following a link needs the matching permission: the link is a pointer, not a grant.


Keeping a copy in sync

  1. On the first run, follow links.next through everything and upsert each transaction by id
  2. Remember the newest updated_at you received
  3. On the next run, pass it as filter[updated_since], follow links.next to the end, and upsert each transaction by id

© 2024-2026 Stoked — Real conversations. Real trust.