Skip to main content
This page lists every developer-facing change to the Loyalty Admin API, the Storefront API, Shopify Flow and the Partner Framework, newest first. Each entry is dated the day the change reached production.
  • Additive changes (new endpoints, new response fields, new optional parameters, new values of an existing field) don’t break a client that ignores what it doesn’t know. Parse JSON leniently and don’t treat enum fields as closed lists.
  • Entries tagged Action required may need a code change in your integration. Each one says who is affected and what to do.
  • The API reference is generated from the live API, so it always shows the current contract. The Admin API base URL is https://loyalty-admin.appstle.com, and Storefront API paths start with /loyalty/cp/api/.
Admin APIShopify FlowBreaking changeAction required
Points, approvals, birth dates

Stricter validation on points, approvals and birth dates

These calls now return 400 for requests they used to accept. The problem title in the response says what’s wrong.
  • POST /api/external/add-points and POST /api/external/remove-points reject a points value of 0 or less with the title Points must be greater than 0. Until now, 0 and negative values were accepted. To take points away, call remove-points with a positive number.
  • add-points rejects an earnRuleId whose earn rule is turned off, with the title Point Earn Rule is not active. It already rejected an unknown rule and a rule outside its scheduled dates. The same check applies to the Rule Id field of the Shopify Flow Add Points action.
  • PUT /api/external/approve-pending-transactions approves every pending transaction only when you set approveAllPendingTransactions=true. A call that sends no approval list (or an empty one) and leaves out approveAllPendingTransactions now returns 400 with the title Please provide an approval list or set approveAllPendingTransactions to true. Until now, that call returned 204 and approved every pending transaction in the store.
  • PUT /api/external/update-customer-birth-date validates dob the way the Storefront API already did. A missing dob, a year before 1900 or a date in the future returns 400 with the title UserGeneratedError:Please enter a valid birthdate. When you send dobYearProvided: false, only a missing dob is rejected. An unknown customerId now returns 400 with the title Customer not found using this customerID instead of an empty 500.
Who is affected: integrations that send 0 or negative points, pass the ID of a turned-off earn rule, call approve-pending-transactions without a list to approve everything, or send birth dates without validating them.Action required: send a positive points value, and send an earnRuleId only for an active earn rule. To approve every pending transaction, set approveAllPendingTransactions=true. Validate birth dates before you send them. Handle 400 on these calls and log the title.

Reference corrections

The API reference now matches what these endpoints have always done. Their behavior didn’t change.
  • GET /api/external/customer-loyalty returns 400, not 404, when the customer isn’t found. The title is Customer not found using this customerID, Customer not found using this email, or Customer info not found when you send neither customerId nor customerEmail. Without status, only UNUSED rewards are returned. status takes one or more of UNUSED, USED, EXPIRED, SUBSCRIPTION_ACTIVE, REFUNDED and CANCELED, separated by commas, and any other value returns 400.
  • PUT /api/external/check-discount returns the reward whatever its status, so check status before you apply the code. An unknown code returns 400 with the title Discount is not found, not 404.
  • When the earn rule you pass to add-points requires manual approval, the points stay pending until you approve them with approve-pending-transactions.
Reference: Add points to customer account, Remove points from customer account, Approve pending point transactions, Update customer birth date, Get customer loyalty details, Check discount code validity.
Storefront APINew fields
Social media points
When POST /loyalty/cp/api/claim-social-media-points awards points, the response includes redirectUrl, the social media link set on the earn rule. Open it for the customer after the claim. A refused claim returns redirectUrl as null.Reference: Claim social media reward points.
Shopify FlowBehavior change
Flow points actions

Add Points and Remove Points apply once per action run

Shopify Flow resends an action with the same action run ID when it doesn’t get a response in time. The Add Points and Remove Points actions now apply the points once per action run, so a resent action no longer adds or removes them a second time.Who is affected: workflows that guard against doubled points, for example with a tag check before the action. You can remove that guard.Reference: Shopify Flow.
Storefront APINew endpoint
Rewards

