Skip to main content
IMPORTANT: This guide is only applicable for checkout providers in Shopify platform

Overview

When a customer reaches your checkout, this integration lets you show them three things from Yuko — in real time:
What the customer sees / doesAPI endpoint
Their current points balanceGET /customers/rewards/redeemable
Rewards available to redeem right nowGET /customers/rewards/redeemable
Spend their points to get a discount code or store creditPOST /customers/rewards/redeem
Points they will earn on this purchasePOST /points/estimate
Three API calls. One seamless checkout experience.

How It Works

Customer reaches checkout


Your checkout identifies the customer
(Shopify Customer ID is required for Endpoints 1 & 3)

        ├─────────────────────────────────────────────┐
        ▼                                             ▼
  API Call #1                                  API Call #2
  GET /customers/rewards/redeemable            POST /points/estimate
  Requires Shopify Customer ID                 Public — no customer ID needed
  Only for logged-in customers                 Works for guests too
        │                                             │
        ▼                                             ▼
  Returns:                                     Returns:
  · Points balance                             · Points earned on this cart
  · Rewards available to redeem
  · Unused coupon codes already held
        │                                             │
        └────────────────┬────────────────────────────┘

          Your checkout UI renders:
          "You have 650 points"
          "Redeem: $5 off (costs 500 pts)"   ← customer clicks this
          "Unused coupon: YUKO-TVJ-BL1"
          "You'll earn 120 points on this order"

          Customer clicks "Redeem" on a reward


                   API Call #3
                   POST /customers/rewards/redeem
                   Sends: customer_id + reward_id


                   Returns:
                   · New discount code (e.g. YUKO-ABC-123)
                   · Points deducted
                   · Expiry date


          Your checkout applies the discount code
          Customer completes purchase
Both API calls must be made from your backend server — never directly from the customer’s browser. See Security Rules for details.

Before You Start

What the merchant needs to do

The merchant must have Yuko installed on their Shopify store. Once installed:
1

Open Shopify Admin

Go to the merchant’s Shopify Admin Dashboard.
2

Open Yuko

Click Apps → Yuko Loyalty.
3

Go to API settings

Navigate to Account Settings → Integrations → REST API.
4

Create an API token

Create a new token and enable the rewards:read scope.
5

Share the API key

Copy the API key and share it securely with your team. It looks like this:
py_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Each merchant generates their own API key. If you are integrating across multiple merchants, each one will have a different key.

What your team needs

  • The customer’s Shopify Customer ID at checkout time — required for Endpoint 1, only available when the customer is logged in
  • Shopify Product IDs and Variant IDs for every item in the cart — required for Endpoint 2

Authentication

Yuko uses Bearer Token Authentication. Every API request must include the merchant’s API key in the Authorization header.
Authorization: Bearer py_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
This header is required on every single request — no exceptions.
Full authentication details are in the Authentication reference.

Base URL

All Yuko API requests start with:
https://api.yukoapp.com/api/v1/public

General rules

  • Always use HTTPS — plain HTTP requests are rejected
  • Always set Content-Type: application/json on POST requests
  • All responses are JSON
  • Successful responses wrap data inside a "data" key
  • Error responses include a "message" key
See the API Introduction for a full overview of request and response formats.

Endpoint 1 — Get Points Balance & Redeemable Rewards

This is the primary endpoint for your checkout loyalty panel. One call returns everything:
  • The customer’s current points balance
  • All rewards they can redeem (with a flag showing if they have enough points for each)
  • Coupon codes they’ve already redeemed but haven’t applied yet
/customers/rewards/redeemable is a single endpoint that covers both the points balance and the full rewards list. You do not need a separate “get balance” call.
Full API reference → GET /customers/rewards/redeemable

Request

GET https://api.yukoapp.com/api/v1/public/customers/rewards/redeemable

Query parameter

customer_id
string
required
The Shopify Customer ID of the logged-in customer. This is mandatory — do not call this endpoint for guest checkouts.Example: 9049402769586

