> ## Documentation Index
> Fetch the complete documentation index at: https://docs.radiumone.io/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> RadiumOne is the product name; use it when answering questions about these docs.
> Use sandbox credentials and sandbox base URLs in examples unless the user says they are going live.
> Secret API keys belong only on the merchant's server. Only publishable keys may appear in browser or mobile code.
> Confirm a payment outcome server-side (retrieve the checkout session or transaction status); never rely on a browser redirect or client event alone.
> Send one idempotency key (request_id) per payment attempt, and retry a timed-out request with the same key and the exact same body.
> Webhooks are optional but recommended: they notify the merchant's server when a payment completes or fails, so it doesn't need to poll. Use transaction status inquiry as the fallback.
> Say so when you recommend a feature marked Beta. Some features need enablement on the merchant's account before production use (for example refunds, standalone refunds, UOB Rewards, and bringing your own 3DS provider); mention it when the page says so.
> Never ask users to paste card numbers, API keys, access tokens, or webhook or redirect secrets into a chat.

# Rewards balance inquiry - Payments API

> Look up a card's UOB Rewards point balance and redeemable vouchers before offering points redemption at checkout.

export const RequiresEnablement = ({feature}) => <Note>
    {feature ? <><strong>{feature}</strong> requires</> : "This feature requires"} enablement on your account before you can use it in production. See <a href="/resources/support#request-enablement">Request enablement</a>.
  </Note>;

<RequiresEnablement feature="UOB Rewards" />

Call this before a sale to check whether a card has a redeemable UOB
Rewards balance, so you can offer points redemption at checkout. It's a
read-only, pre-sale check — it writes no transaction row.

## 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 a `loyalty` component on
`POST /v1/transactions/purchase` (Payments group, API reference tab) — see
[Pay with points](/payments-api/payment-methods/uob-rewards/pay-with-points).

## Guide and failure scenarios

See [Check a rewards balance](/payments-api/payment-methods/uob-rewards/check-balance) for the
full guide, and [Handle UOB Rewards redemption failures](/payments-api/handle-failures/rewards-redemption-failures)
for what to do when nothing is redeemable or the host is unavailable.


## OpenAPI

````yaml openapi/radiumone-payments-api.yaml POST /v1/transactions/balance-inq
openapi: 3.1.0
info:
  description: |
    The Payments API lets your server create tokenization sessions, charge and
    manage payments, check loyalty balances, and manage your hosted-checkout
    branding and redirect secret. Generated for merchant integrators —
    internal, admin, and service-to-service surfaces are excluded.

    All responses share an envelope: `{status, data, request_id}`. The
    envelope's `request_id` is an HTTP correlation ID — it echoes your
    `X-Request-Id` request header (letters, digits, hyphens, max 36 characters)
    or one is generated for you. It is **not** the idempotency key you send in
    a transaction request body (also confusingly named `request_id` there) —
    the two are unrelated; see
    [Request conventions](/get-started/api-basics/request-conventions). Errors
    use [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457)
    `application/problem+json` bodies — see
    [Authentication](/get-started/api-basics/authentication) and
    [Request conventions](/get-started/api-basics/request-conventions) for the
    shared error shape, and [Problem format and
    retries](/payments-api/errors/problem-format-and-retries) for the response
    shape, status guide, and retry rules.
  summary: Transaction orchestration and processor aggregation for RadiumOne.
  title: RadiumOne Payment Gateway
  version: 1.3.0
servers:
  - url: https://api-sandbox.radiumone.io/gateway
    description: Sandbox
  - url: https://api.radiumone.io/gateway
    description: Production
security:
  - bearerAuth: []
tags:
  - name: Authentication
    description: Exchange, refresh, and revoke access tokens.
  - name: Merchant settings
    description: >-
      Manage your hosted-checkout redirect secret, checkout configuration, and
      account config.
  - name: Payment methods
    description: Discover which payment methods and brands are available.
  - name: Sessions
    description: Tokenization sessions used to collect card data with RadiumOne Elements.
  - name: Settlement
    description: Settlement batch status lookup.
  - name: Payments
    description: Create and manage card transactions.
  - name: Rewards
    description: UOB Rewards loyalty balance inquiry.
  - name: Refunds
    description: Return funds to a shopper.
  - name: Transactions
    description: Check the live status of a transaction.