Return an unused reward for its points

New POST /loyalty/cp/api/return-reward/{rewardId} lets a signed-in customer hand back a reward they haven’t used and get its points back. The discount code is removed from Shopify and the points are credited as a REDEEM_REVERSAL transaction. The response is the customer’s updated loyalty details, in the same shape as redeem-points returns.It works only when the merchant has turned on Let customers return unused rewards in Advanced Settings. Only a discount code the customer bought with points can be returned, and only while it’s unused and hasn’t expired. Store credit and gifted rewards (VIP tier, birthday, referral) can’t be returned.Otherwise the call returns 400. The title explains why, and message is error. followed by one of rewardReturnDisabled, idnotfound, rewardNotUnused, rewardNotReturnable, rewardExpired, rewardUsageUnverified or rewardActionInProgress. The last two are temporary, so the customer can try again.Who is affected: storefronts that list a customer’s rewards. Nothing changes until you call the endpoint.Reference: Return an unused reward for its points.
Admin APIBehavior changeAction required
API keys

Merchants can revoke the legacy API key

In the Appstle admin, under More → API Integrations, the Legacy API Key card has a Revoke button. After a merchant revokes it, every request that sends that key returns 401 with {"status":401,"detail":"Invalid authentication"}, the same response as any other wrong key (see Error responses). Appstle doesn’t issue a replacement. Keys that start with apst_ aren’t affected.Who is affected: integrations that still send the legacy key, the one the app showed before apst_ keys existed.Action required: create an apst_ key under More → API Integrations and move your integration to it before the merchant revokes the legacy key.
Admin APINew fields
Widget labels

Hover labels for reward activation and expiry

GET /api/external/widget-labels returns two new label fields: rewardActivationDelayHoverLabel and rewardExpirationHoverLabel.Reference: List storefront widget label translations.
Admin APIStorefront APIBehavior changeNew fields
Redemptions, earn rules

Redeeming a reward can fail when its Shopify discount has expired

POST /api/external/redeem-points and POST /loyalty/cp/api/redeem-points now return 400 with the title UserGeneratedError:This reward is temporarily unavailable. Please try again later or contact the store. when the Shopify discount behind the redeem rule has expired. Before, Appstle issued a code that Shopify then rejected at checkout, and the customer lost the points. Since October 22, Appstle first tries to renew the expired discount and returns this error only when it can’t. The customer’s points aren’t deducted when the call fails.Show the title to the customer or log it, and retry later. Tell the merchant to check the redeem rule’s discount in Shopify.

Subscription and sign-up settings on earn rules

GET /api/external/point-earn-rules returns three new booleans on each rule:
  • earnOnInitialSubscriptionOrder and earnOnRecurringSubscriptionOrder say whether a purchase rule awards points for subscription products on a subscription’s first order and on its renewal orders. When one is missing, treat it as true.
  • awardExistingCustomers applies to the sign-up rule. When it’s true, customers who joined before the rule was created can still earn its points. When it’s missing, treat it as false.
Reference: Redeem customer points for rewards, Get all point earning rules.
Admin APINew fields
Widget labels

Greeting icon in widget settings

GET /api/external/widget-labels returns a new field, customerGreetingsIcon.Reference: List storefront widget label translations.
Admin APINew fields
Earn rules

Recurring schedule on earn rules

GET /api/external/point-earn-rules returns ruleRecurrence, a JSON string that limits a rule to certain days on top of its start and end dates. It holds two lists: weeks, the weeks of the month (week 1 is days 1 to 7), and days, the days of the week (MONDAY to SUNDAY). Both are read in the store’s time zone, and an empty list means any week or any day. ruleRecurrence is empty when a rule has no recurrence.Reference: Get all point earning rules.
Admin APIStorefront APINew enum valueNew fieldsAction required
Referrals

