Loyalty API

Manage Loyalty Accounts Using the Loyalty API

After sellers set up a Square loyalty program in the Seller Dashboard, you can use the Loyalty API to create loyalty accounts for buyers and allow them to earn points and redeem points for discounts.

Get loyalty programs Permalink Get a link to this section

The Loyalty API provides two endpoints that you can use to get loyalty programs:

Loyalty programs can be configured and managed only in the Square Seller Dashboard. The Loyalty API cannot be used to create or update loyalty programs.

Retrieve a loyalty program Permalink Get a link to this section

Call RetrieveLoyaltyProgram to get a loyalty program by the program ID or using the main keyword. Either value can be used to retrieve the single loyalty program that belongs to the seller.

  • Retrieve a loyalty program by the program ID

    Retrieve Loyalty Program
    • 1
    • 2
    • 3
    • 4
    curl https://connect.squareupsandbox.com/v2/loyalty/programs/{program_id} \
      -H 'Square-Version: 2021-07-21' \
      -H 'Authorization: Bearer {ACCESS_TOKEN}' \
      -H 'Content-Type: application/json'
  • Retrieve a loyalty program using the main keyword

    Retrieve Loyalty Program
    • 1
    • 2
    • 3
    • 4
    curl https://connect.squareupsandbox.com/v2/loyalty/programs/main \
      -H 'Square-Version: 2021-07-21' \
      -H 'Authorization: Bearer {ACCESS_TOKEN}' \
      -H 'Content-Type: application/json'

    Note

    Only the RetrieveLoyaltyProgram endpoint supports using the main keyword in place of the program ID. For example, you cannot use main to call CalculateLoyaltyPoints.

The following is an example RetrieveLoyaltyProgram response:

{
  "program": {
    "id": "8031c1b2-d749-4c76-9c40-ae5472ed2e04",
    "status": "ACTIVE",
    "reward_tiers": [
      {
        "id": "7b897fee-572a-4516-a3d3-47676931e4f3",
        "points": 15,
        "name": "10% off entire sale",
        "definition": {
          "scope": "ORDER",
          "discount_type": "FIXED_PERCENTAGE",
          "percentage_discount": "10"
        },
        "created_at": "2020-12-16T17:39:54Z",
        "pricing_rule_reference": {
          "object_id": "ESNLTB2A77HXVKRBM",
          "catalog_version": "564027IS7PT6"
        }
      },
      {
        "id": "46c2716e-f559-4b75-c015-764897e3c4ae0",
        "points": 30,
        "name": "25% off entire sale",
        "definition": {
          "scope": "ORDER",
          "discount_type": "FIXED_PERCENTAGE",
          "percentage_discount": "25"
        },
        "created_at": "2020-12-16T17:47:22Z",
        "pricing_rule_reference": {
          "object_id": "GR4C4RSNLFBU2GMWT",
          "catalog_version": "738021351929"
        }
      }
    ],
    "terminology": {
      "one": "Point",
      "other": "Points"
    },
    "location_ids": [
      "S8GWD5R9QB376"
    ],
    "created_at": "2020-12-16T23:35:41Z",
    "updated_at": "2020-12-20T02:00:02Z",
    "accrual_rules": [
      {
        "accrual_type": "SPEND",
        "points": 1,
        "spend_amount_money": {
          "amount": 200
        },
        "excluded_category_ids": [
          "7ZERJKO5PVYXCVUHV2JCZ2UG",
          "FQKAOJE5C4FIMF5A2URMLW6V"
        ],
        "excluded_item_variation_ids": [
          "CBZXBUVVTYUBZGQO44RHMR6B",
          "EDILT24Z2NISEXDKGY6HP7XV"
        ]
      }
    ]
  }
}

List loyalty programs (deprecated) Permalink Get a link to this section

Call ListLoyaltyPrograms to list the loyalty programs in a seller's account. A seller account can contain one loyalty program, so only one loyalty program is returned in the list.

Note

The ListLoyaltyPrograms endpoint is deprecated. When possible, you should use the RetrieveLoyaltyProgram endpoint with the main keyword instead. RetrieveLoyaltyProgram and ListLoyaltyPrograms provide the same functionality because a seller account can contain only one loyalty program. For more information, see Migration notes.

List Loyalty Programs
  • 1
  • 2
  • 3
  • 4
curl https://connect.squareupsandbox.com/v2/loyalty/programs \
  -H 'Square-Version: 2021-07-21' \
  -H 'Authorization: Bearer {ACCESS_TOKEN}' \
  -H 'Content-Type: application/json'

The following is an example ListLoyaltyPrograms response:

{
  "programs": [
    {
      "id": "8031c1b2-d749-4c76-9c40-ae5472ed2e04",
      "status": "ACTIVE",
      "reward_tiers": [
        {
          "id": "7b897fee-572a-4516-a3d3-47676931e4f3",
          "points": 15,
          "name": "10% off entire sale",
          "definition": {
            "scope": "ORDER",
            "discount_type": "FIXED_PERCENTAGE",
            "percentage_discount": "10"
          },
          "created_at": "2020-12-16T17:39:54Z",
          "pricing_rule_reference": {
            "object_id": "ESNLTB2A77HXVKRBM",
            "catalog_version": "564027IS7PT6"
          }
        },
        {
          "id": "46c2716e-f559-4b75-c015-764897e3c4ae0",
          "points": 30,
          "name": "25% off entire sale",
          "definition": {
            "scope": "ORDER",
            "discount_type": "FIXED_PERCENTAGE",
            "percentage_discount": "25"
          },
          "created_at": "2020-12-16T17:47:22Z",
          "pricing_rule_reference": {
            "object_id": "GR4C4RSNLFBU2GMWT",
            "catalog_version": "738021351929"
          }
        }
      ],
      "terminology": {
        "one": "Point",
        "other": "Points"
      },
      "location_ids": [
        "S8GWD5R9QB376"
      ],
      "created_at": "2020-12-16T23:35:41Z",
      "updated_at": "2020-12-20T02:00:02Z",
      "accrual_rules": [
        {
          "accrual_type": "SPEND",
          "points": 1,
          "spend_amount_money": {
            "amount": 200
          },
          "excluded_category_ids": [
            "7ZERJKO5PVYXCVUHV2JCZ2UG",
            "FQKAOJE5C4FIMF5A2URMLW6V"
          ],
          "excluded_item_variation_ids": [
            "CBZXBUVVTYUBZGQO44RHMR6B",
            "EDILT24Z2NISEXDKGY6HP7XV"
          ]
        }
      ]
    }
  ]
}

LoyaltyProgram object Permalink Get a link to this section

In the preceding examples, the loyalty program represents an active loyalty program that offers two percentage-based reward tiers and allows buyers to accrue one point for every $2 spent. The following fields represent key attributes of a loyalty program:

FieldDescription
statusIndicates whether the loyalty program is active.
accrual_rulesContains one or more accrual rules that define how buyers can earn points from purchases. Loyalty programs can contain a single type of accrual rule:
• CATEGORY. Can include one or more accrual rules.
• ITEM_VARIATION. Can include one or more accrual rules
• SPEND. Can include one accrual rule.
• VISIT. Can include one accrual rule.

CATEGORY, ITEM_VARIATION, and SPEND accrual rules integrate with the Catalog API. For more information, see Integration with the Catalog API.
expiration_policyThe number of months before points expire, in RFC 3339 duration format. For example, a value of P12M represents a duration of 12 months. This field is present only if the loyalty program has an expiration policy. For information about how sellers configure an expiration policy, see Add Points Expiration Date in Create a Loyalty Program with Square.
terminologyThe terminology used to represent points. For example, Point or Points and Star or Stars.
reward_tiersContains one or more reward tiers that define how buyers can redeem points for rewards.