Required token scope

Your API token must have rewards:read enabled. The merchant configures this in Shopify Admin → Apps → Yuko Loyalty → Account Settings → Integrations → REST API.

Example request

curl --request GET \
  --url "https://api.yukoapp.com/api/v1/public/customers/rewards/redeemable?customer_id=9049402769586" \
  --header "Authorization: Bearer py_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Example response (200)

{
  "data": {
    "points_balance": 650,
    "rewards": [
      {
        "id": "90424fa7-e8a9-4ef4-b43a-72c9b2028db5",
        "name": "$5 off your next order",
        "description": "Redeem 500 points for a $5 discount.",
        "reward_type": "fixed_discount",
        "points_cost": 500,
        "reward_rule": {
          "points_required": 500,
          "discount_value": 5
        },
        "can_redeem": true,
        "points_needed": 0
      },
      {
        "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "name": "10% off your next order",
        "description": "Redeem 1000 points for 10% off.",
        "reward_type": "percentage_discount",
        "points_cost": 1000,
        "reward_rule": {
          "points_required": 1000,
          "discount_percentage": 10
        },
        "can_redeem": false,
        "points_needed": 350
      }
    ],
    "customer_rewards": [
      {
        "id": "1fd80ced-326f-4082-951b-21a38632a603",
        "reward_type": "fixed_discount",
        "status": "active",
        "discount_code": "YUKO-TVJ-BL1",
        "points_used": 500,
        "expires_at": "2026-06-01T00:00:00+00:00",
        "used_at": null,
        "created_at": "2026-02-15T08:30:00+00:00"
      }
    ]
  }
}

Response fields

data.points_balance
integer
The customer’s current redeemable points balance. Display this prominently at the top of your loyalty panel.Example: 650
data.rewards
array
All rewards the merchant has configured, enriched with affordability data for this specific customer.
data.customer_rewards
array
Coupon codes the customer has already redeemed (converted points into a discount code) but not yet applied at checkout.

Display logic

If points_balance > 0:
  Show: "You have {points_balance} points"

For each reward in rewards[]:
  If can_redeem === true  → Show active "Redeem" button: "{name} — {points_cost} pts"
  If can_redeem === false → Show greyed out: "{name} — earn {points_needed} more points"

For each item in customer_rewards[] where status === "active":
  Show: "You have an unused reward: {discount_code}"

Endpoint 2 — Points Estimate at Checkout

This endpoint tells the customer how many loyalty points they will earn when they complete this purchase. This is a public endpoint — no Shopify Customer ID is required. It works for both logged-in customers and guests. Full API reference → POST /points/estimate

Request

POST https://api.yukoapp.com/api/v1/public/points/estimate

Request body

customer
object
Optional. Include only if the customer is logged in. Omit entirely for guest checkouts.
items
array
required
The line items in the cart. Must contain at least one item.

Example request — logged-in customer

curl --request POST \
  --url "https://api.yukoapp.com/api/v1/public/points/estimate" \
  --header "Authorization: Bearer py_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  --header "Content-Type: application/json" \
  --data '{
    "customer": {
      "id": "9049402769586",
      "email": "rahul.sharma@example.com"
    },
    "items": [
      {
        "product_id": "prod_1001",
        "variant_id": "var_1001_red_m"
      },
      {
        "product_id": "prod_2044",
        "variant_id": "var_2044_black_42"
      }
    ]
  }'

Example request — guest checkout

curl --request POST \
  --url "https://api.yukoapp.com/api/v1/public/points/estimate" \
  --header "Authorization: Bearer py_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  --header "Content-Type: application/json" \
  --data '{
    "items": [
      {
        "product_id": "prod_1001",
        "variant_id": "var_1001_red_m"
      }
    ]
  }'

Example response (200) — points earned

{
  "data": {
    "points_earned": 120,
    "message": "You will earn 120 points after completing this purchase"
  }
}