Error key for self-referrals

  • GET and POST /loyalty/cp/api/referral-rules/accept-offer return errorKey SELF_REFERRAL when a customer tries to accept their own referral offer. The response was already 400 with status FAILED. Until now, errorKey was empty for this case.
  • GET /api/external/widget-labels returns selfReferralErrorLabel, the text to show for that error.
Who is affected: clients that map errorKey to a fixed list of values.Action required: accept values you don’t recognize.Reference: Accept referral offer (POST).
Admin APINew fields
Widget labels

Label for unused rewards

GET /api/external/widget-labels returns a new field, unusedRewardsLabel.Reference: List storefront widget label translations.
Admin APIStorefront APINew fields
Referrals

existingCustomer on referral offers

GET and POST /loyalty/cp/api/referral-rules/accept-offer return existingCustomer (boolean). On success, it’s true when the referred email already belongs to a customer of the store. GET /api/external/widget-labels returns referralExistingCustomerAcceptedText.Reference: Accept referral offer (POST).
Admin APIStorefront APIBehavior changeAction required
Redemptions

Turned-off redeem rules can’t be redeemed

POST /api/external/redeem-points and POST /loyalty/cp/api/redeem-points return 400 with the title Redeem rule not available when the redeem rule is turned off, the same title as for an unknown rule. Until now, a turned-off rule could still be redeemed through the API.Who is affected: integrations that store redeem rule IDs and keep using them after the merchant turns a rule off.Action required: take redeem rule IDs from GET /api/external/point-redeem-rules, which lists only active rules, and handle 400 on redeem-points.Reference: Redeem customer points for rewards, Get all point redemption rules.
Admin APIStorefront APINew fieldsAction required
Rewards

Delayed reward activation

  • Redeem rules (GET /api/external/point-redeem-rules) return activationDelayDays, the number of days before a redeemed reward becomes usable.
  • Rewards in customer-loyalty, add-points, add-credits, redeem-points, remove-points and update-discount-code-status responses carry activeFrom, the date the reward becomes usable. check-discount and update-discount return activeFrom too.
  • The Storefront API returns rewards[].activeFrom from GET /loyalty/cp/api/customer-loyalty and POST /loyalty/cp/api/redeem-points.
Who is affected: integrations that show reward codes to customers.Action required: check activeFrom first so you don’t present a code that doesn’t work yet.Reference: Get all point redemption rules, Get customer loyalty details.
Storefront APIBreaking changeNew enum valueAction required
Storefront API writes, social media points

Storefront API writes need X-Requested-With

Every Storefront API request that isn’t a GET, HEAD or OPTIONS must send the header X-Requested-With: XMLHttpRequest. Without it, the call returns 401 with {"status":401,"detail":"Invalid authentication"}, even for a signed-in customer.Who is affected: storefront code that sends a Storefront API POST, PUT or DELETE without that header.Action required: add X-Requested-With: XMLHttpRequest to every Storefront API write call.

New refusal reason for social media claims

POST /loyalty/cp/api/claim-social-media-points can return awarded false with the reason CREDIT_PENDING_RECONCILIATION. This happens only for earn rules that give store credit: the claim is recorded, but Appstle couldn’t confirm that the store credit was added. The message asks the customer to contact support before trying again.Who is affected: clients that map reason to a fixed list of values.Action required: accept reason values you don’t recognize, and show the message for them.Reference: Enroll customer in loyalty program, Claim social media reward points.
Admin APINew fields
Redeem rules

excludeProductData on redeem rules

GET /api/external/point-redeem-rules returns excludeProductData on each rule: a JSON string that lists the products and variants the reward’s discount doesn’t apply to. It’s empty when nothing is excluded.Reference: Get all point redemption rules.
Admin APINew fields
Widget labels

Earn rule description labels

GET /api/external/widget-labels returns three new label fields: buyProductRuleDescriptionLabel, buyProductFromCollectionRuleDescriptionLabel and earnRuleShowMoreLabel.Reference: List storefront widget label translations.
Admin APIStorefront APINew fields
Birthdays

