Skip to main content
Z(ZupyDollar)isablockchainbackedloyaltytokenontheSolananetwork.CustomersearnZ (Zupy Dollar) is a blockchain-backed loyalty token on the Solana network. Customers earn Z automatically when they accumulate points, and can use Z$ to “top up” reward redemptions when they don’t have enough points.
Prerequisites: Your API key (zupy_pk_*) and familiarity with the Authentication page. ZdistributionisautomaticpartnersdoNOTneedtocallaseparateendpointtoawardZ distribution is automatic — partners do NOT need to call a separate endpoint to award Z.

What Are Z$ Tokens?

PropertyDetail
Full nameZupy Dollar (Z$)
BlockchainSolana mainnet
Token typeCompressed SPL token (Merkle tree)
Precision6 decimal places
EarningAutomatic — triggered when points are added
UsageTop up reward redemptions when points are insufficient
TransferabilityNot transferable between customers via API
Each customer has a Zwallet(compressedtokenaccountonSolana).ThewalletiscreatedautomaticallyonthecustomersfirstZ wallet (compressed token account on Solana). The wallet is created automatically on the customer's first Z distribution — no setup needed from partners.

How Customers Earn Z$

Z$ tokens are distributed automatically when a partner adds points to a customer. There is no separate endpoint to call.
POST /api/v2/customers/{id}/points/add/   →   Points added
                                           →   Z$ bonus distributed (async)
Partners do NOT need to call a separate endpoint to award Z.WhenyoucallPOST/api/v2/customers/id/points/add/,theZ. When you call `POST /api/v2/customers/{id}/points/add/`, the Z bonus is distributed automatically as a background task.

Key Details

  • Automatic: Z$ distribution is a side effect of points addition
  • Async: Distribution happens via a background worker (Celery task) — not instant
  • Configured by Zupy: The Z$ bonus amount per points addition is configured by Zupy ops per company, not by partners
  • Wallet creation: If the customer doesn’t have a wallet yet, one is created on first distribution
# Adding points also triggers Z$ distribution automatically
curl -X POST "https://api.zupy.com/api/v2/customers/2awTHloSJX7kGGprFerOOsvABcd/points/add/" \
  -H "X-API-Key: zupy_pk_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"amount": 50, "reason": "Order #12345"}'

Checking Z$ Balance

Real-Time On-Chain Balance

Query the customer’s real-time Z$ balance directly from the Solana blockchain:
GET /api/v2/customers/{id}/z-balance/
Response fields:
FieldTypeDescription
z_balancestringZ$ balance with 6 decimal places (e.g., "150.000000")
wallet_addressstringSolana wallet address (compressed token account)
has_walletbooleanWhether the customer has a Z$ wallet
errorstring | nullError message if Solana query failed (e.g., "timeout")
curl -X GET "https://api.zupy.com/api/v2/customers/2awTHloSJX7kGGprFerOOsvABcd/z-balance/" \
  -H "X-API-Key: zupy_pk_your_api_key_here"
Example response:
{
  "data": {
    "z_balance": "150.000000",
    "wallet_address": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU",
    "has_wallet": true,
    "error": null
  },
  "meta": {}
}
Graceful degradation: If the Solana network is slow or unreachable, the endpoint returns HTTP 200 with "error": "timeout" or "error": "unavailable" and z_balance may be null. Your integration should handle this gracefully — show a “balance unavailable” message rather than failing.

Cached Balance (Customer Profile)

The customer profile also includes a cached Z$ balance:
GET /api/v2/customers/{id}/
The response includes a zupy_balance field:
{
  "data": {
    "id": "2awTHloSJX7kGGprFerOOsvABcd",
    "full_name": "Maria Santos",
    "points_balance": 350,
    "zupy_balance": "150.000000",
    ...
  },
  "meta": {}
}
zupy_balance in the customer profile is a cached off-chain value. It may lag behind the actual on-chain balance by a few minutes. For real-time balance, use the /z-balance/ endpoint.
MethodEndpointFreshnessUse When
Real-timeGET /api/v2/customers/{id}/z-balance/Live on-chain queryDisplaying balance before redemption, showing wallet details
CachedGET /api/v2/customers/{id}/zupy_balanceMay lag a few minutesShowing balance in a list view, non-critical display