Example response (200) — no active campaign

{
  "data": {
    "points_earned": 0,
    "message": null
  }
}

Response fields

data.points_earned
integer
The number of loyalty points the customer will earn after completing the purchase.Example: 120
data.message
string | null
A ready-to-display string. You can show this directly in your UI without additional formatting.Example: "You will earn 120 points after completing this purchase"Will be null if no earning campaign matches the cart.

Display logic

If points_earned > 0:
  Show the message field directly in your UI

If points_earned === 0 or message === null:
  Hide this section entirely — never show "You will earn 0 points"

Endpoint 3 — Redeem a Reward (Burn Points)

This is the endpoint your checkout calls when a customer actively chooses to spend their points on a reward. When the customer clicks “Redeem” on an available reward, call this endpoint. Yuko will:
  1. Deduct the required points from the customer’s balance
  2. Generate a fresh Shopify discount code for that reward
  3. Return the discount code so you can apply it to the order
This endpoint is triggered by a customer action — not automatically at checkout load. Only call it when the customer explicitly clicks “Redeem” on a reward option.
Full API reference → POST /customers/rewards/redeem

Request

POST https://api.yukoapp.com/api/v1/public/customers/rewards/redeem

Required headers

HeaderValue
AuthorizationBearer YOUR_API_KEY
Content-Typeapplication/json

Request body

customer_id
string
required
The Shopify Customer ID of the logged-in customer.Example: "9049402769586"
reward_id
string (uuid)
required
The UUID of the reward the customer wants to redeem. Get this from the rewards[].id field in the Endpoint 1 response (GET /customers/rewards/redeemable).Example: "90424fa7-e8a9-4ef4-b43a-72c9b2028db5"

Example request

curl --request POST \
  --url "https://api.yukoapp.com/api/v1/public/customers/rewards/redeem" \
  --header "Authorization: Bearer py_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  --header "Content-Type: application/json" \
  --data '{
    "customer_id": "9049402769586",
    "reward_id": "90424fa7-e8a9-4ef4-b43a-72c9b2028db5"
  }'
The reward_id comes directly from the rewards[].id field in the Endpoint 1 response. Store these IDs when you render the rewards list so you have them ready when the customer clicks “Redeem”.

Example response (201 — Created)

A 201 status means the redemption was successful and a new coupon code has been generated.
{
  "data": {
    "coupon_code": "YUKO-TVJ-BL1",
    "points_spent": 500,
    "reward_type": "fixed_discount",
    "discount_value": 5,
    "expires_at": "2026-06-01T00:00:00+00:00"
  }
}

Response fields

data.coupon_code
string | null
The newly generated Shopify discount code (e.g. YUKO-TVJ-BL1). Apply this directly through your checkout’s discount flow.Will be null for store_credit reward types — the credit is added to the customer’s account automatically.
data.points_spent
integer
The number of points deducted from the customer’s balance.Example: 500
data.reward_type
enum | null
The type of reward that was redeemed. Possible values: fixed_discount, percentage_discount, free_shipping, free_product, store_credit.
data.discount_value
number | null
The discount amount or percentage associated with the coupon.
  • For fixed_discount: this is the rupee/dollar amount (e.g. 5 means $5 off)
  • For percentage_discount: this is the percentage (e.g. 10 means 10% off)
  • Will be null for free_shipping and free_product reward types
data.expires_at
string (datetime) | null
When the generated coupon expires. null if the reward has no expiry.Example: "2026-06-01T00:00:00+00:00"

Error responses for this endpoint

CodeScenarioWhat to do
422Customer doesn’t have enough pointsThis shouldn’t happen if you used can_redeem from Endpoint 1 correctly. Show the customer a message: “You don’t have enough points for this reward.”
422Reward not found or is inactiveThe reward may have been deactivated by the merchant. Refresh the rewards list by calling Endpoint 1 again.
404Customer not foundThe customer_id is not in Yuko.
401Invalid API keyCheck the Authorization header.