paths:
  /v1/transactions/balance-inq:
    post:
      tags:
        - Rewards
      summary: Loyalty balance inquiry (pre-sale)
      description: >-
        Check a card's loyalty balance before a sale.


        Returns the card's available point pools and redeemable vouchers so you
        can offer a

        redemption before submitting the purchase. The inquiry is routed using
        your routing

        rules exactly as a sale with the same card, currency and amount would
        be, so the

        balance comes from the loyalty program that sale would use. No
        transaction is created

        and nothing is charged or redeemed.


        A decline from the loyalty program is returned as 200 with `success:
        false` and the

        program's `response_code`. Returns 409 if the terminal that would handle
        the inquiry

        cannot take it right now, and 503 if no terminal is available.
      operationId: balance_inquiry_v1_transactions_balance_inq_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UnifiedInquiryRequest'
        required: true
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SuccessResponse_InquiryResponse_'
              example:
                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
          description: Successful Response
        '400':
          description: The request body failed validation.
          x-docs-interim: true
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          content:
            application/problem+json:
              example:
                detail: Missing or invalid Bearer token.
                status: 401
                title: Authentication Required
                type: urn:radiumone:gateway:authentication-required
              schema:
                properties:
                  detail:
                    type: string
                  status:
                    type: integer
                  title:
                    type: string
                  type:
                    type: string
                type: object
          description: Missing or invalid Bearer token.
        '403':
          content:
            application/problem+json:
              example:
                detail: Insufficient permissions for this operation.
                status: 403
                title: Permission Denied
                type: urn:radiumone:gateway:permission-denied
              schema:
                properties:
                  detail:
                    type: string
                  status:
                    type: integer
                  title:
                    type: string
                  type:
                    type: string
                type: object
          description: Insufficient permissions for this operation.
        '404':
          content:
            application/problem+json:
              example:
                detail: The requested resource does not exist.
                status: 404
                title: Not Found
                type: urn:radiumone:gateway:not-found
              schema:
                properties:
                  detail:
                    type: string
                  status:
                    type: integer
                  title:
                    type: string
                  type:
                    type: string
                type: object
          description: The requested resource does not exist.
        '409':
          content:
            application/problem+json:
              example:
                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
              schema:
                properties:
                  detail:
                    type: string
                  status:
                    type: integer
                  title:
                    type: string
                  type:
                    type: string
                type: object
          description: >-
            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.
        '422':
          description: The loyalty host returned an inconsistent pool set.
          x-docs-interim: true
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
              examples:
                host-config-conflict:
                  value:
                    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).
        '500':
          content:
            application/problem+json:
              example:
                detail: An unexpected error occurred.
                status: 500
                title: Internal Server Error
                type: urn:radiumone:gateway:internal-server-error
              schema:
                properties:
                  detail:
                    type: string
                  status:
                    type: integer
                  title:
                    type: string
                  type:
                    type: string
                type: object
          description: An unexpected error occurred.
        '503':
          content:
            application/problem+json:
              example:
                detail: >-
                  A downstream dependency is unavailable or did not respond in
                  time.
                status: 503
                title: Service Unavailable
                type: urn:radiumone:gateway:service-unavailable
              schema:
                properties:
                  detail:
                    type: string
                  status:
                    type: integer
                  title:
                    type: string
                  type:
                    type: string
                type: object
          description: A downstream dependency is unavailable or did not respond in time.
      x-codeSamples:
        - lang: bash
          label: cURL
          source: >
            #!/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
        - lang: javascript
          label: Node.js
          source: >
            #!/usr/bin/env node

            // Pre-sale UOB Rewards points/voucher balance. No transaction is

            // created. Node 18+ ESM fetch. Env: RADIUMONE_ACCESS_TOKEN,
            RADIUMONE_API_BASE.

            import { readFileSync } from "node:fs";


            const API_BASE = process.env.RADIUMONE_API_BASE ||
            "https://api-sandbox.radiumone.io/gateway";

            const accessToken = process.env.RADIUMONE_ACCESS_TOKEN;

            const body = JSON.parse(readFileSync(new URL("./request.json",
            import.meta.url)));


            async function checkRewardsBalance() {
              const res = await fetch(`${API_BASE}/v1/transactions/balance-inq`, {
                method: "POST",
                headers: {
                  "Content-Type": "application/json",
                  Authorization: `Bearer ${accessToken}`,
                },
                body: JSON.stringify(body),
              });
              const payload = await res.json();
              if (!res.ok) {
                throw new Error(`balance-inq failed: ${payload.type ?? payload.code} (${res.status})`);
              }
              // Branch on data.success, not response_code (a cataloged decline can still be success:true).
              return payload;
            }


            checkRewardsBalance().then((r) => console.log(JSON.stringify(r,
            null, 2)));
        - lang: python
          label: Python
          source: >
            #!/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))