To get information about the reward tier discount, call the RetrieveCatalogObject endpoint using the object_id and catalog_version from the pricing_rule_reference field. Make sure to set include_related_objects to true. For more information, see Integration with the Catalog API.

Note
Loyalty reward tiers currently include the deprecated definition field, which is replaced by the pricing_rule_reference field. When possible, you should use pricing_rule_reference.

For more information about Square loyalty programs, see Loyalty Program Overview. For information about how the Loyalty API integrates with other Square APIs, see Integration with the Orders API and Integration with the Customers API.

Create a loyalty account Permalink Get a link to this section

Call CreateLoyaltyAccount to create a loyalty account and enroll the buyer in a loyalty program. You must provide the following information for this request:

  • mapping and phone_number, with the buyer's phone number specified in E.164 format. You can obtain the phone number from your application flow. A given phone number can be mapped to only one loyalty account in a loyalty program.

  • program_id with the ID of the loyalty program. To get the program ID, call RetrieveLoyaltyProgram using the main keyword.

Create Loyalty Account
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
curl https://connect.squareupsandbox.com/v2/loyalty/accounts \
  -X POST \
  -H 'Square-Version: 2021-07-21' \
  -H 'Authorization: Bearer {ACCESS_TOKEN}' \
  -H 'Content-Type: application/json' \
  -d '{
    "loyalty_account": {
      "mapping": {
        "phone_number": "+16295551234"
      },
      "program_id": "8031c1b2-d749-4c76-9c40-ae5472ed2e04"
    },
    "idempotency_key": "{UNIQUE_KEY}"
  }'

Note

If you have the ID of the customer profile that is associated with the buyer, you should also include the customer_id field in the request. Doing so can help prevent creating duplicate customer profiles in the seller's Customer Directory. For more information, see Integration with the Customers API.

After receiving the request, Square does the following:

  • If customer_id is not specified, Square checks the directory to determine whether it contains a customer profile with the same phone number. If not, Square creates a customer profile using the buyer's phone number.

  • Creates an account in the specified loyalty program.

The following is an example response:

{
   "loyalty_account":{
      "id":"716cefbc-3d71-4d7c-bdc8-9c7f84c2d793",
      "mapping": {
        "id":"6377d589-3f09-4f00-a0e8-56d7dfc1d2b5",
        "phone_number":"+16295551234",
        "created_at":"2020-01-30T00:11:58Z"
      },
      "program_id":"8031c1b2-d749-4c76-9c40-ae5472ed2e04",
      "balance":0,
      "lifetime_points":0,
      "customer_id":"REK96J96AS5AN2Y8Z4HE2Z5NVX",
      "created_at":"2020-01-30T00:11:58Z",
      "updated_at":"2020-01-30T00:11:58Z"
   }
}

Both balance and lifetime_points are 0 because the buyer has not yet accrued any loyalty points.

The phone number that you provide to create a loyalty account must use the E.164 format (for example, +16295551234). The country code of the phone number must correspond to a country where Square Loyalty is available. Otherwise, the CreateLoyaltyAccount request returns an INVALID_PHONE_NUMBER error code.

Terms of service and text notifications Permalink Get a link to this section

After a loyalty account is created, Square can contact a buyer using the phone number provided and send text messages, such as "You have a reward available." However, the buyer must agree to the terms of service before Square can send any text messages. Buyers can agree to the terms of service when they enroll in a loyalty program from a Square Point of Sale application. They can also agree on the Loyalty status page after the account is created.

When you create an account through the Loyalty API, Square cannot show the terms of service until a buyer makes a purchase through a Point of Sale application. Therefore, unless the buyer agrees to the terms of service on the Loyalty status page, they cannot receive any text messages until they agree to the terms of service when they make a purchase.

Access loyalty accounts Permalink Get a link to this section

The Loyalty API provides two endpoints that you can use to access loyalty accounts:

You can use these endpoints to retrieve a buyer's loyalty account using an account ID, search for accounts by phone number or customer ID, or retrieve all loyalty accounts.

Retrieve a loyalty account Permalink Get a link to this section

Call RetrieveLoyaltyAccount if you know the ID of the loyalty account.

Retrieve Loyalty Account
  • 1
  • 2
  • 3
  • 4
curl https://connect.squareupsandbox.com/v2/loyalty/accounts/{account_id} \
  -H 'Square-Version: 2021-07-21' \
  -H 'Authorization: Bearer {ACCESS_TOKEN}' \
  -H 'Content-Type: application/json'

The following is an example RetrieveLoyaltyAccount response:

{
  "loyalty_account": {
    "id": "716cefbc-3d71-4d7c-bdc8-9c7f84c2d793",
    "mapping": {
      "id": "66aaab3f-da99-49ed-8b19-b87f824d73a4",
      "phone_number": "+16295551234",
      "created_at": "2020-01-30T00:11:58Z"
    },
    "program_id": "8031c1b2-d749-4c76-9c40-ae5472ed2e04",
    "balance": 10,
    "lifetime_points": 20,
    "customer_id": "Q8002F9Y7E9JJTJ5P6JKYYEM0BC7VPG",
    "created_at": "2020-05-08T21:44:32Z",
    "updated_at": "2020-05-08T21:44:32Z"
  }
}

If the account cannot be found, the Loyalty API returns a 404 NOT_FOUND error.

Search loyalty accounts Permalink Get a link to this section

Call SearchLoyaltyAccounts to search for accounts by phone number or customer ID, or to retrieve all loyalty accounts. A search query can contain the mappings field or the customer_ids field, but not both.

Loyalty accounts in the response are sorted by the created_at date in ascending order. If you search for phone number mappings or customer IDs, the API returns only the accounts that match the search criteria.

You can use the limit field to specify a maximum page size of 1 to 30 results. The default page size is 30.

Accumulate points from a purchase Permalink Get a link to this section

Buyers accrue points for the purchases they make. After the buyer pays for an order, call AccumulateLoyaltyPoints to add points to the buyer's account for the purchase. The information you send depends on whether you are using the Orders API to process orders.

  • If you are using the Orders API, provide the order ID in the order_id field of the request. Square computes the loyalty points using the purchase amount, and then adds the points to the account.

    Accumulate Loyalty Points
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    curl https://connect.squareupsandbox.com/v2/loyalty/accounts/{account_id}/accumulate \
      -X POST \
      -H 'Square-Version: 2021-07-21' \
      -H 'Authorization: Bearer {ACCESS_TOKEN}' \
      -H 'Content-Type: application/json' \
      -d '{
        "accumulate_points": {
          "order_id": "cb9LSpDgOH3rITBaZ6eIBb9ee4F"
        },
        "location_id": "S8GWD509MEHCA",
        "idempotency_key": "{UNIQUE_KEY}"
      }'
  • If you are using your own order processing system, and not the Orders API, you must compute the loyalty points on the client side and then specify the points in the points field of the request.

    Accumulate Loyalty Points
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    curl https://connect.squareupsandbox.com/v2/loyalty/accounts/{account_id}/accumulate \
      -X POST \
      -H 'Square-Version: 2021-07-21' \
      -H 'Authorization: Bearer {ACCESS_TOKEN}' \
      -H 'Content-Type: application/json' \
      -d '{
        "accumulate_points": {
          "points": 7
        },
        "location_id": "S8GWD509MEHCA",
        "idempotency_key": "{UNIQUE_KEY}"
      }'

    Note

    The country of the seller's Square account determines whether tax is included in the purchase amount when accruing points for amount-spent and visit-based programs. For more information, see Availability of Square Loyalty.

The following is an example AccumulateLoyaltyPoints response, which contains a LoyaltyEvent object. The Loyalty API generates a searchable loyalty event after each change to the loyalty point balance. For more information, see Loyalty events.