Display logic after a successful redemption

On successful 201 response:

1. Show the customer their new discount code:
   "Your reward is ready! Code: {coupon_code}"

2. Auto-apply the discount code to the order if your checkout supports it

3. Update the displayed points balance:
   New balance = old points_balance - points_spent

4. Remove the redeemed reward from the "available rewards" list in your UI
After a successful redemption, the customer’s points balance has decreased. If you have the old balance cached, subtract points_spent from it to show the updated balance without making another API call.

Full Checkout Flow

Step 1 — Collect what you need at checkout

  • Shopify Customer ID — only if the customer is logged in (needed for Endpoint 1)
  • Product IDs and Variant IDs for every item in the cart (needed for Endpoint 2)

Step 2 — Decide which endpoints to call

Customer stateCall Endpoint 1?Call Endpoint 2?Call Endpoint 3?
Logged in, Shopify Customer ID available✅ Yes✅ Yes — include customer field✅ Yes — when customer clicks “Redeem”
Guest checkout❌ No — skip✅ Yes — omit customer field❌ No — guests can’t redeem points

Step 3 — Fire both calls in parallel

Do not wait for one to finish before starting the other. Running them in parallel keeps checkout fast.
# Call 1 — Only if the customer is logged in
curl --request GET \
  --url "https://api.yukoapp.com/api/v1/public/customers/rewards/redeemable?customer_id=9049402769586" \
  --header "Authorization: Bearer py_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# Call 2 — Always run this, for both logged-in and guest customers
curl --request POST \
  --url "https://api.yukoapp.com/api/v1/public/points/estimate" \
  --header "Authorization: Bearer py_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  --header "Content-Type: application/json" \
  --data '{
    "customer": {
      "id": "9049402769586"
    },
    "items": [
      {
        "product_id": "prod_1001",
        "variant_id": "var_1001_red_m"
      }
    ]
  }'

Step 4 — Render the loyalty panel - Example

Combine both responses to display the loyalty section: Its an example. Customize as per your UI.
┌──────────────────────────────────────────────┐
│  🏆  Your Rewards                            │
│                                              │
│  Points Balance: 650 pts                     │
│                                              │
│  ✅  $5 off your next order                 │
│      Costs 500 pts              [Redeem →]  │
│                                              │
│  🔒  10% off your next order                │
│      Earn 350 more points to unlock          │
│                                              │
│  🎟️  You have an unused coupon              │
│      YUKO-TVJ-BL1          [Apply to order] │
│                                              │
│  💰  You'll earn 120 points on this order!  │
└──────────────────────────────────────────────┘

Step 5 — Handle the “Redeem” button click

When a customer clicks “Redeem” on an available reward, call Endpoint 3 with their customer_id and the reward_id of the reward they selected.
curl --request POST \
  --url "https://api.yukoapp.com/api/v1/public/customers/rewards/redeem" \
  --header "Authorization: Bearer py_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  --header "Content-Type: application/json" \
  --data '{
    "customer_id": "9049402769586",
    "reward_id": "90424fa7-e8a9-4ef4-b43a-72c9b2028db5"
  }'
On a 201 response:
  • Take the coupon_code from the response and apply it to the checkout order
  • Update the displayed points balance: new_balance = old_balance - points_spent
  • Remove the redeemed reward from the UI rewards list
The reward_id is the id field from the rewards[] array in the Endpoint 1 response. You should store these IDs when you render the rewards list so they’re ready when the customer clicks.

Error Handling

The loyalty panel is an enhancement to checkout — it must never block or break the purchase. If any Yuko API call fails, hide the loyalty panel silently and let checkout continue.
Full list of error codes → Errors reference

HTTP status codes