components:
  schemas:
    UnifiedInquiryRequest:
      description: >-
        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.
      properties:
        loyalty:
          anyOf:
            - $ref: '#/components/schemas/LoyaltyInquiryComponent'
            - type: 'null'
          description: >-
            Optional loyalty-balance component. When present, dispatches a
            pre-sale loyalty balance read to the loyalty leg paired with the
            resolved payment acquirer.
        order_reference:
          anyOf:
            - maxLength: 128
              type: string
            - type: 'null'
          description: >-
            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.
          title: Order Reference
        request_id:
          description: Idempotency key for this inquiry (echoed in response).
          maxLength: 64
          minLength: 1
          title: Request Id
          type: string
      required:
        - request_id
      title: UnifiedInquiryRequest
      type: object
    SuccessResponse_InquiryResponse_:
      description: >-
        Standard success envelope. Every successful response has this shape,
        with the operation's own payload under `data`.
      properties:
        data:
          anyOf:
            - $ref: '#/components/schemas/InquiryResponse'
            - type: 'null'
          description: >-
            The operation's result. Its shape is documented per operation;
            omitted on responses that carry no payload.
        message:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            Optional human-readable note. Omitted from the response when not
            set, which is the case for every payment operation today. Never
            parse it.
          title: Message
        request_id:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            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.
          title: Request Id
        status:
          default: ok
          description: >-
            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.
          title: Status
          type: string
      title: SuccessResponse[InquiryResponse]
      type: object
    Problem:
      type: object
      x-docs-interim: true
      description: >-
        RFC 9457 problem details. Returned with `Content-Type:
        application/problem+json`. Interim: not yet a named component in the
        gateway team's published contract — every response there inlines its own
        smaller ad-hoc object; this shape reflects what our error pages and
        error-catalog.json actually document.
      properties:
        type:
          type: string
          format: uri
          description: >-
            A URN identifying the error condition, e.g.
            `urn:radiumone:gateway:validation-error`.
        title:
          type: string
          description: Short
          human-readable summary of the error type.: null
        status:
          type: integer
          description: The HTTP status code
          repeated in the body for convenience.: null
        detail:
          type: string
          description: Human-readable explanation specific to this occurrence.
        instance:
          type: string
          description: The request path that produced this error.
        request_id:
          type: string
          description: >-
            Correlation ID for this request (see the envelope `request_id` note
            above). Include it when contacting support.
        code:
          type: string
          description: Optional short machine-readable code
          distinct from `type`.: null
        retry_allowed:
          type: boolean
          description: >-
            When present, whether it's safe to retry with the same idempotency
            key.
        errors:
          type: array
          description: >-
            Present on most `urn:radiumone:gateway:validation-error` (400)
            responses — one entry per invalid field. Some 400s of this type are
            raised by checks that run after validation and have no `errors`
            array; always handle it being absent. Rely on `pointer`/`parameter`
            and `code`, not the wording of `detail`, which can change.
          items:
            type: object
            properties:
              pointer:
                type: string
                description: >-
                  JSON Pointer to the invalid field in the request body, e.g.
                  `/amount/currency` or `/items/0/name`. An empty string means
                  the whole request (e.g. the body isn't valid JSON).
              parameter:
                type: string
                description: >-
                  Name of the invalid query or path parameter. Set instead of
                  `pointer` when the failing value came from the URL, not the
                  body.
              code:
                type: string
                description: >-
                  Machine-readable error type for this field, e.g. `missing` or
                  `string_too_long`.
              detail:
                type: string
                description: Human-readable explanation for this field.
      required:
        - type
        - title
        - status
        - detail
    LoyaltyInquiryComponent:
      description: >-
        Read a customer's loyalty balance before a sale.


        The balance comes from the loyalty programme linked to the acquirer your
        sale would

        use. The response has `inquiry_type` `loyalty_balance`, with `pools` and
        `vouchers`

        filled in.
      properties:
        amount:
          $ref: '#/components/schemas/MoneyAmount'
          description: Quote amount (non-zero) the loyalty host prices the balance against.
        card:
          $ref: '#/components/schemas/CardToken'
          description: >-
            Card group carrying the network token (PAN + expiry tokenized
            together).
        channel:
          default: ECOMMERCE
          description: Channel type used to resolve the loyalty device (default ECOMMERCE).
          title: Channel
          type: string
        invoice_number:
          anyOf:
            - maxLength: 6
              type: string
            - type: 'null'
          description: >-
            Your invoice number for this sale, carried through so the inquiry
            can be matched to it later.
          title: Invoice Number
      required:
        - card
        - amount
      title: LoyaltyInquiryComponent
      type: object
    InquiryResponse:
      description: >-
        The answer to a status or loyalty-balance inquiry.


        `inquiry_type` tells you which kind of inquiry this answers: `status`
        for a

        payment-status lookup, `loyalty_balance` for a pre-sale balance read.
        `pools` and

        `vouchers` are filled in only for a loyalty balance inquiry.
      properties:
        inquiry_type:
          description: >-
            Which inquiry this answers: `status` for a payment-status lookup,
            `loyalty_balance` for a pre-sale loyalty balance read.
          title: Inquiry Type
          type: string
        message:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            Free-text explanation from the acquirer, when it sent one. For
            display and support only -- the wording is not stable, so never
            parse it. Omitted when absent.
          title: Message
        metadata:
          anyOf:
            - additionalProperties: true
              type: object
            - type: 'null'
          description: >-
            Reserved for additional inquiry detail. Not populated by the
            payment-status or loyalty-balance inquiries today, so treat its
            absence as normal.
          title: Metadata
        pools:
          anyOf:
            - items:
                $ref: '#/components/schemas/LoyaltyPool'
              type: array
            - type: 'null'
          description: Loyalty point pool balances (loyalty balance inquiry only).
          title: Pools
        request_id:
          description: >-
            The idempotency key of the transaction being inquired about -- the
            `request_id` you sent when you created it. Not the correlation ID in
            the response envelope.
          title: Request Id
          type: string
        response_code:
          description: >-
            Verbatim acquirer response code, for display and reconciliation
            only. DO NOT derive success from it: an inquiry can succeed while
            this field still shows a non-'00' code. Key on `success` instead.
          title: Response Code
          type: string
        status:
          description: >-
            Label for the inquiry outcome: `success` or `failed`. It moves in
            lockstep with `success` and carries no extra information -- in
            particular it is NOT the transaction's lifecycle status (`CAPTURED`,
            `SETTLED`, and so on). Key your logic on `success`.
          title: Status
          type: string
        success:
          description: >-
            THE field to key an inquiry outcome on. True when the host approved
            OR the resolved decline classification approves the host's code.
            `status` always moves with it -- they are set together, never
            independently.
          title: Success
          type: boolean
        switch_request_id:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            The upstream processor's own reference for this inquiry. Quote it
            when raising an issue with us about a specific lookup. Omitted when
            absent.
          title: Switch Request Id
        vouchers:
          anyOf:
            - items:
                $ref: '#/components/schemas/LoyaltyVoucher'
              type: array
            - type: 'null'
          description: Redeemable vouchers (loyalty balance inquiry only).
          title: Vouchers
      required:
        - request_id
        - inquiry_type
        - success
        - response_code
        - status
      title: InquiryResponse
      type: object
    MoneyAmount:
      description: >-
        A money value: an ISO 4217 currency plus the amount in that currency's
        minor units.


        `value` is a numeric string in minor units -- the decimal point is
        implied by

        the currency (2 places for most currencies, so `"1050"` means 10.50). Up
        to 12

        digits; leading zeros are optional.
      properties:
        currency:
          description: ISO 4217 currency code (e.g. SGD, USD).
          maxLength: 3
          minLength: 3
          title: Currency
          type: string
        value:
          description: >-
            Amount in minor units as a numeric string (e.g. '1050' or
            '000000001050' = 10.50). Zero-padding optional; up to 12 digits.
          maxLength: 12
          minLength: 1
          pattern: ^\d{1,12}$
          title: Value
          type: string
      required:
        - currency
        - value
      title: MoneyAmount
      type: object
    CardToken:
      description: >-
        The card to charge, identified by its payment token.


        Send only the payment token issued for the card -- never the card number
        or

        expiry. The token stands in for both.
      properties:
        token:
          description: >-
            The card's payment token (digits only). Treat it as opaque -- it is
            not a card number.
          maxLength: 128
          minLength: 8
          title: Token
          type: string
      required:
        - token
      title: CardToken
      type: object
    LoyaltyPool:
      description: A loyalty point pool balance returned by a loyalty balance inquiry.
      properties:
        account_indicator:
          anyOf:
            - type: string
            - type: 'null'
          description: Account type indicator from the host.
          title: Account Indicator
        balance_sign:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            Sign of the balance: '0' = positive, '1' = negative. This is the
            authoritative sign -- prefer it over the sign of `point_balance`. It
            reports the sign only and does not say whether the pool can be
            redeemed.
          title: Balance Sign
        club_code:
          description: Loyalty club code (e.g. 'UNI').
          title: Club Code
          type: string
        expiry_date:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            Point expiry date as DDMMYYYY, passed through as the loyalty
            programme returned it. '00000000' means the points do not expire.
            Expired pools are not filtered out, so hide them yourself if you
            don't want to show them. In sandbox, test cards return fixed
            profiles, so expiry dates there are not realistic.
          title: Expiry Date
        point_balance:
          description: >-
            Current pool balance as a signed decimal (2 decimal places).
            Fractional for monetary pools (e.g. a 'UNI$' cash-back pool returns
            4534.56); whole for point pools. The sign always agrees with
            `balance_sign`, except at exactly zero, where the number carries no
            sign -- read `balance_sign` instead.
          title: Point Balance
          type: number
        pool_id:
          description: Pool identifier within the club.
          title: Pool Id
          type: string
        pool_name:
          description: Human-readable pool label (e.g. 'UNI$').
          title: Pool Name
          type: string
      required:
        - club_code
        - pool_id
        - pool_name
        - point_balance
      title: LoyaltyPool
      type: object
    LoyaltyVoucher:
      description: A redeemable voucher offered against a loyalty pool.
      properties:
        description:
          description: Human-readable voucher label.
          title: Description
          type: string
        max_redeemable:
          description: Maximum vouchers redeemable in one order.
          title: Max Redeemable
          type: integer
        points_price:
          description: >-
            Points required to redeem one voucher. Fractional for monetary pools
            (e.g. a 'UNI$' cash-back voucher priced at 15.50); whole for point
            pools. Host-supplied, so accept both to avoid dropping decimals.
          title: Points Price
          type: number
        pool_name:
          description: Pool the voucher redeems against (e.g. 'UNI$').
          title: Pool Name
          type: string
        redeem_value:
          description: >-
            Monetary value of the voucher in currency major units (e.g. 10.0 =
            $10.00).
          title: Redeem Value
          type: number
        voucher_code:
          description: Voucher identifier used to redeem.
          title: Voucher Code
          type: string
      required:
        - voucher_code
        - description
        - pool_name
        - points_price
        - redeem_value
        - max_redeemable
      title: LoyaltyVoucher
      type: object
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        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.
      x-docs-interim: true

````