Skip to main content

42 posts tagged with "api"

View All Tags

API late September 2026 security update (1.7.0)

Sam Critchley
Co-Founder

A security-focused API release that follows the mid September 2026 release.

  • Changed (breaking) Two-Factor Authentication (2FA) for admin user login. 2FA on login is now enforced for every request API version, including the default 1.0.0 used when no X-Spaaza-API-Version header is sent. Previously the passcode step only ran for requests with version 1.5.8 or higher, so older or version-less admin logins received a full session immediately and bypassed 2FA. Those clients now receive a session_passcode_key and session_passcode_expiry_date instead of session_info, and must complete the login by posting the emailed passcode to the session endpoint. Admin users with login_2fa_exempt set are unaffected and continue to receive an immediate session. See the versioning page for details.

API access token scope restrictions (1.7.0)

Sam Critchley
Co-Founder

A security improvement to the creation of access tokens for privileged authentication through the Resources API.

  • Changed POST /resources/access_token so that the scope of a new token is restricted to the chain given in the X-Spaaza-Chain-ID header of the request: only chain:{chain_id} and read_businesses:{chain_id} for that chain are accepted. A request whose scope names a different chain, or uses any other scope key, is rejected with access_denied (code 424) and no token is created. Previously the submitted scope was stored unchanged. Existing tokens are not affected. See scope.

API basket shopper chain scope (1.7.0)

Sam Critchley
Co-Founder

A security improvement to the way add-basket and get-basket-price identify the shopper from the spaaza_user_id field of the user object.

  • Fixed the resolution of the shopper from spaaza_user_id so that the shopper must belong to the chain identified in the request. A spaaza_user_id of a shopper in another chain is now treated as not found: the basket is processed as an anonymous basket and, from API version 1.5.2, the response carries a user_not_found warning, exactly as for an unknown ID. Previously such a request could attach the shopper from the other chain to the basket. The member_number and authentication_point_identifier fields were already limited to the chain of the request and are unchanged. This change is not tied to an API version. See shopper identification fields.

API access token revocation (1.7.0)

Sam Critchley
Co-Founder

A security improvement to privileged authentication in the Spaaza API.

  • Fixed the checks made on each request that uses privileged (Bearer access token) authentication. A request is now rejected if the access token is inactive or deleted, or if the service client that owns the access token is disabled or deleted. Previously such a request could still authenticate for a period of time after the token or service client was revoked. See access token revocation.
  • Changed the error returned for a request made with a revoked access token, or with an access token of a disabled or deleted service client. Such requests now return access_token_invalid (code 266, HTTP status 401) at authentication time instead of access_denied (code 424). This change is not tied to an API version. API clients that check for access_denied in this situation should check for access_token_invalid instead.

API mid September 2026 improvements (1.6.8)

Sam Critchley
Co-Founder

Further API features, improvements and fixes that shipped to production in mid September 2026, on top of the earlier late August 2026 release.

  • Added the email provider webhook types ses and smtp to add-webhook and alter-webhook, configured on the email_verification_otp and email_verification_deeplink events, so a chain's email verification messages can be sent either by Spaaza's own email service or through the chain's own SMTP email provider. See sending verification emails from your own email provider.
  • Added a backup provider for the messages that verify an email address or a phone number, configured as a pair of webhooks on the same event using the new delivery_role field on add-webhook and alter-webhook. The primary sends; the standby is held back and used only when the primary fails to accept the message, so the customer still receives exactly one message. Available on the email_verification_otp, email_verification_deeplink and phone_number_verification events. The new swap-webhook-delivery-roles endpoint exchanges the two roles in one step, and conflicts return the new error webhook_delivery_role_conflict (code 562). See backup email provider.
  • Added last_purchase_date to the shopper object sent in webhook event payloads, such as the shopper.altered event. It holds the date and time of the customer's most recent purchase in UTC (for example 2026-06-27T13:33:43Z), or null for a customer with no purchases. The get-user response is unchanged.
  • Changed the type of an email verification webhook so that it names the delivery provider, ses or smtp, instead of repeating the event name. The previous values email_verification_otp and email_verification_deeplink are no longer accepted by add-webhook; the event is given in event_name as for every other webhook.
  • type can now be changed on alter-webhook, limited to switching an email verification webhook between ses and smtp.
  • Changed alter-webhook and delete-webhook so that a primary verification webhook can no longer be deactivated, deleted, moved to another event or have its delivery_role removed or changed while its standby is still active. Such requests return webhook_delivery_role_conflict (code 562). To retire a primary, first swap the roles and retire the demoted webhook, or deactivate the standby first. Deactivating or deleting a standby, or a primary without a standby, is unaffected.