{
   "event": {
      "id": "bbd1ef00-92ac-3e5f-8887-cd3c6ba29313",
      "type": "ACCUMULATE_POINTS",
      "created_at": "2020-05-07T22:31:48Z",
      "accumulate_points": {
         "loyalty_program_id": "8031c1b2-d749-4c76-9c40-ae5472ed2e04",
         "points": 12,
         "order_id": "cb9LSpDgOH3rITBaZ6eIBb9ee4F"
      },
      "loyalty_account_id": "716cefbc-3d71-4d7c-bdc8-9c7f84c2d793",
      "location_id": "S8GWD5R9QB376",
      "source": "LOYALTY_API"
   }
}

Adjust points manually Permalink Get a link to this section

Call AdjustLoyaltyPoints to manually add or remove points from a loyalty account.

You should use this endpoint only when you need to add or remove points outside of the normal order-purchase flow. For example, you might give extra points for a special offer or remove points for a returned item. When buyers earn points from a purchase, you should use the AccumulateLoyaltyPoints endpoint.

  • To add points, specify a positive integer as the points value.

  • To remove points, specify a negative integer as the points value. This value must be greater than or equal to the current point balance in the loyalty account.

Adjust Loyalty Points
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
curl https://connect.squareupsandbox.com/v2/loyalty/accounts/{account_id}/adjust \
  -X POST \
  -H 'Square-Version: 2021-07-21' \
  -H 'Authorization: Bearer {ACCESS_TOKEN}' \
  -H 'Content-Type: application/json' \
  -d '{
    "adjust_points": {
      "points": 15,
      "reason": "Sign up bonus."
    },
    "idempotency_key": "{UNIQUE_KEY}"
  }'

The following is an example AdjustLoyaltyPoints response, which contains a LoyaltyEvent object. The Loyalty API generates a searchable loyalty event after each change to the loyalty point balance. For more information, see Loyalty events.

{
   "event": {
      "id": "e13a6fca-8d67-39d0-bbd2-3b4bC1beb38f",
      "type": "ADJUST_POINTS",
      "created_at": "2020-04-10T00:18:51Z",
      "adjust_points": {
         "loyalty_program_id": "8031c1b2-d749-4c76-9c40-ae5472ed2e04",
         "points": 15,
         "reason": "Sign up bonus."
      },
      "loyalty_account_id": "0146344c-77fa-4fa8-86db-4a4b8fec801",
      "source":"LOYALTY_API"
   }
}

Redeem loyalty rewards Permalink Get a link to this section

A loyalty program can have one or more reward tiers that define how buyers can redeem points for discounts. Higher reward tiers often offer better discounts, which encourages buyers to earn more points. For example:

  • Reward tier 1: Redeem 10 points for 10% off the entire purchase.

  • Reward tier 2: Redeem 15 points for 20% off the entire purchase.

While building the order, your application can offer discount options based on the point balance of the buyer's loyalty account. For example, if the balance is 12 points, you can offer the option to redeem reward tier 1. If the balance is 17 points, you can offer the option to redeem reward tier 2. For information about retrieving reward tier information, see Get discount details for a reward tier.

Create a reward Permalink Get a link to this section

If the buyer chooses to redeem points for a discount, call CreateLoyaltyReward to create a reward. Provide the following information in the request:

  • The ID of the buyer's loyalty account.

  • The ID of the reward tier.

  • The ID of the order, If the order was created with the Orders API. Integrating with the Orders API can simplify loyalty workflows.

Create Loyalty Reward
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
curl https://connect.squareupsandbox.com/v2/loyalty/rewards \
  -X POST \
  -H 'Square-Version: 2021-07-21' \
  -H 'Authorization: Bearer {ACCESS_TOKEN}' \
  -H 'Content-Type: application/json' \
  -d '{
    "reward": {
      "loyalty_account_id": "716cefbc-3d71-4d7c-bdc8-9c7f84c2d793",
      "reward_tier_id": "46c2716e-f559-4b75-c015-764897e3c4ae0",
      "order_id": "cb9LSpDgOH3rITBaZ6eIBb9ee4F"
    },
    "idempotency_key": "{UNIQUE_KEY}"
  }'

Did you know?

You can show buyers a preview of the discount before creating the reward. For more information, see Deferred reward creation.

The following is an example response, which includes the points required to redeem the reward.

{
  "reward":{
    "id": "6c1ac262-a066-3c0e-8386-5704eac36b86",
    "status": "ISSUED",
    "loyalty_account_id": "716cefbc-3d71-4d7c-bdc8-9c7f84c2d793",
    "reward_tier_id": "46c2716e-f559-4b75-c015-764897e3c4ae0",
    "points": 10,
    "order_id": "cb9LSpDgOH3rITBaZ6eIBb9ee4F",
    "created_at": "2020-03-13T00:00:51Z",
    "updated_at": "2020-03-13T00:00:51Z"
  }
}

When a reward is created, Square removes the points from the loyalty account balance. These points are held in reserve until the reward is redeemed or deleted.

Your integration with the Orders API determines whether Square updates the order or whether it is your responsibility:

  • Order ID specified: Square attaches the reward to the order, applies the corresponding discounts to qualifying line items, and adjusts the discount and total amounts accordingly.

  • No order ID specified: You must apply all appropriate discounts to the order.

Note

The Orders API allows you to add items and rewards to an order in any sequence. If you add a reward first, you should verify that the discounted item is part of the order. For example, if the reward gives the buyer a free coffee, make sure the order includes a coffee.

If an order ID was specified when creating the reward but the item is not included in the order, Square deletes the reward after the order is paid and returns the points to the buyer's loyalty account.

The steps required to redeem the reward and manage the order also depend on whether you specified the order ID in your CreateLoyaltyReward request. If you use the Orders API to manage orders, Square handles most of the remaining workflow.

Manage the reward state Permalink Get a link to this section

A loyalty reward can be in one of the following states:

  • ISSUED. The initial state of a reward. When a reward is created, the points required to redeem the reward are removed from the loyalty account and held in reserve until the reward is redeemed or deleted.

  • REDEEMED. The reward was redeemed. When a reward is redeemed, the reserved points are permanently deleted from the loyalty account.

  • DELETED. The reward was deleted. When a reward is deleted, the reserved points are returned to the loyalty account.

Note

REDEEMED and DELETED are terminal states. You cannot delete a redeemed reward in order to return points to a loyalty account. If you need to manually adjust the point balance of a loyalty account, call AdjustLoyaltyPoints.

The following common workflows can cause rewards to move from ISSUED to the REDEEMED or DELETED state. Your responsibility depends on whether an order ID was specified when creating the reward.

If the buyer pays for the order and receives the discount Permalink Get a link to this section

  • Order ID specified: Square sets the status to REDEEMED.

  • No order ID specified: You must call RedeemLoyaltyReward, which sets the status to REDEEMED.

If the buyer pays for the order but did not receive the discount Permalink Get a link to this section

  • Order ID specified: Square sets the status to DELETED.

  • No order ID specified: You must call DeleteLoyaltyReward, which sets the status to DELETED.

An example scenario for this workflow is when a buyer removes a discounted item from the order before paying for the order.

If the buyer chooses not to redeem a reward or abandons the order Permalink Get a link to this section

You must call DeleteLoyaltyReward, which sets the status to DELETED.

  • Order ID specified: Square removes the discount from the order and updates the order amount.

  • No order ID specified: You must also update the order appropriately.

For abandoned orders, you can determine the appropriate amount of time to wait before deleting dangling rewards, but it is your responsibility to clean them up. Otherwise, they remain in the ISSUED state and the reserved points cannot be used for other purchases.