Using Z$ in Reward Redemption (Top-Up)

When a customer doesn’t have enough points for a reward, Z$ tokens can cover the gap. This is called a top-up.
POST /api/v2/customers/{id}/rewards/{reward_id}/redeem/
Request body:
{ "use_z_tokens": true }

How Top-Up Works

  1. Customer wants a reward that costs 500 points
  2. Customer only has 450 points
  3. With use_z_tokens: true, Z$ covers the 50-point gap (up to 20% of the reward cost)
  4. A 20% markup is applied to the Z$ portion
Response includes additional Z$ fields:
FieldTypeDescription
z_tokens_usedstringZ$ tokens spent on this redemption
new_z_balancestringCustomer’s remaining Z$ balance after redemption
curl -X POST "https://api.zupy.com/api/v2/customers/2awTHloSJX7kGGprFerOOsvABcd/rewards/2bxRKmpWJY8lHHqsGfsQQtwCDef/redeem/" \
  -H "X-API-Key: zupy_pk_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"use_z_tokens": true}'
Example response (top-up scenario):
{
  "data": {
    "coupon_code": "CZ-X9Y8Z7W6",
    "points_used": 450,
    "z_tokens_used": "60.000000",
    "new_balance": 0,
    "new_z_balance": "1090.000000",
    "valid_until": "2026-04-25T00:00:00Z"
  },
  "meta": {}
}
In the example above:
  • Reward cost: 500 points
  • Customer has: 450 points + 1,150 Z$
  • Points used: 450 (all available points)
  • Points gap: 50 points
  • **Zcap:max20 cap**: max 20% of reward cost = 100 points coverable by Z (50 is within cap)
  • **Zequivalent:50points=50Z equivalent**: 50 points = 50 Z
  • 20% markup: 50 Z×1.20=60Z × 1.20 = **60 Z**
  • Z$ used: 60.000000
  • Remaining Z$: 1,150 - 60 = 1,090.000000
The Z$ top-up can cover at most 20% of the reward’s point cost. If the points gap exceeds this limit, the redemption will fail with a 422 error. The markup percentage is configured globally by Zupy and is not visible to partners via the API.

Important Notes & FAQ

No. ZtokenscannotbetransferredbetweencustomersviatheAPI.EachcustomersZ tokens cannot be transferred between customers via the API. Each customer's Z balance is tied to their individual compressed token account on Solana.
No. The Z$ distribution amount per points addition is configured by Zupy ops, not by partners. Contact Zupy support if you need to discuss bonus amounts for your company.
Yes. Z$ tokens exist on Solana mainnet as compressed SPL tokens stored in a Merkle tree. They are real blockchain assets, not just database entries. The /z-balance/ endpoint queries the Solana blockchain in real time.
If a customer has never received Ztokens,haswalletwillbefalseinthe/zbalance/response.AwalletisautomaticallycreatedwhenthecustomerfirstreceivesZ tokens, `has_wallet` will be `false` in the `/z-balance/` response. A wallet is automatically created when the customer first receives Z (triggered by a points addition). No action is needed from the partner.
The /z-balance/ endpoint has a timeout. If Solana is slow or unreachable, the response returns HTTP 200 with "error": "timeout" and the balance may be unavailable. Use the cached zupy_balance from the customer profile as a fallback.
No. Zisdesignedtobetransparenttocustomers.Theyseea"Z is designed to be transparent to customers. They see a "Z balance” in their loyalty interface — the blockchain implementation is an internal detail. Partners should present Z$ as a supplementary loyalty currency, not a crypto token.

Next Steps

Coupon Lifecycle

Learn the complete coupon flow from reward browsing to validation

OTP Flow

Set up customer identity verification for sensitive operations

API Reference

Browse all endpoints with request/response schemas