Applies to: Loyalty API | Orders API | Catalog API | Payments API
Learn how to use the Loyalty API to redeem points on a purchase.
A loyalty program includes one or more reward tiers that define the available discounts. If a buyer qualifies for a reward tier and chooses to redeem points for the discount, you create a reward.
This step follows the typical application flow that enables buyers to redeem points for a discount on a purchase. In this scenario, the buyer redeems points for a free coffee and also accumulates points for their purchase. With "Item based" accrual rules, buyers earn points only for the items that they pay for. They don't earn points for discounted items.
The following is a high-level application flow that enables buyers to redeem loyalty points for a discount:
- Place an order for the buyer.
- Show reward tier options to the buyer. Your application uses client-side logic to determine whether the buyer qualifies for any discounts based on the loyalty point balance, the reward tier, and the order.
- If the buyer chooses to redeem points for a discount, create a reward. The Loyalty API removes the points from the loyalty account and holds them in reserve. It also applies the discount to the order.
- Take a payment for the order. The Loyalty API sets the reward status to
REDEEMED
and permanently removes the points from the loyalty account. - If the buyer earned more points from the order, add the points to the buyer's account.
Note
This application flow assumes that you use the Orders API to create and manage orders, which simplifies loyalty workflows. For more information, see Integration with the Orders API.
Call ListCatalog in the Catalog API to get information for the order. To order coffee, you need the ID of the coffee item variation that you created in Add items to the catalog.
- If you have the ID of the coffee item variation, skip this step.
- If you don't have the ID, call ListCatalog in the Catalog API. The following request includes a
types
filter to retrieve catalog objects of typeITEM_VARIATION
.
Replace
{ACCESS_TOKEN}
with your Sandbox access token.List catalog
Note
The
?
in the endpoint URL can cause issues when running the cURL command from a terminal window. If you encounter issues, try wrapping the endpoint URL in quotation marks and resending the request.In the response, find the Coffee item variation you created and then copy the ID. Make sure to copy the
id
property, not theitem_id
.Call CreateOrder in the Orders API to create an order for four cups of coffee.
- Replace
{ACCESS_TOKEN}
with your Sandbox access token and{UNIQUE_KEY}
with a unique idempotency key. - Replace the example values for
catalog_object_id
andlocation_id
with the item variation ID and location ID.
Create order
The following is an example response. Each coffee costs $3, so the
total_money
amount is $12.{ "order":{ "id":"I3LwAibJUA8VGZXnO3fNX8example", "location_id":"S8GWD5example", "line_items":[ { "uid":"rlauAbvClDr9cnJexample", "catalog_object_id":"ZFPGMTKFH332UOJY3example", "quantity":"4", "name":"coffee", "variation_name":"Coffee", "base_price_money":{ "amount":300, "currency":"USD" }, "gross_sales_money":{ "amount":1200, "currency":"USD" }, "total_tax_money":{ "amount":0, "currency":"USD" }, "total_discount_money":{ "amount":0, "currency":"USD" }, "total_money":{ "amount":1200, "currency":"USD" }, "variation_total_price_money":{ "amount":1200, "currency":"USD" } } ], "created_at":"2020-03-11T00:18:38.074Z", "updated_at":"2020-03-11T00:18:38.074Z", "state":"OPEN", "version":1, "total_tax_money":{ "amount":0, "currency":"USD" }, "total_discount_money":{ "amount":0, "currency":"USD" }, "total_tip_money":{ "amount":0, "currency":"USD" }, "total_money":{ "amount":1200, "currency":"USD" }, "total_service_charge_money":{ "amount":0, "currency":"USD" }, "net_amounts":{ "total_money":{ "amount":1200, "currency":"USD" }, "tax_money":{ "amount":0, "currency":"USD" }, "discount_money":{ "amount":0, "currency":"USD" }, "tip_money":{ "amount":0, "currency":"USD" }, "service_charge_money":{ "amount":0, "currency":"USD" } }, "source":{ "name":"Sandbox for sq0idp-MJ1Sr5Iim0hGGvAexample" } } }- Replace
Copy the order ID from the response.
To determine whether the buyer qualifies for a discount, your application does the following:
- Retrieve the loyalty account to check the point balance.
- Retrieve the loyalty program to get the available reward tiers. A reward tier defines the number of points required to claim the reward, the discount value, and what the discount applies to.
- Determine qualifying reward tiers based on the loyalty point balance, the reward tier requirements, and the order.
If the buyer qualifies for a discount, your application can offer the reward tier option to the buyer.
Call RetrieveLoyaltyAccount in the Loyalty API to retrieve the loyalty account.
- Replace
{ACCESS_TOKEN}
with your Sandbox access token. - Replace the example account ID in the path with the loyalty account ID.
Retrieve loyalty account
The following is an example response.
{ "loyalty_account":{ "id":"1beb38f9-54de-4cb6-8121-718bDexample", "mapping":{ "id":"e27de0ff-e56f-450d-95cb-a49a4example", "phone_number":"+14255551234", "created_at":"2020-05-11T22:55:18Z" }, "program_id":"93afe66e-3a14-4be6-8d50-02755example", "balance":12, "lifetime_points":12, "customer_id":"Q80035RNBEZ4WYTB1P9PTAMTexample", "created_at":"2020-05-11T22:55:18Z", "updated_at":"2020-05-11T25:11:07Z" } }- Replace
From the response:
- Check the
balance
field to find the point balance for the account. This example has 12 points. - Copy the loyalty account ID.
- Check the
Call RetrieveLoyaltyProgram to retrieve the loyalty program in the seller's account. You can use the
main
keyword (as shown in the example) or provide the program ID.Replace
{ACCESS_TOKEN}
with your Sandbox access token.Retrieve loyalty program
The following is an example response, which lists the reward tiers in the loyalty program. The loyalty program used in this walkthrough offers two reward tiers.
{ "program": { "id": "93afe66e-3a14-4be6-8d50-02755example", "status": "ACTIVE", "reward_tiers": [ { "id": "9854964a-ee8b-4622-9fbe-7fcb7example", "points": 10, "name": "One free Coffee", "definition": { "scope": "ITEM_VARIATION", "discount_type": "FIXED_PERCENTAGE", "percentage_discount": "100", "catalog_object_ids": [ "ZFPGMTKFH332UOJY3example" ] }, "created_at": "2020-05-11T23:33:03Z", "pricing_rule_reference": { "object_id": "78Y3HESNsJLTB2A9Iexample", "catalog_version": "135548example" } }, { "id": "4efa3400-dca3-4464-9fe6-33bfDexample", "points": 15, "name": "One free Sandwich", "definition": { "scope": "ITEM_VARIATION", "discount_type": "FIXED_PERCENTAGE", "percentage_discount": "100", "catalog_object_ids": [ "HONASX6SULQC55VOWexample" ] }, "created_at": "2020-05-11T23:33:03Z", "pricing_rule_reference": { "object_id": "ZKFKBH5IINTZLY3VAexample", "catalog_version": "160396example" } } ], "terminology": { "one": "Point", "other": "Points" }, "location_ids": [ "S8GWD5example" ], "created_at": "2020-05-05T23:18:07Z", "updated_at": "2020-05-11T23:33:03Z", "accrual_rules": [ { "accrual_type": "ITEM_VARIATION", "points": 1, "item_variation_data": { "item_variation_id": "ZFPGMTKFH332UOJY3example" } } ] } }Note the number of points required to claim the reward, which is specified in the
points
field of the reward tier. The first reward tier requires 10 points and the second requires 15 points.Copy the following values. In this walkthrough, you only need the values for the first reward tier.
- The reward tier ID.
- The object ID and catalog version from the
pricing_rule_reference
field.pricing_rule_reference
references the specific version of aPRICING_RULE
catalog object that defines the discount details for the reward tier.
Note
The RetrieveLoyaltyProgram
response currently also includes the deprecated definition
field, which is replaced by the pricing_rule_reference
field. When possible, you should use pricing_rule_reference
.
Your application can now determine whether the buyer qualifies for any discounts based on the point balance of the loyalty account, the order, and the reward tier.
Check whether the loyalty account has enough points to claim the reward. In this example, the loyalty account has a balance of 12 points, so the buyer qualifies for reward tier 1 (redeem 10 points for a free coffee), but doesn't qualify for reward tier 2 (redeem 15 points for a free sandwich). Therefore, you need to get the discount details for reward tier 1.
Call RetrieveCatalogObject in the Catalog API to retrieve the PRICING_RULE and other catalog objects that define the discount details for the reward tier.
- Replace
{ACCESS_TOKEN}
with your Sandbox access token. - Replace the example object ID and catalog version in the path with the actual values. The pricing rule is pinned to a specific catalog version, so you must specify the catalog version in the request. The request must also set the
include_related_objects
parameter totrue
.
Retrieve catalog object
Note
The
?
or&
in the endpoint URL can cause issues when running the cURL command from a terminal window. If you encounter issues, try wrapping the endpoint URL in quotation marks and resending the request.The following is an example response.
{ "object": { "type": "PRICING_RULE", "id": "ZKFKBH5IINTZLY3VAexample", "updated_at": "2020-03-22T21:40:20.403Z", "version": 135548example, "is_deleted": false, "present_at_all_locations": true, "pricing_rule_data": { "discount_id": "ZSY25QTFQ3SKCYG56example", "match_products_id": "I5HNIOF4ESIRVQCU4example", "application_mode": "ATTACHED", "discount_target_scope": "LINE_ITEM", "max_applications_per_attachment": 1 } }, "related_objects": [ { "type": "DISCOUNT", "id": "ZSY25QTFQ3SKCYG56example", "updated_at": "2020-03-22T21:40:20.403Z", "version": 135548example, "is_deleted": false, "present_at_all_locations": true, "discount_data": { "name": "One free Coffee", "discount_type": "FIXED_PERCENTAGE", "percentage": "100.0", "application_method": "MANUALLY_APPLIED" } }, { "type": "PRODUCT_SET", "id": "I5HNIOF4ESIRVQCU4example", "updated_at": "2020-03-22T21:40:20.403Z", "version": 135548example, "is_deleted": false, "present_at_all_locations": true, "product_set_data": { "product_ids_any": [ "ZFPGMTKFH332UOJY3example" ], "quantity_exact": 1 } }, { "type": "ITEM_VARIATION", "id": "ZFPGMTKFH332UOJY3example", "updated_at": "2020-03-22T21:35:40.443Z", "version": 135548example, "is_deleted": false, "present_at_all_locations": true, "item_variation_data": { "item_id": "WVKYFIQQVJMTHQFKKexample", "name": "Coffee", "ordinal": 0, "pricing_type": "FIXED_PRICING", "price_money": { "amount": 300, "currency": "USD" }, "sellable": true, "stockable": true } } ] }- Replace
Determine the discount scope and value. The reward tier in this walkthrough offers a free coffee for 10 points. You can find this information in the
PRICING_RULE
,DISCOUNT
, andPRODUCT_SET
objects. ForCATEGORY
andITEM_VARIATION
scopes, the response also includes the categories or items that the discount applies to.The following settings indicate that the scope is a single item:
- In the
PRICING_RULE
object, thepricing_rule_data.discount_target_scope
field isLINE_ITEM
. - In the
PRODUCT_SET
object, theproduct_set_data.product_ids_any
field contains one ID, which maps to theITEM_VARIATION
object that was also returned in the response.
The following settings indicate that the value is 100% (free):
- In the
DISCOUNT
object, thediscount_data.discount_type
field isFIXED_PERCENTAGE
. - In the
DISCOUNT
object, thediscount_data.percentage
is100.0
.
Note
Depending on your application flow, you might also need to call the Catalog API to get current product information, such as the current pricing. For more information, see Getting discount details for a reward tier.
- In the
Your application can show the reward tier option to the buyer. For this walkthrough, assume that the buyer chooses to redeem 10 points to get a free coffee.
Call CreateLoyaltyReward in the Loyalty API to create a reward and apply the discount to the order.
- Replace
{ACCESS_TOKEN}
with your Sandbox access token and{UNIQUE_KEY}
with a unique idempotency key. - Replace the example values for
loyalty_account_id
,reward_tier_id
, andorder_id
with the actual values.
Create loyalty reward
The following is an example response:
{ "reward":{ "id":"43f05faf-96b1-3169-adab-c8a6aexample", "status":"ISSUED", "loyalty_account_id":"1beb38f9-54de-4cb6-8121-718bDexample", "reward_tier_id":"9854964a-ee8b-4622-9fbe-7fcb7example", "points":10, "order_id":"I3LwAibJUA8VGZXnO3fNX8example", "created_at":"2020-05-11T23:37:06Z", "updated_at":"2020-05-11T23:37:06Z" } }When a reward is created, the Loyalty API does the following:
Removes the points required by the reward tier from the buyer's loyalty account. These points are held in reserve and cannot be redeemed for any other reward unless this reward is deleted. For more information, see Redeem a loyalty reward.
Updates the order with reward and discount information. You can see these updates in the next step. The Loyalty API performs this step only if the order was created using the Orders API and the order ID was specified in the
CreateLoyaltyReward
request.
Did you know?
You might prefer to show the buyer a preview of the discounted order before you create a reward. For more information, see Deferred reward creation.
- Replace
Call RetrieveOrder to retrieve the updated order amounts to show to the buyer.
- Replace
{ACCESS_TOKEN}
with your Sandbox access token. - Replace the example order ID in the path with the actual value.
Retrieve order
The following in an example response.
{ "order": { "id": "I3LwAibJUA8VGZXnO3fNX8example", "location_id": "S8GWD5example", "line_items": [ { "uid": "C8DSCY3whA4p6W6example", "catalog_object_id": "ZFPGMTKFH332UOJY3example", "quantity": "1", "name": "Coffee", "variation_name": "Coffee", "base_price_money": { "amount": 300, "currency": "USD" }, "gross_sales_money": { "amount": 300, "currency": "USD" }, "total_tax_money": { "amount": 0, "currency": "USD" }, "total_discount_money": { "amount": 300, "currency": "USD" }, "total_money": { "amount": 0, "currency": "USD" }, "variation_total_price_money": { "amount": 300, "currency": "USD" }, "applied_discounts": [ { "uid": "5WxqugPnzGRiYn3example", "discount_uid": "AYYOZh3mL5qlIbTexample", "applied_money": { "amount": 300, "currency": "USD" } } ] }, { "uid": "pISztslNZbEQbSMexample", "catalog_object_id": "ZFPGMTKFH332UOJY3example", "quantity": "3", "name": "Coffee", "variation_name": "Coffee", "base_price_money": { "amount": 300, "currency": "USD" }, "gross_sales_money": { "amount": 900, "currency": "USD" }, "total_tax_money": { "amount": 0, "currency": "USD" }, "total_discount_money": { "amount": 0, "currency": "USD" }, "total_money": { "amount": 900, "currency": "USD" }, "variation_total_price_money": { "amount": 900, "currency": "USD" } } ], "discounts": [ { "uid": "AYYOZh3mL5qlIbtXexample", "catalog_object_id": "I672Q27QOFTRK2ZWNexample", "name": "One free Coffee", "percentage": "100.0", "applied_money": { "amount": 300, "currency": "USD" }, "type": "FIXED_PERCENTAGE", "scope": "LINE_ITEM", "reward_ids": [ "43f05faf-96b1-3169-adab-c8a6Aexample" ], "pricing_rule_id": "ZKFKBH5IINTZLY3VAexample" } ], "created_at": "2020-05-11T23:22:29.983Z", "updated_at": "2020-05-11T23:37:06.834Z", "state": "OPEN", "version": 2, "total_tax_money": { "amount": 0, "currency": "USD" }, "total_discount_money": { "amount": 300, "currency": "USD" }, "total_tip_money": { "amount": 0, "currency": "USD" }, "total_money": { "amount": 900, "currency": "USD" }, "total_service_charge_money": { "amount": 0, "currency": "USD" }, "net_amounts": { "total_money": { "amount": 900, "currency": "USD" }, "tax_money": { "amount": 0, "currency": "USD" }, "discount_money": { "amount": 300, "currency": "USD" }, "tip_money": { "amount": 0, "currency": "USD" }, "service_charge_money": { "amount": 0, "currency": "USD" } }, "source": { "name": "Sandbox for sq0idp-FjGzHcGJQBbe_cCexample" }, "rewards": [ { "id": "43f05faf-96b1-3169-adab-c8a6Aexample", "reward_tier_id": "9854964a-ee8b-4622-9fbe-7fcb7example" } ] } }The Loyalty API updates the order with reward and discount fields and amounts, as follows:
- Adds the
discounts
andrewards
fields to the order. In this example, the order contains one discount and one reward.- The discount maps to the
PRICING_RULE
andDISCOUNT
objects for the reward tier and the loyalty reward you created. - The reward maps to the reward tier and the loyalty reward you created.
- The discount maps to the
- Adds the
applied_discounts
field to qualifying line items. In this example, the line item has one applied discount, which maps to the order-level discount. - Updates the following amounts for the order and line item:
total_discount_money
shows a $3 discount amount that represents the value of the free coffee.total_money
shows a decrease from $12 to $9.
- Replace
Note
The presence of the discount indicates the reward was applied to the order. It's possible to create a reward that cannot be applied to the order. For example, you might create a reward for a free coffee, but the coffee isn't in the order and the discount cannot be applied. In this case, Square deletes the reward and returns the points to the buyer's loyalty account after the order reaches a terminal state (for example, the order is paid or canceled).
Call CreatePayment in the Payments API to take a payment of $9 for the preceding order. In this walkthrough, you provide a Sandbox payment token for the source_id
of the payment source.
- Replace
{ACCESS_TOKEN}
with your Sandbox access token and{UNIQUE_KEY}
with a unique idempotency key. - Replace the example value for
order_id
with the order ID.
Create payment
After you pay for the order, the Loyalty API sets the loyalty reward status to REDEEMED
and permanently removes the points from the loyalty account.
Did you know?
A searchable loyalty event is generated when a reward is created, redeemed, or deleted. For more information, see Search for Balance-Changing Loyalty Events.
The buyer paid for the order and therefore qualifies for loyalty points. Call AccumulateLoyaltyPoints in the Loyalty API to add the points to the buyer's loyalty account.
- Replace
{ACCESS_TOKEN}
with your Sandbox access token and{UNIQUE_KEY}
with a unique idempotency key. - Replace the example account ID in the path with the actual loyalty account ID.
- Replace the example values for
order_id
andlocation_id
with the actual order ID and location ID.
Accumulate loyalty points
The buyer received one free coffee and paid for three coffees. The loyalty program's accrual rule is "Earn one point for each coffee purchased," so the buyer gets three points for this purchase. Because you're using the Orders API to create manage orders, you don't have to do any calculations. You provide the order ID in your AccumulateLoyaltyPoints
request and the Loyalty API computes the loyalty points using the purchase amount.
{
"event":{
"id":"efc9fc89-60e5-360a-9002-d3904example",
"type":"ACCUMULATE_POINTS",
"created_at":"2020-05-12T00:05:29Z",
"accumulate_points":{
"loyalty_program_id":"93afe66e-3a14-4be6-8d50-02755example",
"points":3,
"order_id":"I3LwAibJUA8VGZXnO3fNX8example"
},
"loyalty_account_id":"1beb38f9-54de-4cb6-8121-718bDexample",
"location_id":"S8GWD5example",
"source":"LOYALTY_API"
}
}
You can optionally call RetrieveLoyaltyAccount to see that the points were added.
- Replace
{ACCESS_TOKEN}
with your Sandbox access token. - Replace the example account ID in the path with the actual loyalty account ID.
Retrieve loyalty account