API late August 2026 improvements (1.6.8)

Sam Critchley
Co-Founder

Further API features, improvements and fixes that shipped to production in late August 2026, on top of the earlier mid August 2026 release.

  • Added the chain option first_transaction_sets_home_and_signup_store, configured through alter-chain and also available on the Chain resource. When it is enabled, a customer's first completed transaction sets their signup store and their home store to the branch business of that transaction's basket. Each store is only filled if it is still empty, and later transactions never change either store. See stores set by the first transaction.
  • Added the email verification webhook types email_verification_otp and email_verification_deeplink to add-webhook, so the delivery of a chain's email verification messages can be configured through the API.
  • Changed the error returned by otp-verify for an incorrect or expired code to verification_code_invalid_or_expired (code 561), replacing the more general password_error_or_non_existent (code 5). Clients which show their own message for an invalid passcode should key on the new error code.
  • Improved the performance of returns which do not supply an original_retailer_basket_code: matching a returned item to its original purchase is now fast even for customers with a very large transaction history, where such requests could previously take tens of seconds. The lookup covers the customer's 2,000 most recent transactions.
  • Improved validation of points_tracker campaign rules, which are now rejected when no action is supplied. This prevents a rule which cannot be applied from being saved, and prevents the error which such a rule caused when a customer's purchase progress was updated.
  • Fixed the survey campaign endpoints so that a request for an inactive or deleted survey is rejected with campaign_not_active (code 449), and a required consent question is only treated as answered when a value is actually supplied. An explicit false still counts as an answer.
  • Fixed Shopify customer synchronisation so that a customer who already exists in Spaaza keeps their existing signup_channel. Only customers genuinely created by the Shopify webhook are recorded as a Shopify signup. See data synchronisation.

API mid August 2026 improvements (1.6.8)

Sam Critchley
Co-Founder

Additional API features, improvements and fixes that shipped to production in mid August 2026, on top of the earlier late July 2026 release.

  • Added survey campaigns, a composable campaign with context: "survey". The survey questions are configured on the campaign through survey_definition in add-campaign and alter-campaign, client applications fetch the definition and the shopper's completion state with GET /survey, and answers are submitted with POST /submit-survey. Completion is idempotent per shopper and campaign, issues the campaign's direct reward methods, and enforces the campaign's segment restriction on both retrieval and submission. Completed responses can be retrieved with GET /internal/get-survey-responses.
  • Added email address verification, configured per chain with the email_verification_method option (off, otp or deeplink) through alter-chain and returned by get-chain. See verifying user contact details for the full flows.
  • Added an email one-time passcode flow: otp-request and otp-verify accept an email parameter to send a six-digit passcode to a user's email address and verify it, mirroring the existing phone number flow with the same rate and attempt limits.
  • Added an email verification link flow with the new email-verify-request and email-verify endpoints, which email a signed, single-use verification link that is valid for three days.
  • Added an email_status field to the user, returned by get-user, showing whether the email address has been verified (1) or not (0). Changing a user's email address through add-user or alter-user resets email_status to unverified.
  • Added privileged authentication for the Resources API, so a service client can use a bearer access token in the X-Spaaza-Access-Token header instead of an administrator session. See authentication for the resources and operations available.
  • Added end-user (shopper) authentication for the Resources API, allowing a customer to retrieve their own data with the session credentials returned by login plus the X-Spaaza-MyPrice-App-Hostname header. GET requests are supported on the Business, Voucher and ContentPage resources, results are limited to the customer's own data and their app's chain, and properties that are only relevant to administration are omitted from the response.
  • Changed the default voucher filtering for end-user Resources API requests: GET /resources/vouchers returns only vouchers with status generated or claimed unless redeemed vouchers are requested explicitly, for example GET /resources/vouchers?status=redeemed.
  • Improved authentication handling so that a customer session is validated against the chain of the app making the request, and can no longer be used with an app belonging to a different chain.
  • Fixed purchase progress distribution so that a campaign contributing progress into a wallet or stamp card honours its own earn_on_promotional_items setting, and no longer awards progress for promotional items when that setting is false.
  • Fixed the counting of issued honour_voucher rewards against a reward method's usage_limit, so a composable campaign can no longer issue more rewards than the configured stock allows.
  • Fixed the status filter on Resources API voucher requests, so GET /resources/vouchers?status=claimed now returns the matching vouchers.
  • Fixed Shopify registration and customer synchronisation: registering with an email address that already exists in Shopify now returns the intended duplicate email error rather than a generic server error, customer lookups require an exact email address match so a similar address is never adopted, and synchronising existing Shopify customers into Spaaza no longer fails for customers without an existing programme opt-in.