Showing buyers a preview of the discount before creating the reward might help avoid creating dangling rewards. For more information, see Deferred reward creation.

Note

The operations involved in changing the reward state run asynchronously, so changes might not be immediately visible if you call RetrieveLoyaltyReward to retrieve the reward.

Integration with the Customers API Permalink Get a link to this section

All loyalty accounts have a customer_id field that associates the account with a customer profile in the seller's Customer Directory. This association enables integration features such as searching loyalty accounts by customer and accessing loyalty activity from the customer's Loyalty Summary card in the directory.

When you enroll a buyer in a loyalty program, you should provide the optional customer ID in the CreateLoyaltyAccount request when possible. Otherwise, Square uses the phone number provided in the request to search the directory for a matching customer profile. If a match is not found, Square creates a new customer profile and associates it with the loyalty account. However, this process might result in the creation of multiple customer profiles for a single buyer. For example, if a customer profile without a phone number was previously created for the buyer, it would not be returned in the phone number search and Square would create another customer profile.

Note

When Square creates a customer profile for a CreateLoyaltyAccount request, the creation_source field of the customer profile is set to LOYALTY.

Integration with the Orders API Permalink Get a link to this section

The Loyalty API is integrated with the Orders API and you should leverage this in your applications. Some of the benefits are:

  • A simplified point accrual flow. The following Loyalty API endpoints let you easily compute the points earned on orders created using the Orders API.

    Note

    The country of the seller's Square account determines whether tax is included in the purchase amount when accruing points for amount-spent and visit-based programs. For more information, see Availability of Square Loyalty.

  • A simplified reward redemption flow. The Loyalty API provides the CreateLoyaltyReward endpoint to create a reward and turn the reward into appropriate discounts by automatically updating the order. The Loyalty Walkthrough 1 and Loyalty Walkthrough 2 examples show how the integration works.

    The Orders API provides an added benefit when working with multiple discounts on an order. The pricing engine that Square provides can aggregate multiple discounts from various sources. Without the Orders API, you need to write code to accomplish this task.

  • Useful reporting in the Seller Dashboard. The reports in the Seller Dashboard provide useful metrics about how the loyalty program is working:

    • Visits report. The Visits report uses the order data to show the number of first-time (and repeat) loyalty buyers and the average visits by loyalty (and non-loyalty) buyers for a given period.

    • Sales report. The Sales report shows sales amounts by loyalty (and non-loyalty) buyers and the average amount spent by loyalty (and non-loyalty) buyers.

      The Seller Dashboard also shows the Top Customers report.

Depending on the program type, your development costs might be higher if you do not use the Orders API for order processing. However, the following loyalty programs are easy to implement without using the Orders API:

  • A loyalty program that offers visit-based accrual. Consider this VISIT accrual rule: "Earn one point for every visit, with a minimum purchase of $10." In this case, you can add points to the buyer's account with minimal code. You do not need itemized orders. For example, suppose a buyer pays $15 for an order. You can use the CalculateLoyaltyPoints endpoint to compute loyalty points and then call AccumulateLoyaltyPoints to add the points to the buyer's account.

  • A loyalty program that offers amount-spent accrual. Consider this SPEND accrual rule: "Earn one point for each dollar spent." You can use the CalculateLoyaltyPoints endpoint to compute loyalty points and then call AccumulateLoyaltyPoints to add the points to the loyalty account of the buyer. This does not require matching any order line items to compute the loyalty points.

Note that the accrual logic Square uses to calculate the number of points earned depends on the country of the seller's Square account. If you use the Orders API, these amounts are known and the points are computed appropriately without the need of additional code.

Integration with the Catalog API Permalink Get a link to this section

A loyalty program contains accrual rules and reward tiers.

An accrual rule defines how buyers can earn points. Loyalty programs can include one or more accrual rules, depending on the rule type. The following rule types integrate with the Catalog API:

  • CATEGORY accrual rules specify the catalog_object_id of the CATEGORY catalog object that qualifies for points accrual.

  • ITEM_VARIATION accrual rules specify the catalog_object_id of the ITEM_VARIATION catalog object that qualifies for points accrual.

  • SPEND accrual rules can optionally specify excluded_category_ids and excluded_item_variation_ids that contain the IDs of any CATEGORY and ITEM_VARIATION catalog objects that do not qualify for points accrual.

    To get information about the catalog objects used in accrual rules, you can call BatchRetrieveCatalogObjects in the Catalog API.

A reward tier defines how buyers can redeem points for discounts. Loyalty programs can include one or more reward tiers. For example, a reward tier might represent a reward such as "Redeem 10 points for 10% off your entire purchase." A loyalty reward tier uses PRICING_RULE, DISCOUNT, and PRODUCT_SET catalog objects to define the discount details for a reward.

Get discount details for a reward tier Permalink Get a link to this section

The following high-level steps describe how to get discount details and product information that correspond to the reward tiers in a loyalty program:

Step 1: Get the reward tiers for the loyalty program. Call RetrieveLoyaltyProgram in the Loyalty API. Then, check whether the loyalty account balance has enough points to qualify for a reward tier.

Step 2: Get discount details for the reward tier. Call RetrieveCatalogObject in the Catalog API to get the PRICING_RULE, DISCOUNT, and PRODUCT_SET catalog objects that define the discount for each qualifying reward tier. You must retrieve these objects at a specific catalog version.

Step 3: Get current product information. Call BatchRetrieveCatalogObjects in the Catalog API to get the CATEGORY and ITEM_VARIATION catalog objects that the discount applies to. This step applies to CATEGORY and ITEM_VARIATION scopes only and ensures that you show the most recent category or item information to the buyer.

Step 1: Get the reward tiers for the loyalty program Permalink Get a link to this section

To get the reward tiers for a loyalty program, call the RetrieveLoyaltyProgram endpoint.

Retrieve Loyalty Program
  • 1
  • 2
  • 3
  • 4
curl https://connect.squareupsandbox.com/v2/loyalty/programs/main \
  -H 'Square-Version: 2021-07-21' \
  -H 'Authorization: Bearer {ACCESS_TOKEN}' \
  -H 'Content-Type: application/json'

The following is an excerpt of a RetrieveLoyaltyProgram response. The reward_tiers field contains a list of LoyaltyProgramRewardTier objects that represent the reward tiers in the loyalty program.

{
  "program": {
    "id": "946651f0-229e-488c-bb97-183e34c20de6",
    "status": "ACTIVE",
    "reward_tiers": [
      {
        "id": "e1b39225-9da5-43d1-a5db-782c4e3c4ae0",
        "points": 10,
        "name": "10% off entire sale",
        "definition": {
          "scope": "ORDER",
          "discount_type": "FIXED_PERCENTAGE",
          "percentage_discount": "10"
        },
        "created_at": "2020-04-20T16:55:11Z",
        "pricing_rule_reference": {
          "object_id": "74C4JSHESNLTB2A7ITO5HO6F",
          "catalog_version": "1605486402527"
        }
      }
    ],
    ...
  }
}

Each reward tier in the response contains the following fields:

  • id. The reward tier ID that you use to create a loyalty reward for a buyer.

  • points. The number of points that must be redeemed to claim the reward.

  • name. The seller-defined name for the reward tier.

  • pricing_rule_reference. The specific version of a PRICING_RULE catalog object that defines the discount details for the reward tier.

Note

The RetrieveLoyaltyProgram response currently includes the deprecated definition field, which is replaced by the pricing_rule_reference field. You should use pricing_rule_reference.

Step 2: Get the discount details for the reward tier Permalink Get a link to this section

To get the discount details for a reward tier, call the RetrieveCatalogObject endpoint in the Catalog API. You must retrieve these objects at a specific catalog version. The request must:

  • Include the object_id and catalog_version from the corresponding pricing_rule_reference field.

  • Set include_related_objects to true to return all catalog objects that define discount details.

