#!/usr/bin/env bash
# Pre-sale UOB Rewards points/voucher balance. No transaction is
# created. Branch on data.success, not response_code.
set -euo pipefail
API_BASE="${RADIUMONE_API_BASE:-https://api-sandbox.radiumone.io/gateway}"
: "${RADIUMONE_ACCESS_TOKEN:?set RADIUMONE_ACCESS_TOKEN to a Bearer access token}"
curl -sS -X POST "$API_BASE/v1/transactions/balance-inq" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $RADIUMONE_ACCESS_TOKEN" \
-d @request.json#!/usr/bin/env python3
"""Pre-sale UOB Rewards points/voucher balance. No transaction is created."""
import json
import os
from pathlib import Path
import requests
API_BASE = os.environ.get("RADIUMONE_API_BASE", "https://api-sandbox.radiumone.io/gateway")
def check_rewards_balance() -> dict:
body = json.loads((Path(__file__).parent / "request.json").read_text())
resp = requests.post(
f"{API_BASE}/v1/transactions/balance-inq",
json=body,
headers={"Authorization": f"Bearer {os.environ.get('RADIUMONE_ACCESS_TOKEN', '')}"},
timeout=30,
)
payload = resp.json()
if not resp.ok:
code = payload.get("type") or payload.get("code")
raise RuntimeError(f"balance-inq failed: {code} ({resp.status_code})")
# Branch on data.success, not response_code (a cataloged decline can still be success:true).
return payload
if __name__ == "__main__":
print(json.dumps(check_rewards_balance(), indent=2))
{
"status": "ok",
"request_id": "req_inq1005bal1a",
"data": {
"request_id": "inq-1005-balance-1",
"inquiry_type": "loyalty_balance",
"success": true,
"status": "success",
"response_code": "00",
"switch_request_id": "sw-inq-1005-balance-1",
"pools": [
{
"club_code": "UNI",
"pool_id": "pool_9a8b7c6d",
"pool_name": "UNI$",
"point_balance": 4534.56,
"balance_sign": "0",
"expiry_date": "00000000"
}
],
"vouchers": [
{
"voucher_code": "UNI10OFF",
"description": "S$10 rebate",
"pool_name": "UNI$",
"points_price": 1500,
"redeem_value": 10,
"max_redeemable": 3
}
]
}
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"instance": "<string>",
"request_id": "<string>",
"code": "<string>",
"retry_allowed": true,
"errors": [
{
"pointer": "<string>",
"parameter": "<string>",
"code": "<string>",
"detail": "<string>"
}
]
}{
"detail": "Missing or invalid Bearer token.",
"status": 401,
"title": "Authentication Required",
"type": "urn:radiumone:gateway:authentication-required"
}{
"detail": "Insufficient permissions for this operation.",
"status": 403,
"title": "Permission Denied",
"type": "urn:radiumone:gateway:permission-denied"
}{
"detail": "The requested resource does not exist.",
"status": 404,
"title": "Not Found",
"type": "urn:radiumone:gateway:not-found"
}{
"detail": "The resolved terminal cannot take this request right now -- its settlement batch is closing (`device-settling`, self-clears) or was rejected and needs an operator (`device-batch-rejected`), the terminal is not active, or the operation is disabled on it. Under the `SINGLE` device-selection strategy the request is refused rather than moved to another terminal.",
"status": 409,
"title": "Terminal Unavailable",
"type": "urn:radiumone:gateway:terminal-unavailable"
}{
"type": "urn:radiumone:loyalty:host-config-conflict",
"title": "Loyalty Host Configuration Conflict",
"status": 422,
"detail": "The loyalty host returned a pool set with a duplicate club_code/pool_id (422)."
}{
"detail": "An unexpected error occurred.",
"status": 500,
"title": "Internal Server Error",
"type": "urn:radiumone:gateway:internal-server-error"
}{
"detail": "A downstream dependency is unavailable or did not respond in time.",
"status": 503,
"title": "Service Unavailable",
"type": "urn:radiumone:gateway:service-unavailable"
}Rewards balance inquiry - Payments API
Look up a card’s UOB Rewards point balance and redeemable vouchers before offering points redemption at checkout.
#!/usr/bin/env bash
# Pre-sale UOB Rewards points/voucher balance. No transaction is
# created. Branch on data.success, not response_code.
set -euo pipefail
API_BASE="${RADIUMONE_API_BASE:-https://api-sandbox.radiumone.io/gateway}"
: "${RADIUMONE_ACCESS_TOKEN:?set RADIUMONE_ACCESS_TOKEN to a Bearer access token}"
curl -sS -X POST "$API_BASE/v1/transactions/balance-inq" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $RADIUMONE_ACCESS_TOKEN" \
-d @request.json#!/usr/bin/env python3
"""Pre-sale UOB Rewards points/voucher balance. No transaction is created."""
import json
import os
from pathlib import Path
import requests
API_BASE = os.environ.get("RADIUMONE_API_BASE", "https://api-sandbox.radiumone.io/gateway")
def check_rewards_balance() -> dict:
body = json.loads((Path(__file__).parent / "request.json").read_text())
resp = requests.post(
f"{API_BASE}/v1/transactions/balance-inq",
json=body,
headers={"Authorization": f"Bearer {os.environ.get('RADIUMONE_ACCESS_TOKEN', '')}"},
timeout=30,
)
payload = resp.json()
if not resp.ok:
code = payload.get("type") or payload.get("code")
raise RuntimeError(f"balance-inq failed: {code} ({resp.status_code})")
# Branch on data.success, not response_code (a cataloged decline can still be success:true).
return payload
if __name__ == "__main__":
print(json.dumps(check_rewards_balance(), indent=2))
{
"status": "ok",
"request_id": "req_inq1005bal1a",
"data": {
"request_id": "inq-1005-balance-1",
"inquiry_type": "loyalty_balance",
"success": true,
"status": "success",
"response_code": "00",
"switch_request_id": "sw-inq-1005-balance-1",
"pools": [
{
"club_code": "UNI",
"pool_id": "pool_9a8b7c6d",
"pool_name": "UNI$",
"point_balance": 4534.56,
"balance_sign": "0",
"expiry_date": "00000000"
}
],
"vouchers": [
{
"voucher_code": "UNI10OFF",
"description": "S$10 rebate",
"pool_name": "UNI$",
"points_price": 1500,
"redeem_value": 10,
"max_redeemable": 3
}
]
}
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"instance": "<string>",
"request_id": "<string>",
"code": "<string>",
"retry_allowed": true,
"errors": [
{
"pointer": "<string>",
"parameter": "<string>",
"code": "<string>",
"detail": "<string>"
}
]
}{
"detail": "Missing or invalid Bearer token.",
"status": 401,
"title": "Authentication Required",
"type": "urn:radiumone:gateway:authentication-required"
}{
"detail": "Insufficient permissions for this operation.",
"status": 403,
"title": "Permission Denied",
"type": "urn:radiumone:gateway:permission-denied"
}{
"detail": "The requested resource does not exist.",
"status": 404,
"title": "Not Found",
"type": "urn:radiumone:gateway:not-found"
}{
"detail": "The resolved terminal cannot take this request right now -- its settlement batch is closing (`device-settling`, self-clears) or was rejected and needs an operator (`device-batch-rejected`), the terminal is not active, or the operation is disabled on it. Under the `SINGLE` device-selection strategy the request is refused rather than moved to another terminal.",
"status": 409,
"title": "Terminal Unavailable",
"type": "urn:radiumone:gateway:terminal-unavailable"
}{
"type": "urn:radiumone:loyalty:host-config-conflict",
"title": "Loyalty Host Configuration Conflict",
"status": 422,
"detail": "The loyalty host returned a pool set with a duplicate club_code/pool_id (422)."
}{
"detail": "An unexpected error occurred.",
"status": 500,
"title": "Internal Server Error",
"type": "urn:radiumone:gateway:internal-server-error"
}{
"detail": "A downstream dependency is unavailable or did not respond in time.",
"status": 503,
"title": "Service Unavailable",
"type": "urn:radiumone:gateway:service-unavailable"
}Request
request_id is a reference for this call, echoed back in the response —
it isn’t an idempotency key; balance inquiry has no dedup or replay store,
so every call re-queries the rewards host. loyalty.card is the
card token from a tokenization session (same shape as a purchase’s card);
loyalty.amount is the sale amount the loyalty host prices the balance
against; loyalty.channel defaults to ECOMMERCE. Optional
order_reference links the inquiry to the order it belongs to, if you
already have one.
Response
pools lists the point pools available on the card (each with a signed
point_balance and an expiry_date); vouchers lists redeemable vouchers
with their points_price and redeem_value. success is the field to key
the outcome on — never response_code, which is the verbatim host code for
display and reconciliation only.
Using a redemption at checkout
To actually redeem points on a sale, pass aloyalty component on
POST /v1/transactions/purchase (Payments group, API reference tab) — see
Pay with points.
Guide and failure scenarios
See Check a rewards balance for the full guide, and Handle UOB Rewards redemption failures for what to do when nothing is redeemable or the host is unavailable.Authorizations
Bearer access token from POST /v1/auth/token. Treat it as an opaque string — do not depend on its internal encoding, which has changed before and isn't part of the contract.
Body
Request a loyalty balance inquiry before a sale.
Include the loyalty component to read the customer's balance. request_id is
the idempotency key for this inquiry.
Idempotency key for this inquiry (echoed in response).
1 - 64Optional loyalty-balance component. When present, dispatches a pre-sale loyalty balance read to the loyalty leg paired with the resolved payment acquirer.
Show child attributes
Show child attributes
Your order or cart reference for the purchase this inquiry belongs to. Forwarded to the acquirer for reconciliation; omit it when the inquiry comes before the order exists. It is not saved, so it cannot be searched on later.
128Response
Successful Response
Standard success envelope. Every successful response has this shape, with the operation's own payload under data.
The operation's result. Its shape is documented per operation; omitted on responses that carry no payload.
Show child attributes
Show child attributes
Optional human-readable note. Omitted from the response when not set, which is the case for every payment operation today. Never parse it.
Correlation ID for this HTTP request, for logs and support. Send your own in the X-Request-Id header (letters, digits and hyphens, up to 36 characters -- other characters are stripped) or the gateway generates one. This is NOT the request_id idempotency key you send in a transaction body; the two are unrelated.
Always ok on a successful (2xx) response. Errors use a different body shape entirely (RFC 9457 problem details), so branch on the HTTP status code, not on this field.