API late July 2026 improvements (1.6.8)

Sam Critchley
Co-Founder

Additional API features, improvements and fixes that shipped to production in late July 2026, on top of the earlier mid July 2026 release.

  • Added support for campaigns contributing progress into a stamp card. Any campaign that supports purchase progress (for example a matching_item campaign) can add stamps to an item_purchase_count campaign by setting its recipient_campaign_id to the stamp card's campaign_id and its recipient_reward_method to points. The card's reward is issued when its target_count is reached, whether the completing stamps come from the card's own qualifying items, from contributions, or from a combination of both within the same basket. Existing stamp card behaviour is unchanged.
  • Added an owner_code field to composable campaign reward methods, settable through alter-reward-method and returned by get-reward-method and get-reward-methods. It is a short label of your own choosing (maximum 64 characters) used to identify a reward method when several are listed together, and has no effect on how rewards are calculated or issued.
  • Changed the max_basket_items_considered field on the reward-method basket_item restriction so that it counts individual items rather than basket lines. A single basket line with a quantity of 3 now counts as three items, exactly as three separate quantity-1 lines would, and the same limit is applied when the reward value is distributed across the matched items.
  • Fixed the promotional state of stored basket items so that it is no longer re-derived from current product data when a basket is processed again, for example by claim-basket or a return. An item that was not on promotion when it was bought continues to earn from campaigns configured with earn_on_promotional_items set to false, even if the product has since been flagged as promotional.
  • Fixed the handling of non-boolean item_is_promotional values in add-basket. Values such as "false", "0" and 0 are now interpreted as not promotional, values such as "true" and 1 as promotional, and any unrecognised value defaults to not promotional.

API mid July 2026 improvements (1.6.8)

Sam Critchley
Co-Founder

Additional API features, improvements and fixes that shipped to production in mid July 2026, on top of the earlier early July 2026 release.

  • Added a require_unique_phone_number chain option (set via alter-chain, returned by get-chain). When enabled, add-user and alter-user reject any request that would give two active accounts in the same app the same phone number, returning the new phone_number_already_exists error (code 555). When disabled (the default), duplicate phone numbers are still allowed and are only flagged via the phone_number_duplicate field. Enforcement applies to new writes only; accounts that already share a phone number are left unchanged when the option is enabled.
  • Added two value_calculation_rule options for wallet_contribution reward methods on composable campaigns, configured through alter-reward-method: fixed_value_per_basket awards the configured value once per qualifying basket, and fixed_value_per_spend awards the value for each spend_step of basket spend (using the new spend_step reward-method field). Unlike the existing per-item fixed_value rule, both are independent of item quantity.
  • Added the get-campaign-barcode-conflicts endpoint. Given a chain, a list of barcodes and a reference date window, it returns each barcode that is shared with another campaign whose active date window overlaps the reference window, along with those campaigns' details. This makes it possible to detect barcode and scheduling clashes between campaigns in a single request.
  • Changed the chain basket_campaign_require_format_assignment option so that a Business (store) assignment now also satisfies the requirement. When the option is enabled, an active BasketCampaign is accepted if it has either a Business Format assignment or a Business (store) assignment, aligning the API with the Console campaign activation checklist.
  • Changed date-time fields in Resources API responses to RFC 3339 format (a profile of ISO 8601), normalised to UTC (for example 2026-07-07T15:30:23+00:00), for API version 1.6.8 and above. Earlier API versions continue to receive the previous Y-m-d H:i:s format for backwards compatibility.
  • Removed the shopper object from the transaction/receipt response. Member identity is now carried solely by the user field, which already contains the same name, contact, membership and address details, so the duplicate shopper block is no longer returned.