Retrieve Catalog Object
  • 1
  • 2
  • 3
  • 4
curl https://connect.squareupsandbox.com/v2/catalog/object/74C4JSHESNLTB2A7ITO5HO6F?include_related_objects=true&catalog_version=1605486402527 \
  -H 'Square-Version: 2021-07-21' \
  -H 'Authorization: Bearer {ACCESS_TOKEN}' \
  -H 'Content-Type: application/json'

The following table describes where you can find discount details in the PRICING_RULE, DISCOUNT, and PRODUCT_SET catalog objects from the response:

Discount propertyCatalog API mapping
Type of discount offered by the reward tierThe discount_data.discount_type field of the DISCOUNT catalog object.

Valid values are FIXED_AMOUNT or FIXED_PERCENTAGE.
Fixed percentage of a FIXED_PERCENTAGE discountThe discount_data.percentage field of the DISCOUNT catalog object.

This value is a string representation of a decimal number. For example, a 7.25% discount is represented as "7.25".
Maximum money amount of a FIXED_PERCENTAGE discountThe discount_data.maximum_amount_money field of the DISCOUNT catalog object.

Optional. This field is a Money object, which specifies amount using the smallest denomination.
Fixed money amount of a FIXED_AMOUNT discountThe discount_data.amount_money field of the DISCOUNT catalog object.

This field is a Money object, which specifies amount using the smallest denomination.
Scope of the rewardThe discount_target_scope field of the PRICING_RULE catalog object and the product_set_data field of the PRODUCT_SET catalog object. You can determine which items the discount applies to, as follows:

If the discount applies to the entire order:
discount_target_scope is WHOLE_PURCHASE.
product_set_data contains "all_products": true.

If the discount applies to specific categories of items:
discount_target_scope is LINE_ITEM.
product_set_data contains a product_ids_any field that references one or more CATEGORY catalog objects.

If the discount applies to specific items:
discount_target_scope is LINE_ITEM.
product_set_data contains a product_ids_any field that references one or more ITEM_VARIATION catalog objects.

The following are example RetrieveCatalogObject responses for the different scopes.

Example response for the order scope (entire sale)

{
  "object": {
    "type": "PRICING_RULE",
    "id": "L63DXGEYPJJTAM5JBX32ZBR5",
    "updated_at": "2020-12-16T22:48:32.75Z",
    "version": 1602888512750,
    "is_deleted": false,
    "present_at_all_locations": true,
    "pricing_rule_data": {
      "discount_id": "ZSWOAGU2E75BO7OI33AFIUMU",
      "match_products_id": "UHB65AGFKMS2IYVA7KHXMDYU",
      "application_mode": "ATTACHED",
      "discount_target_scope": "WHOLE_PURCHASE"
    }
  },
  "related_objects": [
    {
      "type": "DISCOUNT",
      "id": "ZSWOAGU2E75BO7OI33AFIUMU",
      "updated_at": "2020-12-16T22:48:32.75Z",
      "version": 1602888512750,
      "is_deleted": false,
      "present_at_all_locations": true,
      "discount_data": {
        "name": "$10.00 Off Entire Sale",
        "discount_type": "FIXED_AMOUNT",
        "amount_money": {
          "amount": 1000,
          "currency": "USD"
        },
        "application_method": "MANUALLY_APPLIED"
      }
    },
    {
      "type": "PRODUCT_SET",
      "id": "UHB65AGFKMS2IYVA7KHXMDYU",
      "updated_at": "2020-12-16T22:48:32.75Z",
      "version": 1602888512750,
      "is_deleted": false,
      "present_at_all_locations": true,
      "product_set_data": {
        "all_products": true
      }
    }
  ]
}

Example response for the category scope

{
  "object": {
    "type": "PRICING_RULE",
    "id": "74C4JSHESNLTB2A7ITO5HO6F",
    "updated_at": "2020-12-16T00:26:42.527Z",
    "version": 1605486402527,
    "is_deleted": false,
    "present_at_all_locations": true,
    "pricing_rule_data": {
      "discount_id": "ZLSTXZUW6BJED7ZZON4QZ4F5",
      "match_products_id": "RJM4MYXSBWZICCRS4N2B63QV",
      "application_mode": "ATTACHED",
      "discount_target_scope": "LINE_ITEM",
      "max_applications_per_attachment": 1
    }
  },
  "related_objects": [
    {
      "type": "DISCOUNT",
      "id": "ZLSTXZUW6BJED7ZZON4QZ4F5",
      "updated_at": "2020-12-16T00:26:42.527Z",
      "version": 1605486402527,
      "is_deleted": false,
      "present_at_all_locations": true,
      "discount_data": {
        "name": "50% Off One Hot Drink",
        "discount_type": "FIXED_PERCENTAGE",
        "percentage": "50.0",
        "application_method": "MANUALLY_APPLIED",
        "maximum_amount_money": {
          "amount": 250,
          "currency": "USD"
        }
      }
    },
    {
      "type": "PRODUCT_SET",
      "id": "RJM4MYXSBWZICCRS4N2B63QV",
      "updated_at": "2020-12-16T00:26:42.527Z",
      "version": 1605486402527,
      "is_deleted": false,
      "present_at_all_locations": true,
      "product_set_data": {
        "product_ids_any": [
          "TWCJXQJZMIAJJ3MQJNCWLCQG"
        ],
        "quantity_exact": 1
      }
    },
    {
      "type": "CATEGORY",
      "id": "TWCJXQJZMIAJJ3MQJNCWLCQG",
      ...
    }
  ]
}

Example response for the item variation scope

{
  "object": {
    "type": "PRICING_RULE",
    "id": "AZH2XITJVQQTYSWSOEXIW57Z",
    "updated_at": "2020-12-08T21:01:37.385Z",
    "version": 1607461297385,
    "is_deleted": false,
    "present_at_all_locations": true,
    "pricing_rule_data": {
      "discount_id": "2PS6ILT65FVO6UY227FZ4HGM",
      "match_products_id": "P35KAELYZUVV7YHR3DLCWRJN",
      "application_mode": "ATTACHED",
      "discount_target_scope": "LINE_ITEM",
      "max_applications_per_attachment": 1
    }
  },
  "related_objects": [
    {
      "type": "DISCOUNT",
      "id": "2PS6ILT65FVO6UY227FZ4HGM",
      "updated_at": "2020-12-08T21:01:37.385Z",
      "version": 1607461297385,
      "is_deleted": false,
      "present_at_all_locations": true,
      "discount_data": {
        "name": "20% Off Coffee Drinks",
        "discount_type": "FIXED_PERCENTAGE",
        "percentage": "20.0",
        "application_method": "MANUALLY_APPLIED"
      }
    },
    {
      "type": "PRODUCT_SET",
      "id": "P35KAELYZUVV7YHR3DLCWRJN",
      "updated_at": "2020-12-08T21:01:37.385Z",
      "version": 1607461297385,
      "is_deleted": false,
      "present_at_all_locations": true,
      "product_set_data": {
        "product_ids_any": [
          "QBIAVB2BWSPT2PYLPNAFJZ36",
          "MHXTR5VRKLXN767RCBTNB7YJ"
        ],
        "quantity_exact": 1
      }
    },
    {
      "type": "ITEM_VARIATION",
      "id": "QBIAVB2BWSPT2PYLPNAFJZ36",
      ...
    },
    {
      "type": "ITEM_VARIATION",
      "id": "MHXTR5VRKLXN767RCBTNB7YJ",
      ...
    }
  ]
} 