Birth year is optional on birthday updates

  • PUT /api/external/update-customer-birth-date and POST /loyalty/cp/api/update-customer-birth-date accept dobYearProvided (boolean). When false, the year in dob is a placeholder and only the month and day are used to match birthday rewards. It defaults to true when omitted, so existing clients behave as before.
  • customer-loyalty, add-points, add-credits, redeem-points, remove-points, update-discount-code-status and update-customer-birth-date responses return dobYearProvided, and so does POST /loyalty/cp/api/update-customer-status.
  • The birthday earn rule returns collectBirthYear. When it’s false, the merchant has turned off Ask for birth year, so collect only the month and day and send dobYearProvided: false. When it’s missing, treat it as true.
Who is affected: integrations that collect birthdays without a year. Send dobYearProvided: false with a placeholder year in dob.Reference: Update customer birth date.
Admin APIStorefront APINew enum valueAction required
Point transactions

New transaction rule REDEEM_REVERSAL

The transactionRule field of a point transaction can now be REDEEM_REVERSAL, recorded when the points from a redeemed reward are returned to the customer. It isn’t counted as newly earned points. The other values are ADJUSTMENT, EARN_RULE, REDEEM_RULE and REFERRAL. It appears in GET /api/external/point-transaction-history/{customer_id} and GET /loyalty/cp/api/transaction-by-shop.Who is affected: clients that map transactionRule to a fixed list of values.Action required: accept values you don’t recognize.Reference: Get customer point transaction history.
Storefront APIBreaking changeAction required
Birthdays

Customers can’t change a birth date that’s already set

POST /loyalty/cp/api/update-customer-birth-date no longer changes a birth date the customer already has. It returns 400 with the title UserGeneratedError:Birthdate has already been set. Please contact the store to update it. and leaves the birth date as it is. A customer who has no birth date can still set one.Who is affected: storefronts that let signed-in customers change their birthday.Action required: don’t offer customers a way to change a birth date once it’s set. To change one, call PUT /api/external/update-customer-birth-date from your server, which doesn’t have this restriction.Reference: Update customer birth date, Update customer birth date (Admin API).
Admin APIStorefront APINew fieldsBreaking changeAction required
Redeem rules, customer updates

Discount expiry on redeem rules

GET /api/external/point-redeem-rules returns discountExpirationType (DAY, MONTH or YEAR), discountExpirationValue and enableDiscountExpirationOverride on each rule.

Birthday and status updates return only the profile

POST /loyalty/cp/api/update-customer-birth-date and POST /loyalty/cp/api/update-customer-status return a smaller customer object. Only the profile fields are filled in: shop, customerId, firstName, lastName, displayName, email, dob, status and loyaltyProgramEnabled. The counters completedActivities, rewardClaimed, referrals and totalRevenue are always 0, and every other field is null, including id, availablePoints, pendingPoints, availableStoreCredits and vipTier. Until now, these calls returned the customer’s full record. The API reference lists more fields, such as totalEarnedPoints, but they’re always null here.Who is affected: storefront code that reads points, store credit or the VIP tier from these responses.Action required: after the call, read availablePoints, storeCreditBalance and currentVipTier from GET /loyalty/cp/api/customer-loyalty.Reference: Get all point redemption rules, Update customer birth date, Update customer loyalty status.
Storefront APINew endpointBreaking changeAction required
Reviews, session checks

Submit a review from an invitation

New POST /loyalty/cp/api/submit-review/{reviewToken} submits a product review from a review invitation. reviewToken comes from the invitation, and the body takes rating (1 to 5), title and body. An invalid token returns 400 with the title Invalid review token, and a rating outside 1 to 5 returns 400 with the title Rating must be between 1 and 5.

Storefront requests must match the session

The Storefront API now checks the customerId and shop you send against the signed-in customer’s session:
  • A customerId in the request body or query string that isn’t the signed-in customer’s returns 403 with the detail Customer does not match the authenticated session. The bodies of redeem-points, submit-review, update-customer-birth-date and update-customer-status have a customerId field.
  • A shop in the request body that names another store returns 403 with the detail Shop does not match the authenticated session. submit-review is the only endpoint whose body has a shop field.