CodeMeaningWhat to do
200SuccessUse the response data
400Bad request — missing or malformed parametersCheck your request structure
401Unauthorized — API key missing or incorrectCheck the Authorization header and key value
403Forbidden — token missing the right scopeAsk the merchant to regenerate a token with rewards:read scope
404Customer not foundThe customer_id doesn’t exist in Yuko — hide the panel silently
422Validation error — logically incorrect requestCheck the message field in the response
429Rate limit exceededWait 1 second and retry once — see Rate Limits
500Yuko internal errorRetry once. If it persists, hide the panel and let checkout continue.
503Yuko temporarily unavailableSame as 500 — retry once, then fail gracefully

Error response format

All error responses from Yuko return a message field:
{
  "message": "Customer not found"
}
401 → Log the error. Hide the loyalty panel.
404 → Customer has no Yuko account yet (common for new customers). Hide silently.
429 → Wait 1 second. Retry the same request once.
5xx → Retry once after a short delay. If it fails again, hide the panel.
Any other error → Hide the loyalty panel. Never block checkout.

Rate Limits

See full details → Rate Limits reference
LimitValue
Requests per second (per API token)10
Error when exceededHTTP 429 Too Many Requests
Reset interval1 second
Cache the rewards list. The rewards[] catalogue changes infrequently — you can cache it for 5–15 minutes. The points_balance and customer_rewards[] are customer-specific and should be fetched fresh each checkout session.
  • Don’t poll. Call both endpoints once when the customer arrives at checkout.
  • Retry with a delay. On a 429, wait 1 second and retry once. Never retry immediately.

Security Rules

These rules are not optional. Violating them exposes the merchant’s API key and puts their store at risk.
Rule 1 — Never expose the API key on the frontend. The key is a secret. It must only ever live on your backend server.
  • ❌ Never put it in browser-side JavaScript
  • ❌ Never put it in a mobile app binary
  • ❌ Never commit it to a public code repository
  • ✅ Make all Yuko API calls from your backend — pass only the results to your frontend
Rule 2 — Use HTTPS everywhere. All requests to Yuko must use https://. Plain HTTP will be rejected.

Authentication Setup Options

Choose whichever approach fits your architecture.
This is the simplest approach. No OAuth flow required.How it works:
1

Merchant generates a token

The merchant goes to Shopify Admin → Apps → Yuko Loyalty → Account Settings → Integrations → REST API and creates a token with rewards:read scope.
2

Merchant shares the token

The merchant copies the token and pastes it into your checkout platform’s merchant settings.
3

Your backend uses the token

Your backend reads the token from your settings and includes it in every Yuko API request for that merchant.
Pros: Fast to set up. No OAuth flow required.
Cons: The merchant must manually copy-paste the token. If they regenerate it, it needs to be updated on your side.

Testing

Step 1 — Get a test API key

Contact the Yuko team for a test key, or use a real merchant’s key on a development Shopify store.

Step 2 — Verify authentication

curl --request GET \
  --url "https://api.yukoapp.com/api/v1/public/customers/rewards/redeemable?customer_id=9049402769586" \
  --header "Authorization: Bearer py_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Expected: HTTP 200 with data.points_balance in the response body.
If you get HTTP 401, the API key is wrong — check for extra spaces or incorrect values.

Step 3 — Test Endpoint 1 with a real customer

curl --request GET \
  --url "https://api.yukoapp.com/api/v1/public/customers/rewards/redeemable?customer_id=REAL_CUSTOMER_ID" \
  --header "Authorization: Bearer py_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Verify:
  • points_balance returns a number
  • rewards[] is populated with the merchant’s reward options
  • can_redeem correctly reflects the customer’s balance
  • customer_rewards[] returns any existing coupons

Step 4 — Test Endpoint 2 with real cart items

curl --request POST \
  --url "https://api.yukoapp.com/api/v1/public/points/estimate" \
  --header "Authorization: Bearer py_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  --header "Content-Type: application/json" \
  --data '{
    "customer": {
      "id": "REAL_SHOPIFY_CUSTOMER_ID"
    },
    "items": [
      {
        "product_id": "REAL_PRODUCT_ID",
        "variant_id": "REAL_VARIANT_ID"
      }
    ]
  }'