The following considerations apply to reward tier discount integrations:

  • Developers cannot use Square APIs to manage loyalty programs or reward tiers. To ensure that the discount details for a reward tier cannot be changed using the Catalog API, Square pins the corresponding pricing rule to a PRICING_RULE catalog object at a specific catalog version.

    When a seller updates the reward tier in the Seller Dashboard or Point of Sale application, a new pricing rule is created.

  • The Loyalty API does not use all fields in the PRICING_RULE, DISCOUNT, and PRODUCT_SET catalog objects. You can ignore fields that are not listed in the Catalog API mapping table, such as application_mode, max_applications_per_attachment, and application_method.

  • You should use the RetrieveCatalogObject endpoint to get discount details for a reward tier. Although the BatchRetrieveCatalogObject endpoint can also return catalog objects at a specific version, a single call might not return all pricing rules for a loyalty program because the corresponding PRICING_RULE catalog objects might belong to different versions.

Step 3: Get current product information Permalink Get a link to this section

To get the current product information for the catalog objects that are eligible for the discount, call the BatchRetrieveCatalogObjects or RetrieveCatalogObject endpoint in the Catalog API. This step ensures that you retrieve all updates made since the catalog version specified in the previous request, such as changes to an item's price.

Note

This step applies to CATEGORY and ITEM_VARIATION scopes; it does not apply to ORDER scopes. Depending on your application flow, you might have already retrieved the most current category or item information and can skip this step.

For this call, the request should:

  • Include the IDs from the product_set_data.product_ids_any field of the PRODUCT_SET catalog object from the previous request.

  • Not include the catalog_version field.

Batch Retrieve Catalog Objects
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
curl https://connect.squareupsandbox.com/v2/catalog/batch-retrieve \
  -X POST \
  -H 'Square-Version: 2021-07-21' \
  -H 'Authorization: Bearer {ACCESS_TOKEN}' \
  -H 'Content-Type: application/json' \
  -d '{
    "object_ids": [
      "QBIAVB2BWSPT2PYLPNAFJZ36",
      "MHXTR5VRKLXN767RCBTNB7YJ"
    ]
  }'

Webhooks Permalink Get a link to this section

You can subscribe to webhook notifications for the following loyalty events. All events require LOYALTY_READ permission.

Event Description
loyalty.account.created Published when a loyalty account is created for a buyer. A loyalty account can be created using any of the following methods, which all publish this event:
  • An application calls the CreateLoyaltyAccount endpoint.
  • A buyer enrolls in the program from a Square Point of Sale application.
  • The seller enrolls a buyer using the Customer Directory.
  • The seller merges two customer accounts into one account using the Customer Directory. In this process, sellers might merge the two corresponding loyalty accounts by creating a new account and deleting the existing accounts.
loyalty.account.updated Published for any updates to an existing loyalty account. For example:
  • The seller updates the phone number associated with a loyalty account using the Seller Dashboard. For more information, see Square Loyalty FAQ.
  • Any change in the loyalty point balance, such as points added for visits, points expiration, or a manual adjustment to the point balance that a seller might perform.
  • The customer ID of the loyalty account changes. Perhaps the loyalty account moves to another customer.
loyalty.account.deleted Published when a loyalty account is deleted. The published event does not contain the customer_id that was associated with the deleted account. The following actions to delete the account can publish this event:
  • The seller deletes an account using the Seller Dashboard.
  • The seller merges two customer accounts into one account using the Customer Directory. In this process, sellers might merge the two corresponding loyalty accounts by creating a new account and deleting the existing accounts.
loyalty.program.created Published when a loyalty program is created using the Seller Dashboard.
loyalty.program.updated Published when a loyalty program is updated using the Seller Dashboard.
loyalty.event.created Square Loyalty maintains a ledger of events that occur over the lifetime of a loyalty account. Square publishes notifications for each loyalty event logged to the ledger. These loyalty events are immutable, which means they are never updated or deleted. For example, when a buyer redeems a reward and then returns it, Square publishes separate notifications for the corresponding CREATE_REWARD and DELETE_REWARD events. Similarly, Square publishes a notification for the ADJUST_POINTS event when points are deducted after a purchase that accrued points is refunded.

All notifications include the corresponding loyalty account, event, or program object, as shown in the following excerpt of an example loyalty.account.created notification:

{
  "merchant_id": "6QJXJGB6AZFN7",
  "type": "loyalty.account.created",
  "event_id": "45957f82-1e7e-42a3-9532-a4e787c3344c",
  "created_at": "2021-07-13T17:37:11Z",
  "data": {
    "type": "loyalty.account",
    "id": "dd17bfc8-178a-456c-ba4e-dae5813d429f",
    "object": {
      "loyalty_account": {
        // loyalty account fields
      }
    }
  }
}

For more information about subscribing to events and validating notifications, see Square Webhooks.

Requirements and limitations Permalink Get a link to this section

The following requirements and limitations apply when integrating the Square loyalty program in applications using the Loyalty API. For more information about the loyalty program, including pricing information, see Square Loyalty.

Requirements Permalink Get a link to this section

  • Availability of Square Loyalty. Square Loyalty is currently available in the following countries: Australia, Canada, the United Kingdom (beta), and the United States. To be eligible to subscribe to Square Loyalty, the seller's Square account must be activated in a country where Square Loyalty is available. In addition, the country code of the phone number used to create a loyalty account must correspond to a country where Square Loyalty is available.

    Square applies the following accrual logic for SPEND program types and VISIT program types that have a minimum spend requirement:

    • Pretax versus post-tax purchase amounts. For seller accounts activated in Australia, Canada, and the United States, points are accrued based on the pretax purchase amount. For seller accounts activated in the United Kingdom, points are accrued based on the post-tax purchase amount.

    • Pretip purchase amounts. For all countries, points are accrued based on pretip purchase amounts.

    Square applies this accrual logic when you call AccumulateLoyaltyPoints or CalculateLoyaltyPoints and provide an order_id. If you are not using the Orders API to process orders, you should use the same logic to compute the points you provide to AccumulateLoyaltyPoints or the transaction_amount_money you provide to CalculateLoyaltyPoints.

  • The seller must have an active Square Loyalty subscription. You can call the RetrieveLoyaltyProgram endpoint to verify that the subscription has an ACTIVE status. If the seller is not an active subscriber, the CreateLoyaltyAccount, AdjustLoyaltyPoints, and AccumulateLoyaltyPoints endpoints return a BAD_REQUEST error and calls to other Loyalty API endpoints might fail.

    Sellers can also check their subscription status in the Seller Dashboard by choosing Accounts & Settings, Business, and then Pricing & Subscriptions. If the subscription expires, the Loyalty page displays a banner with the message "You are not currently subscribed to Square Loyalty."

Limitations Permalink Get a link to this section

  • A seller account can have only one loyalty program.

  • Loyalty programs can be configured only on the Loyalty page of the Seller Dashboard. The Loyalty API cannot be used to create or modify loyalty program settings.

  • If a reward tier references an invalid catalog item, or another condition prevents the Loyalty API from converting a reward tier, the RetrieveLoyaltyProgram and ListLoyaltyPrograms (deprecated) endpoints return an UNSUPPORTED_LOYALTY_REWARD_TIER error. If this occurs, contact Developer Support, join our Slack, or reach out to your Square Account Manager.

  • While redeeming multiple rewards of different tiers on the same order is supported, redeeming multiple rewards of the same tier on the same order is not supported.

  • When redeeming multiple rewards on the same order, only one reward can apply to each line item. Consequently, redeeming multiple whole purchase rewards leads to the highest discount being picked and others being ignored.

Advanced usage Permalink Get a link to this section

This section describes the following Loyalty API concepts:

Deferred reward creation Permalink Get a link to this section