Until now, these endpoints ignored both values and used the session’s customer and store.Who is affected: storefront code that sends customerId or shop, for example in a body copied from the API reference, whose examples still show customerId.Action required: leave customerId and shop out of Storefront API requests. The session already identifies the customer and the store.Reference: Submit an invited review, Submit product review, Redeem customer loyalty points, Update customer birth date, Update customer loyalty status.
Partner FrameworkBehavior changeAction required
Partner authentication

One error for every failed partner authentication

connect, initiate-connect, verify, disconnect and status under /api/partner/{partnerId}/ now return the same error for every authentication failure: 400 with the errorKey TOKEN_INVALID and the title UserGeneratedError:Invalid partner credentials. That covers a Partner ID that is wrong or belongs to a deactivated partner, a missing or wrong X-Partner-Secret, and an invalid HMAC signature or a timestamp more than 5 minutes off. Until now, an unknown or deactivated Partner ID returned PARTNER_NOT_FOUND, and each authentication failure had its own title, such as UserGeneratedError:Invalid partner secret.Who is affected: partners whose code branches on PARTNER_NOT_FOUND, or on the title of a TOKEN_INVALID error.Action required: stop handling PARTNER_NOT_FOUND and the old titles. On TOKEN_INVALID with the title UserGeneratedError:Invalid partner credentials., check the Partner ID first, then the secret or HMAC key.Reference: Partner integration.
Admin APILimitsAction required
Daily call allowance

Optional daily call allowance per store

The Admin API (/api/external/) can now enforce a daily call allowance for a store. Appstle support sets it per store, and a store without one has no daily cap. Calls made with a partner token don’t count toward it.When a store uses up its allowance, every Admin API call made with its API key returns 429 until 00:00 UTC. The response has a Retry-After header with the number of seconds left until then, and this body (key order can vary):
The Admin API’s other 429 responses, for the per-minute rate limit and for too many PUT calls at once, have no Retry-After header, and their body has an error field instead of detail.Who is affected: integrations that make many Admin API calls a day with one store’s API key.Action required: when a 429 has a Retry-After header, stop calling until it elapses, because retrying sooner can’t succeed. Keep exponential backoff for a 429 without one.Reference: Rate limits.
Admin APINew fields
Widget labels

Label for already claimed social actions

GET /api/external/widget-labels returns a new field, socialAlreadyClaimedLabel.Reference: List storefront widget label translations.
Admin APIStorefront APINew fields
Credit expiry, widget labels

Credit expiry date on point transactions

  • Point transactions return creditExpireAt, the date the store credit from a transaction expires. It’s set only when the store has credit expiry turned on. It appears in GET /api/external/point-transaction-history/{customer_id} and GET /loyalty/cp/api/transaction-by-shop.
  • GET /api/external/widget-labels returns dedicatedPageUnavailableLabel.
Reference: Get customer point transaction history.
Admin APIStorefront APIBreaking changeNew fieldsAction required
Referrals, authentication errors

Referral errors and a smaller referral history

  • GET and POST /loyalty/cp/api/referral-rules/accept-offer return errorKey. When the offer is refused because the friend was already referred, the response is 400 with status FAILED and errorKey ALREADY_REFERRED.
  • GET /api/external/widget-labels returns alreadyReferredErrorLabel, the text to show for that error.
  • GET /loyalty/cp/api/customer-referrals returns less about each referral. referredEmailId is always masked, so jane@example.com comes back as j**e@e******.com. description, referralRuleId, referralNote, referredNote and pixelData are always null. Until now, these fields had values, and the email was masked only in some stores. orderCount is listed in the API reference but is always null on this endpoint.
Who is affected: storefronts that show a friend’s full email, or read the fields that are now null, from the referral history.Action required: show referredEmailId as it comes, and build the history from status, createAt, claimAt, referralRewarded and referredRewarded.

