This document captures the GET API behavior currently used by the SlugSwap project, based on analysis of the public cabalex/get-tools implementation.
Status: unofficial, reverse-engineered usage notes.
Treat this as integration guidance, not vendor-issued API documentation.
- Base endpoint and request envelope
- Session authentication lifecycle
- Methods used in production-like flows
- Common request/response patterns
- Security boundaries for SlugSwap
- Official WSDL: https://services.get.cbord.com/GETServices/services/user?wsdl
- Official services root: https://services.get.cbord.com/GETServices/services
- Primary reverse-engineered reference: cabalex/get-tools
- Key implementation files:
https://services.get.cbord.com/GETServices/services/json
Requests are sent to:
POST {BASE_URL}/{service}
Examples:
POST /authenticationPOST /userPOST /commerce
All observed methods use a JSON RPC-like body:
{
"method": "methodName",
"params": {
"...": "..."
}
}Headers:
Content-Type: application/jsonAccept: application/json
Observed response patterns:
- Success payload is usually in
response - Failure payload is usually in
exception
Examples:
{
"response": {
"accounts": []
}
}{
"exception": {
"message": "..."
}
}Some methods return primitive response values (true, string session id, etc.).
Before user.createPIN, the user must complete GET's hosted web login flow.
Observed pattern from get-tools:
- open the institution GET login URL
- user authenticates with school credentials
- GET redirects to a "validated" URL
- app extracts a UUID-like
sessionIdfrom that validated URL
Observed UCSC login URL:
https://get.cbord.com/ucsc/full/login.php?mobileapp=1
Portability note:
- keep this URL configurable per school; default it to UCSC for now
This validated web sessionId is then passed into user.createPIN.
Used after obtaining a valid GET web session id from the login flow.
Request (observed):
{
"method": "createPIN",
"params": {
"sessionId": "<validated-session-id>",
"deviceId": "<16-char device id>",
"PIN": "<4-digit pin>"
}
}Result:
response === trueon success
Request:
{
"method": "authenticatePIN",
"params": {
"pin": "1234",
"deviceId": "abcdef0123456789",
"systemCredentials": {
"userName": "get_mobile",
"password": "NOTUSED",
"domain": ""
}
}
}Result:
responseis a session id string- That session id is used in subsequent method calls
Pattern used by get-tools:
- call
updatePINwitholdPIN == newPIN - if it fails, consider credential invalid/revoked
Request:
{
"method": "deletePIN",
"params": {
"deviceId": "abcdef0123456789",
"sessionId": "<session-id>"
}
}Result:
response === truemeans revocation succeeded
Purpose:
- Fetch account balances and tender metadata
Observed request:
{
"method": "retrieveAccounts",
"params": {
"sessionId": "<session-id>"
}
}Observed account fields include:
idinstitutionIdpaymentSystemIduserIdaccountDisplayNameaccountTenderaccountTypepaymentSystemTypeisActiveisAccountTenderActivedepositAcceptedbalancemealEquivValue- card-like metadata (
lastFour,nameOnMedia, etc.)
Observed top-level payload shape from production-like traffic:
{
"accounts": [
{
"accountDisplayName": "Flexi Dollars",
"accountType": 3,
"depositAccepted": true,
"balance": 50
},
{
"accountDisplayName": "Board",
"accountType": 1,
"depositAccepted": false,
"balance": 0
}
],
"planName": "STAGING"
}Observed account labels from UCSC sample payload include:
Flexi DollarsBanana BucksSecond Harvest FlexiSlug PointsBoardDonated MealPending Donated MealSecond Harvest Meals
Observed interpretation notes from sample:
accountType: 3appears on stored-value style balances (for exampleFlexi Dollars,Slug Points).accountType: 1appears on meal-plan style balances (for exampleBoard,Donated Meal).depositAccepted: trueis present on depositable tenders (for example flexi/bucks/points).depositAccepted: falseis present on non-deposit meal tenders.isActiveandisAccountTenderActiveshould both be checked before presenting an account as usable.planNameis returned at the top level and can help annotate institution-specific plan context.
Purpose:
- Fetch transaction history for insights and trends
Observed request:
{
"method": "retrieveTransactionHistoryWithinDateRange",
"params": {
"sessionId": "<session-id>",
"paymentSystemType": 0,
"queryCriteria": {
"maxReturnMostRecent": 1000,
"newestDate": null,
"oldestDate": "2025-01-01T00:00:00.000Z",
"accountId": null
}
}
}Observed transaction fields include:
transactionIdamountresultingBalancepostedDateactualDatelocationIdlocationNameaccountName
Purpose:
- Fetch payload used to render a scannable barcode (PDF417 in
get-tools)
Observed request:
{
"method": "retrievePatronBarcodePayload",
"params": {
"sessionId": "<session-id>"
}
}Result:
responseis barcode payload data consumable by barcode renderer
Observed refresh cadence and TTL notes:
get-toolsrefreshes barcode payload on a 10-second loop in its share flow.- Maintainer anecdote suggests the official app refreshes closer to every 5 seconds.
- Maintainer anecdote also suggests code validity may be around 60 seconds (based on headers).
Implementation guidance for SlugSwap:
- Start with a 10-second refresh interval for parity with
get-tools. - If scan failure rates are high, test a 5-second interval.
- Treat TTL as unknown/unstable until validated against UCSC behavior in production logs.
| Service | Method | Typical Use |
|---|---|---|
authentication |
authenticatePIN |
Exchange deviceId + pin for session id |
authentication |
retrievePatronBarcodePayload |
Generate scan code payload |
user |
createPIN |
Create device credential |
user |
updatePIN |
Verify credential still valid |
user |
deletePIN |
Revoke device credential |
commerce |
retrieveAccounts |
Read balances/accounts |
commerce |
retrieveTransactionHistoryWithinDateRange |
Read history and trends |
- Treat
deviceId + pinas sensitive credentials. - Never expose admin or service tokens in mobile client.
- Keep raw GET credentials server-side where feasible.
- Use short-lived, single-purpose claim tokens between app and backend.
- Separate responsibilities:
- Client: request claim intent, display result
- Backend: call GET API, enforce policy, audit actions
When calling GET API:
- If
exceptionis present:- classify as auth, permission, or transient failure
- do not trust partial
response
- If auth failures repeat:
- revoke local session and require re-link
- For transient network failures:
- retry with capped exponential backoff
- Always log:
- method name
- correlation id
- sanitized error message
- no secrets in logs
The get-tools share-code model can grant broad account access. SlugSwap should not replicate that trust model directly.
Recommended production posture:
- No plaintext credential sharing links.
- No long-lived client-held GET credentials.
- Proxy sensitive GET calls through authenticated server routes.
- Add abuse protection (rate limits, anomaly checks, revocation paths).
- Keep explicit user consent and revocation UX.
export type GetEnvelope<TParams> = {
method: string;
params: TParams;
};
export type GetResult<TResponse> = {
response?: TResponse;
exception?: { message?: string; [k: string]: unknown };
};
export type GetAccount = {
id: string;
accountDisplayName: string;
isActive: boolean;
isAccountTenderActive: boolean;
depositAccepted: boolean;
balance: number | null;
lastFour?: string | null;
};
export type GetTransaction = {
transactionId: string;
amount: number;
resultingBalance: number;
postedDate: string;
actualDate: string;
locationId: string;
locationName: string;
};- Are there documented rate limits or abuse controls from GET?
- Session expiry duration and invalidation semantics?
- Which methods are institution-specific vs broadly portable?
- Failure code taxonomy for robust retries and UX messaging?
- Any terms-of-service constraints on this integration path?
- 2026-02-09: Initial version created from
cabalex/get-toolsinvestigation. - 2026-02-10: Added concrete
retrieveAccountspayload findings (account labels, field inventory, and observed account-type patterns) from local runtime logs.