In your application flow, you can show buyers a preview of how a loyalty reward would affect a purchase before you create the reward. Buyers can use this preview to decide whether they want to redeem the points.

By deferring reward creation until the buyer completes the order, you can avoid locking reward points prematurely. When a reward is created, the required points are removed from the loyalty account. The points are held in reserve and cannot be used for discounts on other purchases. For more information, see Redeem loyalty rewards.

For example, consider the following eCommerce checkout scenarios.

  • Window shopping. Buyers can add items to the cart and apply available discounts to see the effect on purchase price. They might keep the cart open for a long time without paying for it.

  • Abandoned carts. Buyers might never pay for items they added to the cart.

Both scenarios illustrate the benefit of deferring reward creation until the buyer completes the order. In such scenarios, you can call CalculateOrder in the Orders API to create a copy of an order with the specific rewards applied. Then, you can show the buyer the effect of applying the discounts. Later, when the buyer is ready to make a purchase, you can call CreateLoyaltyReward to create a reward.

The following example CalculateOrder request calculates the amounts for a non-catalog item order.

Calculate Order
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
curl https://connect.squareupsandbox.com/v2/orders/calculate \
  -X POST \
  -H 'Square-Version: 2021-07-21' \
  -H 'Authorization: Bearer {ACCESS_TOKEN}' \
  -H 'Content-Type: application/json' \
  -d '{
    "order": {
      "line_items": [
        {
          "name": "Unisex Poncho",
          "quantity": "1",
          "base_price_money": {
            "amount": 4200,
            "currency": "USD"
          }
        }
      ],
      "location_id": "S8GWD5R9QB376"
    },
    "proposed_rewards": [
      {
        "id": "some-random-id",
        "reward_tier_id": "b525f003-47ea-43aa-bb18-6d12Ca04c73b"
      }
    ]
  }'

For the order object, you can provide an existing order or a draft order that is not yet created:

  • Existing order. If you know the order ID, you can call RetrieveOrder to retrieve the order and pass the entire order object in the request body.

  • Draft order. You can build a draft order object and pass it in the request body, as shown in the preceding example (an order without an order ID). Use the same object that you would send to the CreateOrder endpoint.

For the proposed_rewards field, provide the following:

  • reward_tier_id. The ID of the reward tier from the loyalty program.

  • id. A random string that serves as the ID for the simulated reward.

The following is an example response that provides a preview of the order with the applied discount.

{
  "order": {
    "location_id": "S8GWD5R9QB376",
    "line_items": [
      {
        "uid": "HFROFMx2MckcvMe7pkU23",
        "quantity": "1",
        "name": "Unisex Poncho",
        "base_price_money": {
          "amount": 4200,
          "currency": "USD"
        },
        "gross_sales_money": {
          "amount": 4200,
          "currency": "USD"
        },
        "total_tax_money": {
          "amount": 0,
          "currency": "USD"
        },
        "total_discount_money": {
          "amount": 420,
          "currency": "USD"
        },
        "total_money": {
          "amount": 3780,
          "currency": "USD"
        },
        "variation_total_price_money": {
          "amount": 4200,
          "currency": "USD"
        },
        "applied_discounts": [
          {
            "uid": "QcKsxjGUDfNWZT8oi80ncK",
            "discount_uid": "XOzfxZ6LaeTjL66knISe4F",
            "applied_money": {
              "amount": 420,
              "currency": "USD"
            }
          }
        ]
      }
    ],
    "discounts": [
      {
        "uid": "XOzfxZ6LaeTjL66eaK4Ile",
        "catalog_object_id": "RU4L3FVPCAZ5WR2SKVPS4IZE",
        "name": "10% off entire sale (up to $50.00 off)",
        "percentage": "10.0",
        "applied_money": {
          "amount": 420,
          "currency": "USD"
        },
        "type": "FIXED_PERCENTAGE",
        "scope": "LINE_ITEM",
        "reward_ids": [
          "random-reward-id"
        ],
        "pricing_rule_id": "JNKW5IZGLA6JI2EFW2GMWTHX"
      }
    ],
    "created_at": "2021-02-27T00:12:52.857Z",
    "updated_at": "2021-02-27T00:12:52.857Z",
    "state": "OPEN",
    "version": 1,
    "total_tax_money": {
      "amount": 0,
      "currency": "USD"
    },
    "total_discount_money": {
      "amount": 420,
      "currency": "USD"
    },
    "total_tip_money": {
      "amount": 0,
      "currency": "USD"
    },
    "total_money": {
      "amount": 3780,
      "currency": "USD"
    },
    "total_service_charge_money": {
      "amount": 0,
      "currency": "USD"
    },
    "net_amounts": {
      "total_money": {
        "amount": 3780,
        "currency": "USD"
      },
      "tax_money": {
        "amount": 0,
        "currency": "USD"
      },
      "discount_money": {
        "amount": 420,
        "currency": "USD"
      },
      "tip_money": {
        "amount": 0,
        "currency": "USD"
      },
      "service_charge_money": {
        "amount": 0,
        "currency": "USD"
      }
    },
    "rewards": [
      {
        "id": "some-random-id",
        "reward_tier_id": "b525f003-47ea-43aa-bb18-6d12Ca04c73b"
      }
    ]
  }
}

Note the following fields in the response:

  • The total_discount_money, total_money, and discount_money amounts for the order and line item are updated with the applied discount.

  • The discounts field is added to the order. The discount contains information about the applied discount.

  • The applied_discounts field is added to the line item. The discount maps to the order-level discount.

  • The rewards field is added to the order. This simulated reward contains the reward and reward tier IDs you provided in the proposed_rewards field of the request.

Multiple redemption Permalink Get a link to this section

In a simple scenario, applications might allow a buyer to redeem only one reward per order. The application flow is simple: show the rewards the buyer qualifies for (for example, a free coffee for 10 points and a free sandwich for 15 points) and let the buyer make the choice. After the buyer chooses a reward, the point balance is adjusted accordingly.

Alternatively, applications (such as Square Point of Sale) can allow buyers to redeem multiple rewards per order. To provide a consistent experience, your application can also allow multiple redemptions. In this scenario, your application must track changes to the loyalty point balance when buyers add or remove rewards, as follows:

  • If your application immediately calls CreateLoyaltyReward each time the buyer adds a reward or DeleteLoyaltyReward each time the buyer removes a reward, the loyalty account reflects the latest point balance. You can call RetrieveLoyaltyAccount to fetch the updated balance.

  • If your application uses the deferred reward creation approach as buyers add and remove rewards, the buyer's loyalty account does not accurately reflect the available point balance. In this case, your application must keep track of the available point balance on the client side. You can use the following logic to track the available point balance on the client side:

    var availableBalance = getLoyaltyAccount().balance
    var allTiers = getLoyaltyProgram().reward_tiers
    var selectedTiers = []
    
    // Use this logic to determine which tiers are available to the buyer
    function getAvailableTiers() {
      var availableTiers = []
      for (tier : allTiers) {
        if (availableBalance >= tier.points) {
          availableTiers.push(tier)
        }
      }
      return availableTiers
    }
    
    // Use this logic when the buyer selects a tier
    function selectTier(rewardTier) {
      selectedTiers.push(rewardTier)
      availableBalance -= rewardTier.points
    }
    

When you apply multiple rewards to an order, the Square pricing engine applies discounts so that they maximize the reward value in the buyer's favor. Therefore, discounts might be rearranged as more rewards are added to the order. For example, consider the following scenario:

  • Your cart contains one tea for $4 and one coffee for $2.

  • You offer two rewards: a Free Drink and a Free Tea.

If you first add the Free Drink reward to the order, Square discounts the tea because it is more expensive. If you then add the Free Tea reward, the Free Drink discount is moved from the tea to the coffee, so the Free Tea reward can be applied to the tea.