Verify: points_earned returns a non-zero value if the merchant has active earning campaigns configured.

Step 5 — Test Endpoint 3 — Redeem a reward

Use a reward_id from the Endpoint 1 response (choose one where can_redeem === true).
curl --request POST \
  --url "https://api.yukoapp.com/api/v1/public/customers/rewards/redeem" \
  --header "Authorization: Bearer py_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  --header "Content-Type: application/json" \
  --data '{
    "customer_id": "REAL_SHOPIFY_CUSTOMER_ID",
    "reward_id": "REWARD_ID_FROM_ENDPOINT_1_RESPONSE"
  }'
Verify:
  • Response is HTTP 201 (not 200)
  • coupon_code is returned and is a valid Shopify discount code
  • points_spent matches the points_cost of the reward you redeemed
  • expires_at is present (or null if the reward has no expiry)

Step 6 — Test Endpoint 2 for guest checkout

curl --request POST \
  --url "https://api.yukoapp.com/api/v1/public/points/estimate" \
  --header "Authorization: Bearer py_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  --header "Content-Type: application/json" \
  --data '{
    "items": [
      {
        "product_id": "REAL_PRODUCT_ID",
        "variant_id": "REAL_VARIANT_ID"
      }
    ]
  }'
Verify: Returns HTTP 200 with no customer field in the request body.

Step 7 — Test error cases

TestHow to triggerExpected result
Wrong API keyUse Bearer wrong_keyHTTP 401
Unknown customerUse customer_id=0000000HTTP 404
Missing itemsSend "items": []HTTP 422
Guest checkoutOmit customer entirelyHTTP 200
Redeem with insufficient pointsUse a reward_id where can_redeem === falseHTTP 422
Redeem with invalid reward IDUse a made-up UUID as reward_idHTTP 422

Step 8 — Test UI edge cases

  • Customer with 0 points — panel shows rewards, all greyed out
  • Customer with no prior redemptions — customer_rewards[] is an empty array — handle without crashing
  • Guest customer — Endpoint 1 and Endpoint 3 are not called; only show earn estimate from Endpoint 2
  • points_earned === 0 — hide the earn message; do not show “0 points”
  • After a successful redemption — UI updates the balance and removes the redeemed reward from the list

Go-Live Checklist

Security
  • API key stored as an environment variable — not hardcoded anywhere
  • All Yuko API calls made from the backend server — not the browser
  • HTTPS used for all requests
API Integration
  • GET /customers/rewards/redeemable working and returning correct data
  • POST /points/estimate working for both logged-in and guest customers
  • POST /customers/rewards/redeem working — returns 201 with a valid coupon_code
  • Endpoints 1 and 2 fire in parallel at checkout load — not sequentially
  • Endpoint 3 is only called on an explicit customer “Redeem” click — not at page load
  • If any call fails, checkout continues without breaking
UI
  • Points balance displayed clearly
  • Redeemable rewards shown with a “Redeem” button for rewards where can_redeem === true
  • Rewards with insufficient points shown as greyed-out with “X more points needed”
  • Unused coupon codes from customer_rewards[] surfaced with an apply action
  • Points earn estimate shown when points_earned > 0
  • After a successful redemption: balance updates, redeemed reward is removed from list, new coupon code is surfaced or auto-applied
  • No loyalty UI shown for guest checkouts
  • Empty customer_rewards[] handled gracefully — no crash, no blank space
Rate Limiting
  • Retry logic in place for HTTP 429 — wait 1 second, retry once
  • No polling within a single checkout session
Authentication
  • Plan in place for token rotation if the merchant regenerates their API key


Support


Built by Flycart — the team behind 100K+ WooCommerce plugin installs.
Discount Rules · WPLoyalty · Yuko