API early July 2026 improvements (1.6.7)

Sam Critchley
Co-Founder

Additional API features, improvements and fixes that shipped to production in early July 2026, on top of the earlier mid June 2026 release.

  • Added manufacturer, private_label and listing_source product fields. These are returned in product responses (for example get-product) and can be set when creating or updating products, including through the product feed import.
  • Added a visible_to_all_user_segments option to the composable campaign segment restriction. When true (the default) a segment-restricted campaign is still shown to everyone in get-campaigns and get-card, and the segment only affects whether the reward applies; set it to false to also hide the campaign from users who are not in the segment.
  • Changed the composable campaign segment restriction to accept a single segment id for user_segment_id and excluded_user_segment_id. Comma-separated lists of segment ids are no longer accepted.
  • Fixed composable interaction campaigns (such as scratch cards) so their reward methods can once again carry redeem-shaping restrictions (basket_item, business, currency), matching the behaviour already documented for these campaigns.
  • Fixed composable voucher redemption so that when a reward-method redeem restriction (basket_item, business or currency) matches nothing in the basket, the voucher now redeems on nothing instead of applying its full value across all basket items.
  • Removed the unused business_format and business_region composable restriction types. Filtering by business format or region remains available through the business restriction using its business_formats and business_regions fields.

API mid June 2026 improvements (1.6.6)

Sam Critchley
Co-Founder

Additional API features, improvements and fixes that shipped to production in mid June 2026, on top of the earlier early June 2026 release.

  • Added max_basket_discount_amount campaign field, allowing a per-voucher cap on the discount value of percentage basket vouchers at redemption time. The cap is enforced per voucher during get-basket-price and add-basket.
  • Added new admin permission fields permission_analytics, permission_export, and permission_segment_query on add-user, alter-user, and permission-related endpoints, enabling more granular access control for admin accounts.
  • Added created_date and last_modified_date as sort parameters for the Business and AllowedIpRange resources in the Resources API.
  • Changed percentage basket voucher application on chains that allow double discounting: get-basket-price and add-basket now apply all eligible campaign-level standalone percentage basket vouchers by threshold allocation — sorted by campaign reward_priority, then cap-aware delivered discount for same-priority vouchers, then created_date — instead of keeping only the single best percentage voucher. The max_basket_discount_amount cap applies per voucher.
  • Changed voiding/cancelling a transaction via an empty get-basket-price (no items and basket_total_value 0) to also unlock the shopper's standalone vouchers: any claimed, non-expired voucher locked to the same retailer_basket_code / voucher_locking_code now has its lock cleared, not only on-the-fly basket campaign vouchers.
  • Improved event handling so that deferred events (such as OTP SMS notifications) are no longer triggered when the API request that staged them fails.
  • Improved get-basket-price to no longer return misleading warnings for auto-loaded vouchers that do not match campaign spend-assignment parameters.
  • Fixed an issue where voucher key generation under high concurrency could produce duplicate keys.
  • Fixed a get-basket-price error that occurred when the basket had no items and the user held vouchers from inactive campaigns.

API early June 2026 improvements