Note

See the Limitations section for other considerations related to multiple redemptions.

Loyalty events Permalink Get a link to this section

Square Loyalty maintains a ledger of events that occur during the lifetime of a buyer's loyalty account. Each point balance change is recorded in the ledger. For example, the following activities cause an event to be added to the ledger:

  • A buyer earns points.

  • A buyer redeems a reward.

  • Loyalty points expire.

You can use the SearchLoyaltyEvents endpoint to search the ledger for events. You can also use this endpoint to get status information for your buyer-facing loyalty status page. For example, the Activity section of the Seller Dashboard displays information from the ledger.

In the search request, you can optionally specify query filters. The endpoint processes the filters as follows:

  • Uses a logical AND to evaluate multiple filters, such as loyalty_account_filter and date_time_filter.

  • Uses a logical OR to evaluate values in an array field, such as location_ids.

The following is an example SearchLoyaltyEvents request. The endpoint processes the specified filter as follows:

  • Performs a logical AND of the following query filters: loyalty_account_filter, date_time_filter, type_filter, and location_filter.

  • Performs a logical OR for the values in the following array fields: types and location_ids.

The request also sets the limit field to specify a maximum page size of 30 results.

Search Loyalty Events
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
curl https://connect.squareupsandbox.com/v2/loyalty/events/search \
  -X POST \
  -H 'Square-Version: 2021-07-21' \
  -H 'Authorization: Bearer {ACCESS_TOKEN}' \
  -H 'Content-Type: application/json' \
  -d '{
    "query": {
      "filter": {
        "loyalty_account_filter": {
          "loyalty_account_id": "716cefbc-3d71-4d7c-bdc8-9c7f84c2d793"
        },
        "date_time_filter": {
          "created_at": {
            "start_at": "2020-01-01T00:00:00Z",
            "end_at": "2020-12-31T00:00:00Z"
          }
        },
        "type_filter": {
          "types": [
            "ACCUMULATE_POINTS",
            "CREATE_REWARD"
          ]
        },
        "location_filter": {
          "location_ids": [
            "M3AK818160XGR",
            "LB43CCKZBPJRZ"
          ]
        }
      }
    },
    "limit": 30
  }'

The endpoint returns all loyalty events for the loyalty account of the buyer ordered by the created_at timestamp in descending order. For the list of valid loyalty events for the type_filter field, see LoyaltyEventType.

Migration notes Permalink Get a link to this section

Deprecated ListLoyaltyPrograms endpoint

The ListLoyaltyPrograms endpoint is deprecated. It is replaced by calling the RetrieveLoyaltyProgram endpoint with the main keyword. Both endpoints are used to return the single loyalty program for a seller account.

Deprecated in version: 2021-05-13
Retired in version: 2022-05-13

To migrate to the RetrieveLoyaltyProgram endpoint, do the following:

  1. Update your requests. Make sure to include the main keyword in your RetrieveLoyaltyProgram request:

    Retrieve Loyalty Program
    • 1
    • 2
    • 3
    • 4
    curl https://connect.squareupsandbox.com/v2/loyalty/programs/main \
      -H 'Square-Version: 2021-07-21' \
      -H 'Authorization: Bearer {ACCESS_TOKEN}' \
      -H 'Content-Type: application/json'
  2. Update code that handles responses. You must also update your code to handle the RetrieveLoyaltyProgram response, which returns a top-level program object instead of a programs array. The following excerpts show the difference between the responses from the two endpoints.

    Excerpt from a RetrieveLoyaltyProgram response that returns a program object:

    {
      "program": {
        // program details
      }
    }
    

    Excerpt from a ListLoyaltyPrograms (deprecated) response that returns a programs array:

    {
      "programs": [
        {
          // program details
        }
      ]
    }
    

Retired mappings, type, and value fields

A loyalty account mapping is used to associate the loyalty account with a buyer by phone number. The following mapping-related fields are retired:

In Square version 2021-05-13 and higher:

  • The mappings field is not accepted in CreateLoyaltyAccount requests.

  • The type and value fields are not accepted in CreateLoyaltyAccount or SearchLoyaltyAccounts requests.

  • The mappings, type, and value fields are not returned in responses.

To migrate to the required mapping implementation, do the following:

  1. Update your requests.

    • In your CreateLoyaltyAccount requests, you must use mapping and phone_number instead of mappings, type, and value, as shown in the following example:

      Create Loyalty Account
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      curl https://connect.squareupsandbox.com/v2/loyalty/accounts \
        -X POST \
        -H 'Square-Version: 2021-07-21' \
        -H 'Authorization: Bearer {ACCESS_TOKEN}' \
        -H 'Content-Type: application/json' \
        -d '{
          "loyalty_account": {
            "mapping": {
              "phone_number": "+16295551234"
            },
            "program_id": "8031c1b2-d749-4c76-9c40-ae5472ed2e04"
          },
          "idempotency_key": "{UNIQUE_KEY}"
        }'
    • In your SearchLoyaltyAccounts requests that query by phone number, you must use phone_number instead of type and value, as shown in the following example. Note that mappings is still a valid search query filter.

      Search Loyalty Accounts
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      curl https://connect.squareupsandbox.com/v2/loyalty/accounts/search \
        -X POST \
        -H 'Square-Version: 2021-07-21' \
        -H 'Authorization: Bearer {ACCESS_TOKEN}' \
        -H 'Content-Type: application/json' \
        -d '{
          "query": {
            "mappings": [
              {
                "phone_number": "+16295551234"
              },
              {
                "phone_number": "+12085556789"
              }
            ]
          }
        }'
  2. Update code that handles responses. You must update your code to handle returned loyalty accounts that include only the mapping and phone_number fields. The following example responses show the changes in a returned loyalty_account object.

    Example CreateLoyaltyAccount response in Square version 2021-05-13 and higher:

    {
       "loyalty_account":{
          "id":"716cefbc-3d71-4d7c-bdc8-9c7f84c2d793",
          "mapping": {
            "id":"6377d589-3f09-4f00-a0e8-56d7dfc1d2b5",
            "phone_number":"+16295551234",
            "created_at":"2020-01-30T00:11:58Z"
          },
          "program_id":"8031c1b2-d749-4c76-9c40-ae5472ed2e04",
          "balance":0,
          "lifetime_points":0,
          "customer_id":"REK96J96AS5AN2Y8Z4HE2Z5NVX",
          "created_at":"2020-01-30T00:11:58Z",
          "updated_at":"2020-01-30T00:11:58Z"
       }
    }
    

    Example CreateLoyaltyAccount response in Square version 2021-04-21:

    {
       "loyalty_account":{
          "id":"716cefbc-3d71-4d7c-bdc8-9c7f84c2d793",
          "mappings":[
            {
              "id":"6377d589-3f09-4f00-a0e8-56d7dfc1d2b5",
              "type":"PHONE",
              "value":"+16295551234",
              "phone_number":"+16295551234",
              "created_at":"2020-01-30T00:11:58Z"
            }
          ],
          "mapping": {
            "id":"6377d589-3f09-4f00-a0e8-56d7dfc1d2b5",
            "type":"PHONE",
            "value":"+16295551234",
            "phone_number":"+16295551234",
            "created_at":"2020-01-30T00:11:58Z"
          },
          "program_id":"8031c1b2-d749-4c76-9c40-ae5472ed2e04",
          "balance":0,
          "lifetime_points":0,
          "customer_id":"REK96J96AS5AN2Y8Z4HE2Z5NVX",
          "created_at":"2020-01-30T00:11:58Z",
          "updated_at":"2020-01-30T00:11:58Z"
       }
    }
    

    Note

    The mapping field was added in Square version 2021-04-21, so earlier versions only return mappings.