New body for authentication errors, and shop must match the key

  • When the API key or the customer’s storefront session is missing or invalid, the Admin API and the Storefront API return 401 with {"status":401,"detail":"Invalid authentication"}. Until now, the body was an application/problem+json document with the title Unauthorized.
  • An Admin API call with a shop parameter that names a store other than the API key’s store returns 403 with the detail Shop does not match the authenticated session. Until now, shop was ignored.
Action required: treat any 401 as a credential problem without parsing its body, and leave shop out of Admin API calls, since your API key already identifies the store.Reference: Accept referral offer (POST), Get customer referral history, Error responses.
Admin APIStorefront APIBreaking changeAction required
Enrollment, reviews, redemptions

Storefront enrollment no longer accepts a VIP tier

POST /loyalty/cp/api/enroll-customer no longer moves a customer into the VIP tier named in vipTier. A signed-in customer’s request that includes vipTier now returns 400 with the title VIP tier changes require merchant access. Enrolling a customer without vipTier works as before.

Stricter checks on reviews and redemptions

  • POST /loyalty/cp/api/submit-review returns 400 with the title Rating must be between 1 and 5 when rating is missing or outside 1 to 5. Until now, the rating wasn’t checked.
  • POST /api/external/redeem-points and POST /loyalty/cp/api/redeem-points return 400 with the title Points to redeem must be greater than zero. when the redeem rule’s type is DYNAMIC_DISCOUNT and points is missing, 0 or negative. Until now, a missing points returned the title UserGeneratedError:Please enter the number of points to redeem.
  • When a redeem rule is limited to customers with certain tags and Appstle can’t read the customer’s tags from Shopify, redeem-points returns 400 with the title Unable to verify reward eligibility. Please try again. Until now, the redemption went ahead without the tag check. The error is temporary.
Who is affected: storefronts that send vipTier when enrolling a customer or submit reviews without a rating, and integrations that redeem dynamic-discount rules.Action required: remove vipTier from the enrollment body. Send a rating from 1 to 5 with every review. Send a positive points value for a dynamic-discount rule, and retry redeem-points after Unable to verify reward eligibility. Please try again.Reference: Enroll customer in loyalty program, Submit product review, Redeem customer points for rewards.
Shopify FlowBehavior change
Flow review points

Reward Points for Reviews accepts any Product ID

The Reward Points for Reviews action now awards the points when Product ID is empty or isn’t a Shopify product ID, for example when a review app passes a SKU or a handle. Until now, the action failed in those cases and awarded nothing.Who is affected: workflows whose review app passes something other than a Shopify product ID as Product ID. Those actions now succeed.Reference: Reward Points for Reviews.
Storefront APINew fields
Social media points

Social media claims say whether points were awarded

POST /loyalty/cp/api/claim-social-media-points now returns a body that says what happened. Until now, it returned 200 with an empty body whether or not the customer earned points. A refused claim still returns 200, so read the body:
  • awarded (boolean): true when the points were added.
  • reason (string): AWARDED, or why the claim was refused: CUSTOMER_EXCLUDED, RULE_NOT_FOUND, RULE_OUTSIDE_SCHEDULE, CUSTOMER_TAGS_UNAVAILABLE, RESTRICTED_CUSTOMER_TAG, MISSING_ALLOWED_CUSTOMER_TAG, IMPORTED_CUSTOMER, ALREADY_CLAIMED or NOT_ELIGIBLE.
  • message (string): a short description of the outcome.
  • points (number): the points added. It’s null when the claim is refused.
The API reference doesn’t show this body yet.Reference: Claim social media reward points.
Admin APINew fields
Earn rules

Extra points for review photos and videos

GET /api/external/point-earn-rules returns addAdditionalPhotoPoints, additionalPhotoPoints, addAdditionalVideoPoints and additionalVideoPoints on review earn rules.Reference: Get all point earning rules.