Sam Critchley
Co-Founder

Additional API features, improvements and fixes that shipped to production in early June 2026, on top of the earlier mid May 2026 release.

  • Added get-campaigns support for JWT-based shopper authentication, extending the JWT auth support introduced in version 1.6.4 to campaign listing.
  • Added Chain resource to the Resources API with GET, PUT, and PATCH support, including nested allowed_ip_ranges and a new standalone AllowedIpRange resource.
  • Added chain-level configuration flag for partial-redemption voucher regeneration, allowing chains to control whether partially-redeemed vouchers are automatically regenerated with the remaining value.
  • Added chain-level basket campaign assignment restriction settings.
  • Added composable reward-method voucher-shaping configuration fields: voucher_claimed_by_default, voucher_expiry_seconds / voucher_expiry_date, and spend_on_promotional_items, enabling fine-grained control over voucher behavior at the reward-method level.
  • Added reward-method-level return_reclaims_earned_rewards field for wallet_contribution reward methods, allowing chains to prevent clawback of earned purchase progress when the earning purchase is returned.
  • Changed add-user and alter-user to no longer automatically trigger phone number verification SMS; clients must now explicitly initiate verification through the phone verification flow.
  • Improved call-processing error handling across multiple API endpoints to return structured API error responses for concurrent request timeouts.
  • Improved segment CSV exports to handle larger datasets without timing out.
  • Improved task-based data exports to exclude deleted users.
  • Improved Spotler webhook integration with updated payload format.
  • Fixed cashback campaign calculation that incorrectly double-subtracted voucher discounts from item prices.
  • Fixed handling of deleted campaign restrictions.

API mid May 2026 improvements (1.6.5)

Sam Critchley
Co-Founder

Additional API features, improvements and fixes that shipped to production in mid May 2026, on top of the earlier early May 2026 release.

  • Added basket-level discount calculation and percentage-based basket voucher support for composable campaigns, extending composable campaigns to handle basket-discount reward flows.
  • Added win_chance configuration to composable campaign reward methods, enabling probabilistic reward issuance so that only a configured percentage of interactions trigger a reward (for example a 5% chance per basket).
  • Changed get-user-vouchers to return voucher campaign details in a nested campaign object for API version 1.6.5 and above, including bounded campaign assignment rows with assigned business details, assignment_count, assignment_count_by_type, and assignment_types_excluded fields. Older versions keep the legacy flat campaign_* fields.
  • Improved API response times for basket endpoints (get-basket-price and add-basket) through caching improvements.
  • Improved create-voucher with concurrency protection to prevent duplicate voucher creation from simultaneous requests.
  • Improved robustness of API requests involving segment lookup through improved retry logic.
  • Fixed campaign segment-restriction handling so that campaigns with segment restrictions correctly fail closed.
  • Fixed get-tags, get-assigned-groups, and get-reward-methods endpoints returning server errors instead of proper API error responses when the chain_id parameter is missing.

API early May 2026 improvements (1.6.4)

Sam Critchley
Co-Founder

Additional API features, improvements and fixes that shipped to production in early May 2026, on top of the earlier mid April 2026 release.

  • Added stateless JWT-based shopper authentication, allowing chains to configure trusted JWT issuers via jwt_jwks_url, jwt_issuer, and optional jwt_audience fields on alter-chain and get-chain. Shopper JWTs are validated using JWKS with automatic key-rotation support, and alter-user enforces an explicit customer_profile.write scope when called with JWT authentication.
  • Added a fixed_value calculation method to composable campaign reward methods, alongside the existing basket-value and items-value methods.
  • Added a context field to composable campaigns, with context-based filtering of available restrictions and reward methods.
  • Changed composable campaign budget and usage-limit configuration to be set at the reward-method level rather than the campaign level.
  • Changed admin and user permission payloads so that the legacy empty businesses block is no longer included in auth/login, auth/session, auth/get-user-permissions, and get-user responses for API version 1.6.4 and above. Older versions still return businesses: null for compatibility.
  • Improved phone-number verification so that re-submitting the same phone number on alter-user or add-user preserves the VERIFIED status instead of resetting to VALIDATED, avoiding unnecessary OTP re-verification.
  • Improved phone-number validation so that invalid phone numbers submitted via legacy API versions (below 1.6.1) are now stored with INVALID status instead of UNCHECKED, giving better data visibility.
  • Improved Stripe subscription handling to fix cancellation webhooks silently failing when a subscription's annual expiry had passed, and to prevent duplicate Stripe subscriptions being created by failed renewal retries.
  • Fixed composable campaign segment-restriction evaluation returning an incorrect type when the segment response was empty, which could cause campaigns with segment restrictions to behave unexpectedly.

API mid April 2026 improvements

Sam Critchley
Co-Founder

Additional API features, improvements and fixes that shipped to production in mid April 2026, on top of the earlier late March 2026 release.

  • Added phone-number verification via SMS one-time passcode (OTP) during user signup and phone-number change, controlled by a chain-level setting.
  • Added a reward object to the interact-campaign response when a reward is issued, so clients can display the reward that was won (for example in scratch-card-style flows).
  • Added content pages to the Resources API via the /resources/content_pages resource, including filtering by name, a parent link for page hierarchy, and display_name, order and active/inactive support.
  • Changed add-product and add-product-variant (and the related product and product-variant importer scripts) so that price is now optional; products and variants can be created without a price where one is not yet known.
  • Fixed a case where email-marketing-consent state from Shopify customer payloads was not recognised consistently across webhook and GraphQL shapes, which could leave subscribed customers stored as unsubscribed.
  • Fixed basket-campaign distribution when a basket_fixed rule is not set, so distribution totals are calculated correctly for these campaigns.
  • Fixed a case where a campaign with only spend assignments would incorrectly allow every basket item to qualify for the reward when no items matched the spend assignments.

API late March 2026 improvements

Sam Critchley
Co-Founder

Additional API features, improvements and fixes that shipped to production in late March 2026, on top of the earlier mid-March 2026 release.

  • Added a new composable campaign type that combines configurable reward-handling behaviour (independent or random_draw, for example competition-draw rewards), reward methods with their own restrictions, usage limits and usage costs, and voucher-style rewards. Composable campaigns can also be triggered via interact-campaign for scratch-card-style flows.
  • Added a rewards_handling_behaviour field (independent/random_draw) on composable campaigns.
  • Added a usage_cost restriction on composable campaigns so that a wallet balance is deducted per interaction.
  • Added usage_limit and selection fields on reward methods, including competition-style random-draw weighting.
  • Added reward-method-level restrictions (currency, business, basket_item) so that spend-context restrictions can be applied directly to a reward method.
  • Added an honour_voucher reward-method type with honour_code configuration.
  • Added member-number-range fields to chain endpoint responses.
  • Added a chain-level setting that controls how long after a user is created a referral_code can still be applied to trigger referral-campaign rewards.
  • Added a new auth/apply-referral-code endpoint so that an existing user can submit a referral code after signup (within the chain's configured submission window).
  • Added explicit is_default create and alter handling to loyalty campaigns, with the API enforcing that only one active default loyalty campaign can exist per chain.
  • Changed loyalty-level-change side effects so they are only triggered for the campaign that owns the progress entry, preventing duplicate side effects when a chain has multiple active loyalty campaigns.
  • Improved database performance for voucher and voucher-distribution reporting through additional database indexes.
  • Fixed min_earn_quantity handling for fixed-monetary and quantity-unit basket campaigns so that an empty min_earn_quantity no longer triggers a type error, and a submitted value of 0 is preserved rather than silently coerced to 1.
  • Fixed claim-basket so that campaign barcode assignments are preloaded consistently with add-basket, ensuring only items matching a campaign's barcode-assignment list qualify for rewards.
  • Fixed delete-voucher and expire-voucher so they no longer delete or expire a voucher that has already been redeemed (previously this could incorrectly restore wallet balance for wallet-campaign vouchers).

API mid-March 2026 improvements

Sam Critchley
Co-Founder

Additional API changes, improvements and fixes that shipped to production in mid-March 2026, on top of the earlier early March 2026 release.

  • Improved phone-number validation so that certain additional South African number prefixes (+27500, +27501, +27502) that were previously rejected as invalid are now accepted.

API early March 2026 improvements

Sam Critchley
Co-Founder

API changes, improvements and fixes that shipped to production in March 2026, on top of the earlier late February 2026 release.

  • Changed admin-user handling across add-user, get-user, alter-user, and delete-user so admin operations are strictly scoped to the requested chain: existing admin users can be granted permissions for an additional chain via a cross-chain upsert, duplicate adds for the same chain return user_already_exists, chain-scoped super-users can only see and alter other admins within the requested chain, and delete-user removes only the requested chain's permissions before fully deleting an account once no permissions remain.
  • Changed alter-user admin handling so admins cannot alter their own permission fields or login_2fa_exempt flag (self-escalation protection).
  • Changed chain endpoints (including alter-chain) so image_url, receipt_logo_url, and password_reset_url can be cleared by passing an empty string or null.
  • Improved basket campaign reward-exclusion performance by caching and reusing campaign-type information, reducing repeated campaign lookups during reward calculation on larger baskets.
  • Fixed a Shopify integration issue where an empty username in an alter-user request could null out the customer's Shopify email address and disable the Shopify customer account.

API late February 2026 improvements

Sam Critchley
Co-Founder

Additional API features, improvements and fixes that shipped to production in late February 2026, on top of the earlier February 2026 release (1.6.3).

  • Added support for a product unit field via add-product, returned by the product endpoint (for example g, l, or item).
  • Added a chain-level option to exclude rewards on basket items that have already been discounted by a basket campaign.
  • Added a chain-level multiplier for scaling competition win rates per chain or region.
  • Added a till_code field on baskets, exposed through basket and transaction documents.
  • Changed basket campaigns so they no longer require campaign rules; rule-free basket campaigns now qualify and apply implicitly.
  • Changed claim-basket so admin users and privileged-auth requests are no longer subject to the anonymous-basket claim rate limit.
  • Changed the product variant importer so it accepts either owner_code or product_variant_owner_code as input, and allows a blank owner code.
  • Changed the Resources API so mutating requests (POST, PUT, PATCH) must use a JSON object body, lookups or deletes with empty identifiers are rejected, unknown resource types fail deterministically, and singular and plural routes no longer accept each other's reserved parameters.
  • Changed the Resources API Business resource so business_id is no longer globally required in its OpenAPI schema.
  • Improved voucher redemption_count so it is normalised consistently across receipts and indexing (taking min_earn_quantity into account).
  • Improved database performance for user phone number lookups.
  • Fixed matching item threshold campaign reward distribution across multiple basket items so the correct remaining quantity is used.
  • Fixed get-webhooks and get-webhook so webhook secrets shorter than three characters are obfuscated correctly in API responses.
  • Fixed campaign responses so minimum_matching_item_value is returned as null (rather than 0) when the value is unset.
  • Fixed an authentication issue affecting user-wallet-ledger for user and Shopify authentication.
  • Fixed Stripe subscription webhook handling so the interaction result is captured and reported when a subscription interaction does not complete.

API February 2026 improvements (1.6.3)

Sam Critchley
Co-Founder
  • Added phone number validation and duplicate checks in add-user and alter-user endpoints.
  • Added composable campaign and reward method foundations for modular campaign configuration.
  • Added location search for the Resources API Business resource.
  • Added text search support across multiple properties for get-businesses and the Resources API using search[*] syntax.
  • Added task-triggered campaign support.
  • Added spend basket-level campaign assignments.
  • Fixed add-user so admin user creation now works correctly when an end-user with the same username already exists in the chain.
  • Changed alter-user so API version 1.6.3 and above requires user_id when updating admin users by username.
  • Improved alter-user so username clash checks now run in the target user's app when both user_id and username are supplied.