# Docs MCP Server Source: https://docs.thanx.com/ai/docs-mcp Set up the Thanx documentation MCP server for AI-powered search and interaction The Thanx Docs MCP Server enables you to search and interact with the entire Thanx API documentation using natural language through AI tools like Claude Code. ## Features * **Natural Language Search**: Find API endpoints, parameters, and examples using plain English * **Instant Answers**: Get quick responses about authentication, rate limits, and best practices * **Code Examples**: Request code samples in any programming language * **Context-Aware Help**: The AI understands the relationships between different API endpoints ## Installation The easiest way to use the Thanx documentation MCP server is to connect to our hosted remote server. This requires no local installation and provides instant access. #### For Claude Code Add to your project's `.mcp.json` file: ```json theme={null} { "mcpServers": { "thanx-docs": { "type": "http", "url": "https://docs.thanx.com/mcp", "description": "Thanx Docs MCP server for searching and interacting Thanx API Docs" } } } ``` or install this for your user: ``` claude mcp add thanx-docs https://docs.thanx.com/mcp --transport http ``` ## Usage Examples Once installed, you can ask questions like: * "How do I authenticate with the Thanx API?" * "Show me how to create a new user with the Consumer API" * "What are the rate limits for the Partner API?" * "Generate Python code to fetch a user's rewards" * "Explain the difference between the Consumer and Partner APIs" ## Configuration The documentation MCP server requires no additional configuration. It automatically: * Indexes all public documentation at docs.thanx.com * Updates when documentation changes * Provides search across all API sections ## Troubleshooting 1. Verify the server URL is correctly configured 2. Check your internet connection 3. Restart your MCP client application ## Privacy & Security * The MCP server only accesses publicly available documentation * No API credentials are required for documentation search * All queries are processed locally by your AI client * No usage data is sent to Thanx servers ## Next Steps * Explore the [Thanx API documentation](https://docs.thanx.com) * Learn more about [Model Context Protocol](https://modelcontextprotocol.io/) # AI Integration Source: https://docs.thanx.com/ai/overview Thanx provides AI-powered tools to help developers integrate with our APIs more efficiently. These tools enable natural language interactions with our documentation and APIs through the Model Context Protocol (MCP). ## Available Tools Search and interact with Thanx API documentation using AI ## What is MCP? The [Model Context Protocol](https://modelcontextprotocol.io/) is an open standard that enables AI applications to securely connect with external data sources and tools. With MCP, you can: * Search documentation using natural language * Get instant answers about API endpoints and parameters * Generate code examples for your use case * Integrate Thanx capabilities into your AI workflows ## Getting Started 1. **Install an MCP-compatible client** like Claude Desktop or Claude Code 2. **Add the Thanx MCP server** to your client configuration 3. **Start asking questions** about the Thanx API in natural language For detailed setup instructions, see the [Docs MCP Server](/ai/docs-mcp) guide. ## Benefits * **Faster Development**: Get instant answers without searching through documentation * **Code Generation**: Generate API integration code in your preferred language * **Natural Language**: Ask questions in plain English instead of searching for specific terms * **Always Up-to-Date**: MCP servers stay synchronized with the latest documentation ## Support For questions about AI integrations, contact us at [developer.support@thanx.com](mailto:developer.support@thanx.com). # Archive Overview Source: https://docs.thanx.com/consumer/archive/overview This section contains archived API endpoints for historical purposes. These endpoints may still be active and functional for existing integrations, but have been superseded by either new platform functionality or API endpoints. New integrations should not use these endpoints. # Design Best Practices Source: https://docs.thanx.com/consumer/best-practices/design ## General Design ### Best Practices * **Fonts & colors:** check font size and color contrast against accessibility standards. To check the optimal contrast for type foreground/background color you can use this tool [https://accessible-colors.com/](https://accessible-colors.com/) * **Buttons:** should be a min height of 40px (Apple recommends 44px) for a reasonable tap area. * **Forms and inputs:** automatically pre-fill values in fields where possible, and let users know which fields are required (or just which are optional) * **Graphics/animations:** use to help illustrate concepts and create delight. (If using animations make sure they aren’t blocking the user from moving forward) Example: Dig uses their own playful illustrations to add delight * Capitalize on opportunities to increase enrollment through incentives * Ensure all legal text is present, legible and that our ToS and Privacy Policy are darker and underlined. * Don’t break design conventions or patterns unnecessarily, especially when it comes to the navigation of your app. ## User Accounts * For ordering apps, reduce administrative burden by allow users to start using the app without creating an account. This means users can skip your onboarding experience and they can view the home page as well as start adding items to cart. * However, if users want to check out or to access their Rewards or Account pages, you should require that the user either create a new account or log in to an existing account. ### Sign up #### Card enrollment at signup * When prompting users to sign up in order to access the Rewards or Account pages, you may choose to use a longer account creation flow. In this flow you will collect the user’s email and . You may also add a step to ask user to enroll their credit card into the loyalty program. * Capturing credit card data is crucial in helping build out a comprehensive understanding of your customers behavior, and in turn allows you to target the right customers at the right time, for increased engagement and marketing ROI. This also benefits consumers because it creates a seamless way for them to earn rewards when they make purchases. Earning progress is as easy as swiping their credit card. * For non-ordering focused apps i.e. malls, retail, etc, card capture at signup is particularly crucial; this is a time you have the users focus and attention, and can highlight the values and incentives for enrolling their card. #### General Best Practices * Ensure consumers have clarity on how to earn progress. We recommend that experiences with digital ordering ensure consumers can enroll a card when they pay, and if they pay with a card that isn’t enrolled (or with Apple Pay for example) the landing screen after payment is complete prompts the user with the opportunity to enroll. Where customers can browse the rewards available to them, we recommend an alert to warn customers they are not automatically earning progress if they have no card enrolled. You can also include the prompt in the onboarding flow to maximize the total number of cards enrolled as an additional option. * Don’t ask for all of the user's information at once during signup. * After account creation, take the user to a page with rewards, ordering or generally something that they can immediately engage with. * Highlighting the details of the signup incentive prominently in the signup flow is recommend, as it has been proven to increase user enrollment conversion. * Separate out sign up and log in into separate actions (using a single UX input has proven confusing to users). * When possible, pre-fill forms with known info. ### Log in #### Best Practices * After the user submits their email to log in, they are presented with a screen confirming that a magic link was sent to their email. On that confirmation screen include a CTA to open the email app on the user’s device. * Provide a means for user to resend the magic link email from screen indicating email has been sent * Debounce resend button so user doesn’t press it multiple times in one attempt ## Saved Cards ### Cards list #### Best practices * Ask for the minimum information required to link a card. * For ordering apps, you need card number (PAN), expiration, CVV and zip * For apps where a card doesn’t need to be linked for payment, just ask for PAN * Integrate [Dyneti](https://dyneti.com/) or a similar library that allows cards to be captured via camera * For ordering apps, users should be able to enroll cards for rewards previously only saved for payment and vice versa. ## Account #### Best Practices * Users should be able to edit their info including their name, email, phone, and birthday * Users should be able to log out of the app, but it does not need to be over-emphasized. (You don’t want users to log out) ## Rewards #### Best Practices * Remove the earn description - it isn’t editable in our system (this is on the rewards detail page where it says “for being awesome”). * If you choose to make a card required as part of signup, give the consumer a reward they can use right away, i.e. \$5 off rather than reward progress (will give them a more tangible incentive, that they are more likely to respond to). * Set up all the rewards you want to use on the rewards page of your dashboard. Those rewards will be available to be used in any campaign. * \$ or % off will appeal to a larger audience than giving away a free item. * Use campaigns in the merchant dashboard to learn what kinds of rewards are most effective for your audience. * Talk to your customer success manager for best practices about loyalty and intro rewards. ## Receipt Upload #### Best Practices * Experience should allow the user to choose a credit card to associate the receipt with, if they have any. ## Customer Feedback/NPS #### What this is * After a customer places an order, or makes a purchase, they are occasionally prompted to give feedback about their experience. * The feedback and ratings that result from this show up in your merchant dashboard; this allows you to target customers based on their satisfaction with your brand. #### Why you should include this * Increases frequency of visit to store * Gives you a private channel to your customers, so they don’t go to external places such as Yelp with a negative review. * Additionally, we recommend you prompt your customers for app store rating after they have placed an order or redeemed a reward. # Card Enrollment Best Practices Source: https://docs.thanx.com/consumer/best-practices/enrollment # Why this is important Thanx leverages proprietary integrations with Visa, Mastercard, and American express to allow consumers to earn loyalty progress when they use a card associated with their accounts when they make qualifying in-store purchases (digital purchases are automatically tracked without requiring enrollment of a card for loyalty). This requires the customer to enter their card and acknowledge that it will synchronize their purchases at participating locations with their account to earn rewards (purchases at non-participating businesses are not shared with Thanx or our merchant partners). This in turn powers the CRM’s automated marketing and targeting tools as well as provides valuable analytics to the brand. It is best practice to promote card registration. This makes customer activity more visible to the business, and this lets customers know that they are missing out on the following loyalty benefits when they don’t have enrolled cards: * Automatically earning reward progress for in-store purchases * Unlocking the intro reward (if configured to require card) For non-ordering focused apps i.e. malls, retail, etc, card capture at signup is particularly crucial; this is a time you have the users focus and attention, and can highlight the values and incentives for enrolling their card. Our studies show that if a customer doesn’t enroll a card within 2 minutes of creating an account they are unlikely to add one later. This document outlines adding cards during a signup flow, capturing cards for loyalty tracking when making an online digital purchase, the ability to add cards proactively within account settings, and the ability to manage cards (remove them, etc). # How Thanx does this ### Home page Your home page can look like anything you want. Include a component on the home page to that encourages users to enroll a credit card for loyalty if they haven’t done so already. Without this UI customers would not know how, where, or why to enroll a card. Users can see a component on the home page that encourages them to enroll a credit card if they want to automatically get reward progress for in-store purchases. * Tapping on this component takes the user to an interstitial page that tells a deeper store of why they should enroll their card. This page can look like anything you want so use this opportunity to explain the value of card enrollment to the customer using the brand’s graphics and tone. * After the interstitial the user is taken to the card registration form. The interstitial page is optional, so you can take users straight to the registration form if you choose. * Make this component appear only to logged in customers that don’t have any enrolled cards. ### Rewards page The rewards page uses a banner right below the points header to prompt the user to enroll a card. If the user has no card enrolled, the banner tells the user that they’re not earning points for in-store purchases. If a user already has cards enrolled, the banner tells the user how many cards they have. * Tapping on this component takes the user to an interstitial page that tells a deeper store of why they should enroll their card. This page can look like anything you want so use this opportunity to explain the value of card enrollment to the customer using the brand’s graphics and tone. * After the interstitial the user is taken to the card registration form. The interstitial page is optional, so you can take users straight to the registration form if you choose. ### Saved Cards page Customers must be able browse to a screen that lists their cards. On this screen they should be able to add more cards, as well as remove any card they have stored. Note the legal text on the card registration form.This must be kept “as is” including the descriptor texts above. See Requirements section for full details. Notice the camera icon in the card input field. Thanx API does not include this functionality, but we recommend you implement this functionality with a 3rd party such as Dyneti. ### Checkout (ordering apps) For applications that include ecommerce, the flow above allows the customer to both pay and enroll the card for reward tracking. This is by far the most efficient way to onboard consumers, as they are typing in their card for payment anyway. In our apps, we see a \~90% conversion rate of customers choosing to store the card for loyalty benefits when they pay. If a customer already has a card enrolled (e.g. in the signup flow), they will not see this screen when they choose to pay with that known card. One important nuance is that in this specific flow, errors that come back from enrolling a card for loyalty are not displayed when we build these screens; we don’t want to interrupt a consumer’s ability to make the purchase. The most common error that comes from enrolling a card for loyalty is that the card is already connected to a different consumer account, which typically means the consumer has another account under a different email address. Asking a customer to address that in the checkout flow would lose the purchase. In that scenario, our apps just accept payment and suppress the card enrollment error. As noted above, it’s important that the screen you present are as close to identical to the designs above. While branding and layout can be adjusted, the wording of the text and buttons should not be altered. Full flow below # How other merchants do this ### Dig app This is an example of how one of our partners (Dig) has laid out the card enrollment flow. ## Requirements for implementation These are requirements that we have negotiated with our card network partners. All card enrollment experiences must be approved by these partners to use the card linked APIs they provide. While you are free to design these experiences as you like, it may produce significant delays of certification. We recommend using the designs as we have presented them to ensure a speedy deployment of your application. * Legal text must be on any screen where you allow a customer to enter their card number and store for loyalty tracking. The legal copy may not be altered. * Button must say “Register card” * Legal text must be visible at all times on all devices supported * ToS and Privacy Policy must be obviously clickable (e.g. darker and underlined) * Must comply with standard accessibility guidelines in regards to color contrast and legibility (see: [https://accessible-colors.com/](https://accessible-colors.com/)) # Card Registration Screen Variants ### Ordering app signup By registering my card, I authorize my card network (Visa, MasterCard, Amex) to share transaction data at `[merchant name]` rewards powered by Thanx. I also accept our *[Terms of Service](https://dashboard.thanx.com/terms)* and *[Privacy Policy](https://dashboard.thanx.com/privacy)*. ### Loyalty app signup By registering my card, I authorize my card network (Visa, MasterCard, Amex) to share transaction data at `[merchant name]` rewards powered by Thanx. I also accept our *[Terms of Service](https://dashboard.thanx.com/terms)* and *[Privacy Policy](https://dashboard.thanx.com/privacy)*. ### Ordering app add payment method You can earn rewards for this and future purchases by using this card at \[Merchant name] Link this card > Pay with this card here or in-store > Earn rewards By registering my card, I authorize my card network (Visa, MasterCard, Amex) to share transaction data at `[merchant name]` rewards powered by Thanx. I also accept our *[Terms of Service](https://dashboard.thanx.com/terms)* and *[Privacy Policy](https://dashboard.thanx.com/privacy)*. ### Loyalty app add payment method By registering my card, I authorize my card network (Visa, MasterCard, Amex) to share transaction data at `[merchant name]` rewards powered by Thanx. I also accept our *[Terms of Service](https://dashboard.thanx.com/terms)* and *[Privacy Policy](https://dashboard.thanx.com/privacy)*. # Design tips from our team * Fonts & colors: check font size and color contrast against accessibility standards. To check the optimal contrast for type foreground/background color you can use this tool [https://accessible-colors.com/](https://accessible-colors.com/) * Buttons: should be a min height of 40px (Apple recommends 44px) for a reasonable tap area. On screens with two buttons (ordering enrollment) both must be the same size, though they can differ in visual weight (e.g. color, outline, etc). * Forms and inputs: automatically pre-fill values in fields where possible, and let users know which fields are required (or just which are optional), and for longer forms break them down into simple steps (e.g. signup flows are better as a series of input screens). * Error handling: be as explicit as possible so users understand why they ran into an error, and give them a means to correct or move forward from there. Include support links in critical flows, where users may need further assistance. See our API docs for how to handle error responses. # Common use cases, questions and errors **Error**: “This card is already associated with another account” **Why this happens**: 1. When a card is on file for a consumer, it cannot be registered for loyalty benefits for another account. That would allow two customers to get credit for the same purchase. So Mr and Mrs Smith each have an account, and they both have the same card number. Mr Smith adds it first, and then Mrs Smith tries. She will get an error that the card is already associated with another account. This prevents fraud (intentional or otherwise). 2. A more common use case is Mr Smith has two email addresses, and he's created an account on our platform with one and associated that card, and then he downloads Dig and creates an account with a different email address. He'll get the same error. Our support team can help the customer resolve the issue by merging accounts. **Additional cases** Now, here's the nuance. In our apps, when we're taking payment for digital ordering, and the customer selects "save card and earn rewards" we attempt to tokenize the card with the ordering provider AND with the card network (Visa et. al.). If Visa responds "this card is already in use" we don't do anything. We don't tell the customer or anything. We just take their card and run the payment. Introducing the error that the card can't earn in-store loyalty on that screen just loses the sale and produces customer frustration. The duplicate account issue takes time to resolve. The best call is to just get the customer their food and accept that their card did not successfully enroll for in-store loyalty. Our recommendation here is that the merchant ignore that error from us when adding payment, and that the screen that lists cards enrolled for loyalty show that card as not enrolled for benefits should the consumer go to that screen specifically. # Feedback & Support Best Practices Source: https://docs.thanx.com/consumer/best-practices/feedback ## Why this is important Thanx offers a feedback experience that implements the Net Promoter Score (NPS) system, a metric for measuring customer satisfaction. Across a wide variety of industries, businesses with higher NPS consistently outperform their competitors. The Thanx feedback system targets customers shortly after they make a purchase, selecting a random group each day to ask a single question: “How likely are you to recommend \[merchant name] to a friend?” and a follow up question for feedback sent directly to the brand via the Thanx dashboard. Both the rating and the written feedback input are optional. Merchants receive daily input about the satisfaction of their customers. Each rating is linked directly to the consumer so their purchase history can be viewed as well as other relevant information such as the history of their satisfaction. Feedback generated this way allows you to reply to customers immediately. Thanx Feedback is not available to mall programs. ## How Thanx does this Consumers should be able to to give a 0-10 rating. It’s important that zero is an option, and it’s also important that the prompt does not start with a preselected value. Customers should be able to exit or dismiss the feedback experience, otherwise they are likely to give a poor rating because they don’t wish to complete the survey. This can lead to bad conclusions about customer satisfaction at the business. Consumers should be able to give optional feedback after providing a rating, and the prompt for that feedback should be neutral (e.g. “Do you have any details to share about your rating?” rather than “What did you like about your visit?” – the latter is a leading question that implies satisfaction). When Thanx receives a purchase record a number of details are considered to determine if a customer should be prompted to give feedback. If the result is that a notification is not issued, the customer should still be able to navigate to a feedback screen and proactively leave feedback, even if they weren’t prompted. The purpose of limiting how often a prompt is issued is to avoid annoying a customer which we’ve found to produce negative ratings for being prompted too often. The user interaction for the middle screen is that they can tap anywhere on the bar to choose a rating. The bar is 100% grey (no rating pre-selected) when it loads. After releasing the number, we display the query for input. The customer can go back to alter their value, or tap the value displayed to revisit the rating. The customer can submit the text input empty. ## Design/UX tips from our team We recommend you add support links throughout your experience to reach customers before they go to google or yelp to complain. # Loyalty & Rewards Best Practices Source: https://docs.thanx.com/consumer/best-practices/loyalty ### Why this is important A key component of the Thanx platform is using incentives to increase customer engagement and ultimately the lifetime value. It’s important that users can see the benefits of the program so that those benefits can influence their buying behavior. Rewards, points, and tiers benefits should be conspicuous and easily accessed. The Thanx API gives you what you need to surface these benefits. ### Points Every time a user makes a qualifying purchase (any purchase known to Thanx), they collect points that can be exchanged for various rewards in the rewards marketplace. Points can also be granted to users through campaigns, intro offers, as a birthday reward, or via tiers. Users can view their points balance in the app along with rewards that they can exchange points to redeem. ### Rewards ### Where rewards appear While a list of rewards is useful, we recommend that you display rewards contextually throughout your experience, to reach customers where they are, and to incentivize or influence customer behavior. Thanx displays rewards in several places: * On the home page of our applications (whatever screen a customer who is logged in sees) * On rewards list page * In the cart From most of these views a user can tap on the reward banner to see the details of that reward (except in cart). The rewards page shows all available rewards that were added by the merchant and can be redeemed for points (rewards marketplace). This page also shows rewards that the user received via campaigns or was granted via feedback. Cart does not show rewards that can’t be redeemed online or rewards that cost more points than the user has. ### Reward redemption When a reward is ready for redemption, a button appears that says “Redeem”. If a reward costs points to redeem, the cost of the points is shown on the reward. Tapping into a reward banner displays a detail view with more information such as the reward description, fine print, and expiration date. Again a CTA Button is only present when a reward is ready to be redeemed. Depending on your configuration and the type of reward, a reward may be redeemable online (integrated ordering only), or in-store (loyalty and ordering). If a reward costs points to redeem but a user does not have enough points, they can still view the detail page of the reward. However, the redeem button will be disabled and will say “Locked”. ### In-store redemption (no code) Once a customer chooses to redeem a reward in-person/on location, a countdown timer is activated. This can be any time interval but we use 1 hour as a standard (the interval is returned by the Thanx API). This is to ensure that a reward can’t be used again if a merchant/customer does not tap (mark as used). The “are you sure” modals help ensure that a customer is very intentional about using their reward, so there is less room for a customer to say “I didn’t mean to, can I have another reward?” Once a reward has been activated it will expire after the countdown reaches 0. In addition, the reward can be set to expire manually by tapping the “Mark as used” button. It is up to the manager to fulfill this reward. ### In-store redemption (with code) In-store redemption can be configured to deliver a code to the screen that a server keys into the POS. This can also be displayed as a bar code or a QR code. ### In-store redemption (automatic cash back) These rewards are activated by the customer and then applied to their next purchase. A reward has to be activated, and then is in a state waiting for a purchase and should be visible in that activated state. There is no timer for a statement credit. ### In-store redemption via POS Customers can skip the app and redeem rewards in-store via the POS if the merchant is using the Toast in-store redemption integration. HOW IT WORKS Option 1: The customer gives their phone or email to the team member at the counter. The team member enters those details into the POS and receives a list of available rewards. Option 2: The customer uses a customer-facing display at the counter to enter their email or phone numbe rand receives a list of available rewards on the display. WHAT HAPPENS IN THE APP Even though the customer can access their rewards in-store via the POS, the app is also still able to display available rewards. However, because redemption now happens via the POS, the redemption flow in the app now becomes a page that instructs the customer on how to redeem rewards via the POS. ### Online redemption Available rewards are displayed in cart. Only one reward can be applied at a time (when one is applied we toggle the other off). Rewards in cart don’t use images in order not to distract the user from their purchase. Rewards that the customer already has in their account (e.g. the rewards granted via a campaign, program or feedback) appear first, followed by the rewards in the marketplace which the customer has enough points to afford. If a customer can’t afford a points reward, that reward is hidden. Locked rewards will not be shown here. If no rewards are available, hide carousel and point balance. The rewards are sorted in the following order: * Earned rewards that can be redeemed online without points * Marketplace rewards that can be redeemed using points and the customer has enough points to exchange for that reward * Within the group of rewards that can be redeemed by using points, the rewards are sorted: * Lowest to highest cost * If the cost is the same, then whichever reward expires soonest, and if that’s the same in the order that the rewards were added to the marketplace, with the older rewards going first ### Rewards vs Points Products When exchanging or redeeming **points products** and **rewards**, there are important differences in their behavior and lifecycle. **Reward Redemption** * The reward **must already exist** in the user’s account before checkout. * The **reward is deducted** from the user’s account when the order is submitted. * If the order is **voided** or **refunded**, the **reward is restored** to the user’s account and is available for use again. **Points Product Exchange** * The user **must have the required number of points** available at checkout to complete the exchange. * **Points are deducted** at checkout in exchange for the reward. * If the order is **voided** or **refunded**, the **points are returned** to the user’s points balance. The original reward instance is finalized as refunded; the user can re-exchange those points for a new reward at any time. In both cases the reversal is automatic — sending the `voided` or `refunded` state on the basket is sufficient. The integrating system does not need to manually credit points or re-issue rewards. See the [Create/Update Basket guide](/loyalty/create-update-basket) for the state-by-state behavior of locked rewards and points products across the basket lifecycle. Because of these differences, it is important to follow our [ordering provider integration](/consumer/guides/points#ordering-provider-integration) when implementing points exchanges or reward redemptions at checkout for your integration. ### Tiers You may choose to build a tiers program to engage different customers. There are always 3 tiers. ## **Tiers Program (e.g. bronze, silver and gold)** The below examples use Thanx's default tiers bronze, silver, and gold however if you've customized these then the customer experience will reflect your Tier names. ### When a customer is close to reaching the next tier status Thanx notifies consumers when they are \$100 away from reaching their next tier status, and again once they’ve reached it. ### Hidden menu Hidden menus are a way to give customers access to items they wouldn’t normally be able to order. For online redemption this means having a menu configured with the digital ordering provider that is not visible to customers. Online redemptions for this reward reveals this menu in the app. There is no redeem button. Instead when a user is granted this reward, a popup appears when they open the app. The popup notifies the user that they got the hidden menu and then takes the user to the menu. In the navigation, the hidden menu is marked with the reward icon. The hidden menu also has a header explaining that this menu is special. This version of the header is using a custom image. Tapping on “Details” in the header brings up a modal with the countdown and fine print. If access to the menu does not expire, then do not include the countdown. ### Access Pass Access passes a way to give customers exclusive access to items they wouldn’t normally be able to order, or to special experiences. For example: * Skip the line * Chef’s table * Cooking class * Swag. These rewards can only be redeemed in-store. A customer shows the reward image to their server to prove that they have special access. This redemption flow does not rely on any digital ordering integration. Instead this relies on a server seeing an image in the app that proves the customer earned special access. The server would then full the reward. Once the access pass has been redeemed, users can be using it if that’s what the merchant configured. For example, a user could skip the line for a whole week. If the pass is still active after it’s been redeemed, e.g., the customer can use it for a week, then the reward button is now called “View” and the countdown shows how much time the customer has left to keep accessing this pass. ### **Design/UX tips from our team** * If you choose to use reward icons, keep the design simple so it reads well at small sizes. * Don’t show the redeem button until a customer has earned a reward * If a customer has earned multiples of the same reward, you can stack them (think a horizontal carousel) rather than a vertical list. # Messaging Best Practices Source: https://docs.thanx.com/consumer/best-practices/messaging Thanx offers Campaigns, a multi-channel marketing tool. A campaign can include email, push (app notifications), and SMS messages. A campaign can be configured to send messages using one or multiple available channels. ## Push notifications Brands using the Thanx platform can send a push message by adding a push channel to their campaign and write custom messaging. Merchants have the option to attach a reward to their campaign, however a reward is not required to send a push message. If a reward is attached, the editor will have a default pre-filled message that says “Surprise! We have a special offer just for you.” The merchant can change this message if they choose. If a reward is not attached, the editor will not have a default pre-filled message. When a merchant sends this campaign, only loyalty members that have logged into the app and enabled notifications will receive the push message. Because enabling notifications is so important, Thanx apps have a pre-prompt step during the app’s onboarding experience that explains to loyalty members why they should enable notifications. This is presented to the loyalty members as a slide. When the loyalty member taps on the slide or swipes to go to the next slide, the OS dialogue comes up where the loyalty member must select whether the app can send them notifications. Once the loyalty member has interacted with the OS dialogue, they will not see the notifications pre-prompt again. In Thanx apps, if merchants don’t include this pre-prompt in their onboarding experience, then loyalty members will not be prompted to enabling notification permissions and will not receive push notifications. # Onboarding & Authentication Source: https://docs.thanx.com/consumer/best-practices/onboarding-authentication ## Onboarding experience The onboarding experience can look and feel like anything you want. You may choose to focus on the welcome message, teach users how to use the app, or ask users to create an account. The experience below is how our own flows do onboarding. When users open the app, they are presented with a custom onboarding slideshow. Once they get past the slideshow—either by dismissing it or getting past the last slide—they are taken to the app’s home page. At this point the user is not logged in yet. They can access some portions of the app but not all of the app: * View the home page * View the locations page * View the FAQ / Support page * View the About page * View the menu and add items to cart However, these users still must create an account or log in to do the following: * Check out and complete their purchase (users can’t make a purchase without an account) * View the rewards page * View the account page When the logged out user opens the navigation and taps on the reward page, account page, or the Sign up / Log in CTAs, they are presented with an authentication form through which they can sign up or log in to the app. When the logged out user attempts to move past the cart page to complete their purchase, they are presented with a simplified authentication form. ## Why the sign up flow is important Onboarding a customer into a CRM powered experience offers a trade off – share your identity and a means to contact you in exchange for rewards. Over many years Thanx has tested dozens of variations of onboarding experiences. The flows below are the current state of our own flows. As noted in our guide on Credit Card enrollment, these flows have also been approved by our card-linked partners at Visa, Mastercard, and American Express. Using these flows as they are will ensure a speedy certification of your application. Changing branding, fonts, colors, etc, are unlikely to materially affect that timeline, but wording and content should remain as they are. ## How Thanx does this The signup / login flows below are presented to the user when they attempt to view the Rewards or Account pages, or tap on the Sign up / Log In links—all accessible from the nav. The signup These flows below use story telling, progressive data capture, and incentives to encourage customers to enroll in a loyalty program. There are small variations to this flow based on the following parameters: * Whether cards captured are intended to be used for payment later * Whether a credit card is required to redeem a signup reward * The type of signup reward ## Authentication Thanx SSO authenticates the user via a password-less flow using email authentication, rather than a password. This reduces the friction of a user having to manage yet another password as well as reduces the friction of transitioning an existing user-base to Thanx. It also makes creating an account as simple as entering an email address – as soon as one is entered, that customer can be addressed by the marketing tools. By breaking the flow out the user’s account is progressively enhanced as the user completes each screen, but the very first one – the email address – results in an addressable account. ### Signup and log in Signup and log in each have their own screen, as users found a single input confusing for both use cases. Make sure that a return user is recognized in the signup view, while a new user in the the log in flow should see an error that their account is not found. E.g. If a known customer enters her email address on the signup screen, they should be prompted to click the magic link emailed to them to access their existing account. However, if a user clicks “log in” and types in an unknown email address, we display an error that the account cannot be found. This is because consumers sometimes create an account ([me@gmail.com](mailto:me@gmail.com)) and then, returning to their account on another device, they choose “log in” because they know they have an account, but they enter a different email ([me@work.com](mailto:me@work.com)). This should not create another account, but rather inform them that that address is unknown. ### Signup flow #### Non-ordering *Card not stored for payment purposes* The conversion rate of this flow (% of users who create an account who then link a card) hovers between 50% and 60% depending on the brand and the signup incentives offered. Thanx tells a story leading up to the card ask screen to explain to customers the value of linking their card. We try to ask for only critical information up front, so it doesn’t feel too tedious, and the account progressively becomes more complete, but is immediately addressable. #### Ordering enabled *Card stored for payment* The main difference in this flow and prior example is on the last screen where we ask for more card details upfront (expiration, etc), because it will save time for the customer at checkout when they order online later and avoid the perception of having to enter the card twice. Notice the back arrow should a customer decide they want to back out and do this step later, by selecting the manual receipt upload option. #### Card required *Available for ordering and non ordering experiences* This variation can be enabled for order and non-ordering experiences; the primary difference being that the signup incentive (intro reward) is locked. To unlock the reward a customer has to enroll their card for rewards. We don’t recommend using this with % progress rewards, as it quickly adds complexity on top of the locked experience. ## Design guidance This flow prioritizes data capture thusly: * email – customer is immediately addressable with email campaigns. * card number – purchases are tracked as soon as a consumer completes this step. * name, favorite location, phone number, etc – if a customer abandons the flow before reaching or completing this step, their account is still active and tracking their purchases. In mobile applications, the prompts for push notification access, GPS access, etc, are all after these prompts. Its okay to let users skip these steps and do them later, so long as there is an incentive in place to do so: i.e. unlock a reward, place an order, etc. ### Authentication during checkout When a logged out user moves from cart to checkout, they are presented with a simpler signup / login flow. Keep in mind the user must still sign up or log in. There is no guest checkout. #### Log in *Magic link experience* Customers need to enter only their email address to access their accounts. They should be shown a screen instructing them to go find the link sent to their email account. Clicking that link should return them to their prior state (in mobile app, or in a browser, etc). This screen should have a back button, a means to re-send the link, and a way to contact support. Be sure to emphasize to the customer that they should open their email on the device they are currently on. ## How other merchants do this #### Dig app Rewards tab with tiers, and cart with earned reward ## How to do this with our APIs In order to interact with the Thanx API you will need a user’s authentication token. This requires either that they authenticate using Thanx’s magic link technology, or that you authenticate them using your own authentication implementation. If you choose the latter, your system will be responsible for account creation and authentication. This limits which marketing tools the brand can use within the Thanx platform. We recommend that your experiences do not expire authentication tokens. This means consumers only need to register once per device. New customers do not need to authenticate at all; only those with existing accounts on file in the Thanx system. For existing customers, their linked credit cards and personal information will immediately be available to power their access to your program. For new customers, they don’t need to go click a link unless they return on another device, so long as you don’t expire their authentication token. ## Requirements for implementation These are requirements that we have negotiated with our card network partners. All card enrollment experiences must be approved by these partners to use the card linked APIs they provide. While you are free to design these experiences as you like, it may produce significant delays of certification. We recommend using the designs as we have presented them to ensure a speedy deployment of your application. * Legal text must be on any screen where you allow a customer to enter their card number and store for loyalty tracking. The legal copy may not be altered. * Button must say “Register card” * Legal text must be visible at all times on all devices supported * ToS and Privacy Policy must be obviously clickable (e.g. darker and underlined) * Must comply with standard accessibility guidelines in regards to color contrast and legibility (see: [https://accessible-colors.com/](https://accessible-colors.com/)) ## Design tips from our team * Fonts & colors: check font size and color contrast against accessibility standards. To check the optimal contrast for type foreground/background color you can use this tool [https://accessible-colors.com/](https://accessible-colors.com/) * Buttons: should be a min height of 40px (Apple recommends 44px) for a reasonable tap area. On screens with two buttons (ordering enrollment) both must be the same size, though they can differ in visual weight (e.g. color, outline, etc). * Forms and inputs: automatically pre-fill values in fields where possible, and let users know which fields are required (or just which are optional), and for longer forms break them down into simple steps (e.g. signup flows are better as a series of input screens). * Error handling: be as explicit as possible so users understand why they ran into an error, and give them a means to correct or move forward from there. Include support links in critical flows, where users may need further assistance. See our API docs for how to handle error responses # Create Card Source: https://docs.thanx.com/consumer/cards/create-card POST https://secure.api.thanxsandbox.com/cards This endpoint registers a new card with Thanx. This card registration endpoint allows for direct enrollment of cards with the Thanx platform for loyalty tracking via the credit card networks (Visa, Mastercard, American Express). This API endpoint is hosted by our [secure card vaulting partner](https://www.basistheory.com/security), which allows us to proxy cards for vaulting directly with the downstream credit card networks. **Note that this API uses a different API URL than other Consumer API endpoints** * Sandbox: `https://secure.api.thanxsandbox.com/cards` * Production: `https://secure.api.thanx.com/cards` Please review proper request headers [here](/consumer/usage/headers). ### Request Field The full card PAN The card's billing zip code ### Response ```bash theme={null} curl https://secure.api.thanxsandbox.com/cards \ -X POST \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" -d '{ "card": { "number": "1234123412341234" } }' ``` ```json Response Example theme={null} { "card": { "id": "92b7b0dac4", "user_id": "weorufsdf", "last4": "1234", "type": "visa", "zip_code": "12345" } } ``` # Delete Card Source: https://docs.thanx.com/consumer/cards/delete-card DELETE /cards/:id This endpoint archives a registered card. The card is unenrolled from Visa/Mastercard/Amex. Please review proper request headers [here](/consumer/usage/headers). ### Parameters The card id ```bash theme={null} curl https://api.thanxsandbox.com/cards/92b7b0dac4 \ -X DELETE \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" ``` ```bash Response Example theme={null} {} ``` # Get Cards Source: https://docs.thanx.com/consumer/cards/get-cards GET /cards This section describes endpoints that enable a third party to fetch and register a user's cards. This endpoint describes all registered cards for the given user. Please review proper request headers [here](/consumer/usage/headers). ### Response ```bash Get Cards theme={null} curl https://api.thanxsandbox.com/cards \ -X GET \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" ``` ```json Response Example theme={null} { "cards": [ { "id": "92b7b0dac4", "user_id": "weorusfs", "last4": "1234", "type": "visa", "zip_code": "12345" }, { "id": "wer340fweiu", "user_id": "weorufjsdf", "last4": "4567", "type": "amex", "zip_code": "54321" } ] } ``` # Get Communication Settings Source: https://docs.thanx.com/consumer/communication-settings/get GET /communication_settings This endpoint returns a user's communication settings. The notification key reflects a user's settings for receiving push notifications in their app. The email key reflects a user's settings for receiving emails. The sms key (under marketing_general) reflects a user's settings for receiving SMS messages. Please review proper request headers [here](/consumer/usage/headers). ### Parameters Merchant ID ### Response ```bash theme={null} curl https://api.thanxsandbox.com/communication_settings/woerihfslkwer \ -X PATCH \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" -d '{ "communication_settings": { "reward_earned": { "notification": false, "email": false }, "feedback_available": { "notification": true } } }' ``` ```json theme={null} { "communication_settings": [ { "id": "weori234098", "merchant_id": "owierywtwt", "merchant_handle": "example-merchant", "user_id": "woeruijsfwer", "reward_earned": { "notification": true, "email": true }, "reward_unused": { "notification": true, "email": true }, "reward_progress": { "notification": true, "email": true }, "reward_offer": { "notification": true, "email": true }, "feedback_available": { "notification": true }, "marketing_general": { "email": true, "sms": true } } ] } ``` # Get Communication Setting by UID Source: https://docs.thanx.com/consumer/communication-settings/get-by-uid GET /communication_settings/:uid This endpoint returns a specific communication setting by its UID. No authentication is required for this endpoint. ### Parameters The UID of the communication setting record (e.g., `4235d6d0-2698-4b27-aece-55c204d9aaab`) ### Response ```bash theme={null} curl https://api.thanxsandbox.com/communication_settings/4235d6d0-2698-4b27-aece-55c204d9aaab \ -X GET ``` ```json theme={null} { "communication_setting": { "id": "weori234098", "merchant_id": "owierywtwt", "merchant_handle": "example-merchant", "user_id": "woeruijsfwer", "reward_earned": { "notification": true, "email": true }, "reward_unused": { "notification": true, "email": true }, "reward_progress": { "notification": true, "email": true }, "reward_offer": { "notification": true, "email": true }, "feedback_available": { "notification": true }, "marketing_general": { "email": true, "sms": true } } } ``` # Update Communication Settings Source: https://docs.thanx.com/consumer/communication-settings/update PATCH /communication_settings/:id This endpoint allows the update of a user's notification / email settings. ### Parameters The ID of the settings record. Can be either a UID (SecureRandom.uuid) for unauthenticated access or an ID for authenticated access. Settings for when a user earns a loyalty reward app notification setting email setting Settings for when a user has an unused reward app notification setting email setting Settings for when a user earns loyalty progress app notification setting email setting Settings for when a merchant sends an offer app notification setting email setting Settings for when a user has the opportunity to leave feedback for a purchase app notification setting Settings for when a merchant sends general marketing email setting SMS setting ### Response ### Authentication This endpoint supports two authentication modes: * **Unauthenticated**: Use the setting's UID to update preferences without authentication * **Authenticated**: Use the setting's hashid with OAuth bearer token for authenticated access ```bash Unauthenticated (UID) theme={null} curl https://api.thanxsandbox.com/communication_settings/550e8400-e29b-41d4-a716-446655440000 \ -X PATCH \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "X-ClientId: ${client_id}" -d '{ "communication_setting": { "reward_earned": { "notification": false, "email": false }, "feedback_available": { "notification": true }, "marketing_general": { "email": true, "sms": false } } }' ``` ```bash Authenticated (Hashid) theme={null} curl https://api.thanxsandbox.com/communication_settings/woerihfslkwer \ -X PATCH \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" -d '{ "communication_setting": { "reward_earned": { "notification": false, "email": false }, "feedback_available": { "notification": true }, "marketing_general": { "email": true, "sms": false } } }' ``` ```json theme={null} { "communication_setting": { "id": "weoruoisdhf", "merchant_id": "owierywtwt", "merchant_handle": "example-merchant", "user_id": "woerushfwe", "reward_earned": { "notification": true, "email": true }, "reward_unused": { "notification": true, "email": true }, "reward_progress": { "notification": true, "email": true }, "reward_offer": { "notification": true, "email": true }, "feedback_available": { "notification": true }, "marketing_general": { "email": true, "sms": true } } } ``` # Get Features Source: https://docs.thanx.com/consumer/features/get-features GET /features This endpoint returns the configuration for a merchant's features. If a merchant does not have a particular feature defined or enabled, the value for the associated feature key will be empty. Please review proper request headers [here](/consumer/usage/headers). ### Parameters Only return features for this merchant if you have access to multiple merchants ### Response The merchant ID **This attribute is deprecated and will be removed at the end of Q3 2023. Instead, use the [points experiences](/consumer/points/get-experiences) endpoints.** Describes the configuration for the loyalty campaign Describes how the loyalty reward is earned What the user should do to earn the reward Whether the user earns progress via how much they spend or how many times they visit. Returns 'spend' or 'visit'. How much the user needs to spend or how many visits the user needs to make to earn the reward. Describes what the reward is How the reward can be redeemed (`manual`, `automatic`) Description of what the loyalty reward is Where the reward can be used: (`instore`, `online`, `all`) Describes the configuration for the introductory campaign Describes how the introductory reward is earned What the user should do to earn the reward Describes what the reward is How the reward can be redeemed (`manual`, `automatic`) Description of what the introductory reward is Where the reward can be used: (`instore`, `online`, `all`) Describes the configuration for the birthday campaign Describes how the birthday reward is earned What the user should do to earn the reward Describes what the reward is How the reward can be redeemed (`manual`, `automatic`) Description of what the birthday reward is Where the reward can be used: (`instore`, `online`, `all`) ```bash Get Features theme={null} curl https://api.thanxsandbox.com/features \ -X GET \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" ``` ```json Response Example theme={null} { "features": [ { "merchant_id": "wourhfslur", "loyalty": { // deprecated "earn": { "description": "spend $150", "threshold": 150, "type": "spend" }, "redeem": { "type": "manual", "text": "$10 off", "venue": "all" } }, "intro": { "earn": { "description": "sign up" }, "redeem": { "type": "manual", "text": "free sandwich", "venue": "online" } }, "birthday": { "earn": { "description": "provide your birthday" }, "redeem": { "type": "automatic", "text": "10% off", "venue": "instore" } } } ] } ``` # Get Feedback Source: https://docs.thanx.com/consumer/feedbacks/get-feedback GET /feedbacks/:id This endpoint returns the feedback record corresponding with the ID in the path. If the user is no longer able to leave feedback for this purchase, a 404 will be returned instead. Please review proper request headers [here](/consumer/usage/headers). ### Parameters The feedback id ### Response ```bash theme={null} curl https://api.thanxsandbox.com/feedbacks/590485d6f0 \ -X PATCH \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" -d '{ "feedback": { "rating": 10, "review": "Lorem ipsum dolor sit amet" } }' ``` ```json theme={null} { "feedback": { "id": "590485d6f0", "user_id": "fsjlk", "merchant_id": "woeri34", "location_id": "fgr2349gh", "state": "unviewed", "expires_at": "2020-01-07T20:00:00Z", "rating": null, "review": null, "response": null, "purchase": { "id": "916895d48a", "purchased_at": "2020-01-01T20:00:00Z", "amount": 16.0, "order": { "id": "aepo3cme2p", "provider": "Toast" } } } } ``` # Get Feedbacks Source: https://docs.thanx.com/consumer/feedbacks/get-feedbacks GET /feedbacks This endpoint describes the user's current feedback records. Please review proper request headers [here](/consumer/usage/headers). ### Response ```bash Get Feedbacks theme={null} curl https://api.thanxsandbox.com/feedbacks \ -X GET \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" ``` ```json theme={null} { "feedbacks": [ { "id": "590485d6f0", "user_id": "fsjlk", "merchant_id": "woeri34", "location_id": "fgr2349gh", "state": "unviewed", "expires_at": "2020-01-07T20:00:00Z", "rating": null, "review": null, "response": null, "purchase": { "id": "916895d48a", "purchased_at": "2020-01-01T20:00:00Z", "amount": 16.0, "order": { "id": "aepo3cme2p", "provider": "Toast" } } } ] } ``` # Update Feedback Source: https://docs.thanx.com/consumer/feedbacks/update-feedback PATCH /feedbacks/:id This endpoint will update a user's feedback record. Please review proper request headers [here](/consumer/usage/headers). ### Parameters The feedback id ### Parameters NPS Score, 1-10 Customer feedback ### Response ```bash theme={null} curl https://api.thanxsandbox.com/feedbacks/590485d6f0 \ -X PATCH \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" -d '{ "feedback": { "rating": 10, "review": "Lorem ipsum dolor sit amet" } }' ``` ```json theme={null} { "feedback": { "id": "590485d6f0", "user_id": "weorifsdf", "merchant_id": "9a1f0772c", "location_id": "fgr2349gh", "state": "reviewed", "expires_at": "2020-01-07T20:00:00Z", "rating": 10, "review": "Lorem ipsum dolor sit amet", "response": null, "purchase": { "id": "wourhfiwer", "purchased_at": "2020-01-01T20:00:00Z", "amount": 9.99, "order": { "id": "aepo3cme2p", "provider": "Toast" } } } } ``` # Create Gift Card Source: https://docs.thanx.com/consumer/gift-cards/create-gift-card POST /gift_cards This endpoint adds a new gift card to a user's account. This endpoint allows users to add a gift card to their account. The card is validated with the gift card provider and the balance is checked before the card is stored. The system prevents duplicate cards — the same card number cannot be added twice for the same user and merchant. Please review proper request headers [here](/consumer/usage/headers). ### Body The provider merchant ID. This identifies which gift card provider and merchant configuration to use for validation. The full gift card number The PIN code for the gift card, if required by the provider ### Response ```bash With PIN theme={null} curl https://api.thanxsandbox.com/gift_cards \ -X POST \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" \ -d '{ "provider_id": "prov123merchant", "card_number": "1234567890123456", "pin": "1234" }' ``` ```bash Without PIN theme={null} curl https://api.thanxsandbox.com/gift_cards \ -X POST \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" \ -d '{ "provider_id": "prov123merchant", "card_number": "9876543210987654" }' ``` ```json 201 Created theme={null} { "gift_card": { "id": "abc123def456", "provider_id": "prov123merchant", "card_number": "1234567890123456", "pin": "1234", "last4": "3456", "balance": 50.00, "state": "active", "expires_at": "2026-12-31T23:59:59Z", "created_at": "2024-12-15T10:00:00Z" } } ``` ```json 400 Bad Request theme={null} { "error": "This gift card has already been added" } ``` # Delete Gift Card Source: https://docs.thanx.com/consumer/gift-cards/delete-gift-card DELETE /gift_cards/{id} This endpoint archives a gift card, removing it from the user's active list. This endpoint archives a gift card, effectively removing it from the user's active gift card list. This is a soft delete — the card data is retained in the system but will no longer appear in standard gift card queries. Please review proper request headers [here](/consumer/usage/headers). ### Parameters The gift card ID to archive ### Response Returns `204 No Content` on success with an empty response body. ```bash Delete Gift Card theme={null} curl https://api.thanxsandbox.com/gift_cards/abc123def456 \ -X DELETE \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" ``` ```text 204 No Content theme={null} (empty response body) ``` # Get Gift Card Source: https://docs.thanx.com/consumer/gift-cards/get-gift-card GET /gift_cards/{id} This endpoint returns a single gift card with its current balance. This endpoint retrieves details for a specific gift card, including the current balance fetched in real-time from the gift card provider. Please review proper request headers [here](/consumer/usage/headers). ### Parameters The gift card ID ### Response ```bash Get Gift Card theme={null} curl https://api.thanxsandbox.com/gift_cards/abc123def456 \ -X GET \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" ``` ```json 200 OK theme={null} { "gift_card": { "id": "abc123def456", "provider_id": "prov123merchant", "card_number": "1234567890123456", "pin": "1234", "last4": "3456", "balance": 50.00, "state": "active", "expires_at": "2026-12-31T23:59:59Z", "created_at": "2024-12-15T10:00:00Z" } } ``` ```json 400 Bad Request theme={null} { "error": { "message": "Could not fetch balance" } } ``` # Get Gift Cards Source: https://docs.thanx.com/consumer/gift-cards/get-gift-cards GET /gift_cards This endpoint returns a paginated list of a user's active gift cards. Please review proper request headers [here](/consumer/usage/headers). ### Parameters ### Response ```bash Get Gift Cards theme={null} curl https://api.thanxsandbox.com/gift_cards \ -X GET \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" ``` ```json theme={null} { "gift_cards": [ { "id": "abc123def456", "provider_id": "prov123merchant", "card_number": "1234567890123456", "pin": "1234", "last4": "3456", "balance": 50.00, "state": "active", "expires_at": "2026-12-31T23:59:59Z", "created_at": "2024-12-15T10:00:00Z" }, { "id": "xyz789ghi012", "provider_id": "prov123merchant", "card_number": "9876543210987654", "pin": null, "last4": "7654", "balance": 25.50, "state": "active", "expires_at": null, "created_at": "2024-11-20T14:30:00Z" } ], "pagination": { "per_page": 10, "total_pages": 1, "current_page": 1 } } ``` # Get Merchant Configuration Source: https://docs.thanx.com/consumer/gift-cards/get-merchant-config GET /gift_cards/merchant_config This endpoint returns the merchant's gift card configuration for UI rendering. This endpoint retrieves the merchant's gift card configuration, including settings for external purchase links and card background styling. Use this information to customize how gift cards are displayed in your application and to provide users with links to purchase new gift cards. This configuration is useful for rendering gift card purchase buttons and customizing the appearance of gift cards in your UI. Please review proper request headers [here](/consumer/usage/headers). ### Response ```bash Get Merchant Configuration theme={null} curl https://api.thanxsandbox.com/gift_cards/merchant_config \ -X GET \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" ``` ```json 200 OK theme={null} { "merchant_config": { "id": "abc123def456ghi789j", "state": "active", "external_link": { "enabled": true, "url": "https://example.com/buy-gift-card", "image": { "small": "https://example.com/images/gift-card-button-2x.png", "large": "https://example.com/images/gift-card-button-3x.png", "default": "https://example.com/images/gift-card-button-2x.png" } }, "card_background": { "color": "#1E88E5", "type": "image", "image": { "small": "https://example.com/images/card-bg-2x.png", "large": "https://example.com/images/card-bg-3x.png", "default": "https://example.com/images/card-bg-2x.png" } } } } ``` ```json 404 Not Found theme={null} { "error": { "message": "Gift card merchant configuration not found" } } ``` # Gift Cards Overview Source: https://docs.thanx.com/consumer/gift-cards/overview The Thanx platform allows users to securely store and manage gift cards for convenient redemption. ## Introduction The Thanx Gift Cards API enables users to add, view, and manage gift cards directly within your application. Gift cards are securely stored and can be used for purchases at participating merchants. Balance information is fetched in real-time from gift card providers to ensure accuracy. ## Gift Card Lifecycle Gift cards in the Thanx platform have two primary states: #### Active A gift card is `active` when it's available for the user to view and use. Active gift cards appear in the user's gift card list and can be retrieved individually for payment operations. #### Archived A gift card is `archived` when the user chooses to remove it from their active list. Archived gift cards are soft-deleted and no longer appear in standard gift card queries, but the data is retained in the system. ## Provider Integration The Thanx platform integrates with external gift card providers to manage card validation and balance checking. When a user adds a gift card, the system validates it with the provider and fetches the current balance. Balance information is retrieved in real-time whenever gift card details are requested, ensuring users always see accurate, up-to-date information. ## Merchant Configuration Merchants can customize how gift cards are presented in your application through the merchant configuration endpoint. This configuration includes: * **External purchase links**: Direct users to a URL where they can purchase gift cards, with optional custom imagery * **Card background styling**: Customize the appearance of gift cards in your UI with colors or background images Use the [Get Merchant Configuration](/consumer/gift-cards/get-merchant-config) endpoint to retrieve these settings and render a branded gift card experience. ## Common Use Cases ### Viewing Gift Cards Use the [Get Gift Cards](/consumer/gift-cards/get-gift-cards) endpoint to display a paginated list of the user's active gift cards. This is ideal for showing all available cards in a wallet or payment selection screen. ### Adding a Gift Card Use the [Create Gift Card](/consumer/gift-cards/create-gift-card) endpoint to allow users to add new gift cards to their account. The endpoint validates the card with the provider and checks the balance before storing it. ### Viewing Card Details Use the [Get Gift Card](/consumer/gift-cards/get-gift-card) endpoint to retrieve details for a specific gift card, including the current balance. This is useful when displaying card information during checkout or in a detailed card view. ### Removing a Gift Card Use the [Delete Gift Card](/consumer/gift-cards/delete-gift-card) endpoint to archive a gift card that the user no longer wants in their active list. Please review proper request headers [here](/consumer/usage/headers). # Deep Linking Source: https://docs.thanx.com/consumer/guides/deep-linking ## Scheme registration for Deep Linking Thanx provides ways to deep link into your app from different parts of the platform. In order for that deep link to work and open your app, you'll have to register a specific scheme. Contact Merchant Success or Dev Support in order to know what would be the unique scheme you'll need to use. There are two main URLs that the Thanx platform will try to use in order to open your app: 1 - `SCHEME://open` 2 - `SCHEME://magic` The first one is a generic URL used to open your app, and the second one is used during the authentication flow; alternatively, you can configure a different redirect URI and the second (authentication) URL will never be invoked. For example, if your SCHEME is pizzaco, then the default URLs your app needs to handle are pizzaco://open and pizzaco://magic. These custom-scheme URIs must be whitelisted as `redirect_uri` values for SSO — register them verbatim (alongside your HTTPS callbacks), since the OAuth flow validates `redirect_uri` by exact string match. See [Acquire Authorization Code](/consumer/sso/acquire-auth-code). ## Configuring the scheme for iOS Add the following into your main `Info.plist` file: Where `{SCHEME}` is your own merchant scheme provided by Thanx. In general, this is the merchant's `handle`. You can find more information in the [Apple documentation](https://developer.apple.com/documentation/xcode/allowing_apps_and_websites_to_link_to_your_content/defining_a_custom_url_scheme_for_your_app) ```xml Info.plist theme={null} ... CFBundleURLTypes CFBundleTypeRole Editor CFBundleURLName Thanx CFBundleURLSchemes {SCHEME} ... ``` ## Configuring the scheme for Android Add an `intent-filter` with the following properties for the main activity in the `Manifest.xml` file: Where `{SCHEME}` is your own merchant scheme provided by Thanx. You can find more information in the [Android Developer documentation](https://developer.android.com/training/app-links/deep-linking#adding-filters) ```xml Manifest.xml theme={null} ``` # Points Integration Source: https://docs.thanx.com/consumer/guides/points # Overview The Thanx APIs now support points for a variety of integration use-cases. This document is intended to provide developers of both consumer UX integrations (via the Thanx Consumer APIs) and ordering integrations (via the Thanx Loyalty APIs) an in-depth guide covering what is required to support points. Please review this integration guide for an overview of what the expected changes are when updating your integration to support points. For specific API references, you can refer to the various API endpoints linked in this document. For any additional support, please reach out to us at [developer.support@thanx.com](mailto:developer.support@thanx.com). Our team can help answer any specific technical questions and can prepare a sandbox environment configured for points for your team to test updated integrations against before promoting the changes to production. There are multiple audiences for this integration guide and each section may not be applicable for each integration partner. While reading the whole document may be helpful for a full understanding of the various integration mechanisms, here is some guidance: * [Entities](#entities) - all developers should review this section * [Consumer UX integration](#consumer-ux-integration) - developers that only manage consumer UX experiences that are integrated with the Thanx Consumer APIs should review this section * [Order provider integration](#ordering-provider-integration) - developers that manage ordering provider systems that are integrated with the Thanx Loyalty APIs for redemption should review this section * [Consumer UX & ordering integration](#consumer-ux-and-ordering-integration) - developers that manages systems that integrate with both the Thanx Consumer APIs (consumer UX integration) and the Thanx Loyalty APIs (ordering loyalty integration) should review this section and both of the above sections. # Entities As part of this new functionality, there are now two additional conceptual entities that have been added to the Thanx platform that are available to be interacted with via API. ### Points Experience Points experiences are configuration that defines the currency that a user can earn points torward, including the conversion rate, imagery, and basic copy. Users can earn points for each configured experience through various interactions with the platform - making purchases, being issued bonus points through a campaign, etc. ### Points Product For each points experience, a merchant can configure many different points products via the merchant dashboard, which can be enabled/disabled/updated in realtime. Points products are configure that describe the reward a user can receive in exchange for accrued points for a given points experience. Each product can be redeemed for a configurable amount of points. Upon exchange of a user's points balance for a points product, the configured amount of points are deducated from the user's points balance and a reward will be added to the user's account. These rewards can then be interacted with as any other reward would. # Consumer UX integration ### Fetch points experiences The configured points experiences for a merchant are queryable via the [GET /points\_experiences](/consumer/points/get-experiences) endpoint. The information in this endpoint can be used to communicate what a user is earning points torward. ### Fetch points balance The points balance that a user currently holds for a given points experience can be queried via the [GET /points\_experiences/:id/balance](/consumer/points/get-points-balance) endpoint. ### Fetch points products The available points products a user can exchange points for are queryable in the [GET /points\_products](/consumer/points/get-products) endpoint. These can optionally be filtered by points experiences via the `points_experience_id` query parameter. ### Points redemption When a user accrues enough points and would like to exchange points for a points product, there are different mechanisms for redemption depending on the venue of redemption. Regardless of the redemption mechanism, however, the process is conceptually the same: * Points exchange is initiatied * User's points balance is validated to ensure the user's balance can cover the points cost of the product * User's points balance is deducted by the cost of the points product * A reward is issued to that user, matching the configuration of the points product * The reward can then be used as would any other reward issued to the user via campaigns or other mechanisms #### Non-ordering points redemption For non-ordering redemption, this exchange can be initiatied via the [POST /points\_products/:id/rewards](/consumer/points/exchange-product) endpoint. * The user's points balance will immediately reflect the adjusted points balance via the [GET /points\_experiences/:id/balance](/consumer/points/get-points-balance) endpoint * The reward that was issued to the user will also be immediately accessible in the [GET /rewards](/consumer/rewards/get-rewards) endpoint. * This reward can then be activated using the [PATCH /rewards/:id/activate](/consumer/rewards/activate-reward) endpoint. #### Ordering points redemption This redemption mechanism is available to all non-Olo ordering providers that have integrated with the [Thanx Loyalty APIs](/loyalty/overview). * Exchange a user's points balance for a reward following the standard non-ordering redemption flow described above. * That reward ID can then be applied to the basket directly using the existing ordering provider APIs. * Once the order is finalized, that reward will be automatically finalized and unavailable for future redemption. This redemption mechanism works even if the integrated ordering partner has not explicitly updated their integration to support points. If the ordering partner you have integrated with has updated their integration to support points directly, there may be simpler mechanisms for points redemption (eg. functionality to apply a points product directly to a basket for redemption). Please discuss your options with your ordering provider. #### Olo ordering redemption Thanx is deeply integrated with the Olo platform and this integration offers a few different mechanisms for redemption. For developers integrating with both the Thanx APIs and directly with the Olo Ordering APIs for order placement, there are two mechanisms for redemption available: **Automatic exchange** * The Thanx integration with the Olo API automatically includes the points products that a user has enough points to redeem for in the Olo loyalty rewards API endpoint, in addition to any already delivered rewards (`GET /baskets/{uid}/loyaltyrewards/qualifying`) * Note that the Olo API does not natively support points, so information about how many points will be deducted from the user's balance or additional information about the points product will not be exposed by the Olo API. * The UIDs of the available points products that are returned by the Olo API will match the `olo_uid` in the [GET /points\_products](/consumer/points/get-products) endpoint. * The points product `olo_uid` can be used just as any other Reward ID would be used in the Olo API. * Upon placement of the order, the points exchange process described above will be transparently handled in the background - deducting the user's balance, creating a new reward, and applying that reward to the Olo basket. **Manual exchange** This flow allows for full control of the redemption process and the ability to communicate more details about the points product to the user. * Exchange a user's points balance for a reward following the standard non-ordering redemption flow described above. * Once the reward is issued, Olo will then return that reward in the Olo API (`GET /baskets/{uid}/loyaltyrewards/qualifying`) * This reward will also be available in the [GET /rewards](/consumer/rewards/get-rewards) endpoint and the `olo_uid` attribute will match the reward IDs returned by the Olo API. * That reward ID can be applied to the basket via Olo APIs. * Once the order is finalized, that reward will be automatically finalized and unavailable for future redemption. points. # Ordering provider integration For ordering providers that have integrated with the [Thanx Loyalty APIs](/loyalty/overview), the Thanx APIs have been updated to minimize the number of endpoints that partners are required to interact with. While the endpoints available above are available to ordering partners, our team has attempted to make the integration upgrade process as simple as possible. The only two endpoints required for integration are: * [GET /account](/loyalty/get-account) * [POST /baskets](/loyalty/create-update-basket) Additional data attributes have been included in these endpoints. Note that the functionality of all existing integrations with these endpoints will still be fully functional. These changes are only required to support the new points loyalty engine. ### [Account endpoint](/loyalty/get-account) changes * The `progress` attribute will no longer be used for merchants that have fully transitioned to points * The `points` attribute has been added, which is an array of all the points experiences of the given merchant and the user's current points balance of that points experience's currency. * The `points_products` attribute has been added, which is an array of all the available points products that is available for the given merchant. * Note that this returns **all** of the merchant's points products, regardless of if the user can currently afford the points product. This enables ordering providers to optionally display which points products users can continue to earn toward. * Only points products available for online redemption will be included * The schema of the points products largely matches the schema of rewards, except for a few items: * `points_experience_id` is present, which is the ID of the points experience queryable via the [GET /points\_experiences/:id](/consumer/points/get-experience) endpoint * These points experience IDs match the data available in the `points` attribute. * `points` is present, which is the number of points required to exchange this points product for a reward * `retire_at` is not relevant for points products, as points have not yet been exchanged for reward * The `state` of the points products will be `redeemable` if the user has enough points balance to cover the cost of the points product and `unredeemable` if the user does not have enough points. ### [Basket endpoint](/loyalty/create-update-basket) changes In addition to the `rewards` attribute, requests now accept a `points_products` attribute which can include a points product ID. If a points product ID is specified for a basket, the points product exchange will be automatically triggered on receipt of the `placed` event. The reward that was created as a result of the points product exchange will be marked as used when the `billed` event is received (using the same points product ID used in that basket's `placed` event. Note that only a single reward or points product can currently be applied to a basket. The request will 400 if multiple rewards or points products are specified in the request. Detailed descriptions of what happens to points products when requests for each basket state are received is documented in [POST /baskets](/loyalty/create-update-basket). ## Consumer UX & ordering integration For developers that manage both consumer UX and ordering systems that are integrated with the Thanx APIs, the above guidance still applies, though there is some additional flexibility. For points product redemption for digital orders, developers can choose to exclusively leverage the explicit API for [exchanging points products](/consumer/points/exchange-product) and leave existing Loyalty API interactions untouched, ignoring the additional data attributes included in the [GET /account](/loyalty/get-account) endpoint. This is an option since exchanging points for a points products issues a reward to a user's account which will then be available to be passed to the [baskets endpoint](/loyalty/create-update-basket) via the `rewards` attribute. Developers can also choose to manage these workflows separately and handle non-ordering points redemption via the explicit API for [exchanging points products](/consumer/points/exchange-product) and handle ordering points redemption via the information coming from the [account](/loyalty/get-account) and [basket](/loyalty/create-update-basket) endpoints. This decision is up to the developer to decide what is easiest for the given integration. Our developer support team is available to provide advice and support for your specific use-case. # Integration support After reading this guide, when you are ready to update your existing integration, feel free to reach out to [developer.support@thanx.com](mailto:developer.support@thanx.com). Our developer support team can provide any integration support that you need, including access to a sandbox environment configured with the new points configuration described in this document. Don't hesitate to reach out! # Push Notifications Source: https://docs.thanx.com/consumer/guides/push-notifications Thanx sends users push notifications in a variety of situations, such as when they make a purchase or earn a reward. We can send push notifications to your app as well. When you are ready to register your app with Thanx for push notifications, you should send your CSM at Thanx your APNS certificate, FCM server key, and sender ID via a secure mechanism, such as Dropbox Transfer The rest of this page provides information regarding the types of push notifications that Thanx currently sends. A push notification payload will contain an event key and a merchant key. Each notification type may have other information provided. The sample notification text provided is not set in stone and will sometimes vary depending on the kinds of campaigns a merchant is running. ```bash Notification object example for iOS theme={null} { aps: { "alert": "You just made your first purchase at Pizza Merchant! You're now 56% towards your next reward here!", "badge": 1, "sound": "default", "content-available": 1 } "merchant_id": "oiu234oiurw", "event": "purchase_discount_applied", "purchase_id": "wotu310589" } ``` ```bash Notification object example for Android theme={null} { "content_available": true, "data": { "message": "You just made your first purchase at Pizza Merchant! You're now 56% towards your next reward here!", "merchant_id": "oiu234oiurw", "event": "purchase_discount_applied", "purchase_id": "wotu310589" }, "notification": { "title": "You just made your first purchase at Pizza Merchant! You're now 56% towards your next reward here!" } } ``` ## Purchase notifications When a user makes a purchase, one of the following notifications is sent: ### Discount Applied A user activated a statement credit reward, and this reward was applied to the purchase. *Thanx! You just saved \$10 at Pizza Merchant! It'll show up on your credit card statement in about two days.* ``` event: :purchase_discount_applied ``` Additional payload keys: ``` purchase_id: 'to35yu2o4i6y34io2j24' ``` ### Granted A user's receipt was accepted and they were granted progress toward their loyalty reward. *Heads up: Pizza Merchant granted you credit for \$15.63 toward your next reward.* ``` event: :progress_granted ``` Additional payload keys: ``` purchase_id: 'to35yu2o4i6y34io2j24' ``` ### Under Minimum A user had activated a statement credit reward, but didn't spend enough money on their subsequent purchase. *We couldn't apply your statement credit reward at Pizza Merchant - it was less than the \$25 minimum! We'll try to apply it to your next purchase.* ``` event: :reward_under_minimum ``` Additional payload keys: ``` reward_id: 'ri3of2o5i46o32iu4u4k' ``` ``` purchase_id: 'to35yu2o4i6y34io2j24' ``` ### Reward Earned This purchase resulted in a user earning their loyalty reward. *Cha-ching! You just earned \$10 off your purchase at Pizza Merchant! Open up Pizza Merchant and activate it when you're ready to use it.* ``` event: :purchase_reward_earned ``` Additional payload keys: ``` reward_id: 'ri3of2o5i46o32iu4u4k' ``` ``` purchase_id: 'to35yu2o4i6y34io2j24' ``` ### Initial Purchase The user made their first purchase. *You just made your first purchase at Pizza Merchant! You're now 56% towards your next reward here!* ``` event: :first_purchase ``` Additional payload keys: ``` purchase_id: 'to35yu2o4i6y34io2j24' ``` ### Reward Unused A user made a purchase and had a reward they could have used. *Heads up: you had a reward waiting for you at Pizza Merchant that you could have used! Activate it before your next visit!* ``` event: :purchase_reward_unused ``` Additional payload keys: ``` reward_id: 'ri3of2o5i46o32iu4u4k' ``` ``` purchase_id: 'to35yu2o4i6y34io2j24' ``` ### Invalid Purchase Amount A user made a purchase that was too small to count for loyalty progress. *Your purchase came in from Pizza Merchant but it was under the minimum purchase. Make a purchase over \$5 to earn loyalty progress.* ``` event: :purchase_under_minimum ``` Additional payload keys: ``` purchase_id: 'to35yu2o4i6y34io2j24' ``` ### Settlement Required A merchant's settings require a settlement to come in before the user can be granted loyalty progress. *Your Pizza Merchant purchase came through but reward progress won't apply until your credit card purchase settles. Stay tuned!* ``` event: :purchase_settlement_required ``` Additional payload keys: ``` purchase_id: 'to35yu2o4i6y34io2j24' ``` ### Tier Purchase Progress A user made a purchase that counted toward tier progress. If a merchant has both a loyalty campaign and tiers, the loyalty progress message will be sent instead. *You're on your way! Spend \$670.56 before the end of the year to earn Silver.* ``` event: :purchase_tier_progress ``` ### Loyalty Progress A user made a purchase that counted toward loyalty progress. *You're almost there! You're now 45% toward your next reward at Pizza Merchant.* ``` event: :purchase_loyalty_progress ``` Additional payload keys: ``` purchase_id: 'to35yu2o4i6y34io2j24' ``` ## Tiers notifications ### On track to reach the silver tier *You're on track to reach Silver for Pizza Merchant - spend \$35.24 more by Dec 31st!* ``` event: :tier_silver_on_track ``` ### Reached the silver tier *Silver rewards at Pizza Merchant are yours! Congrats on achieving Silver status!* ``` event: :tier_silver_reached ``` ### On track to reach the gold tier *You're on track to reach Gold for Pizza Merchant - spend \$23.45 more by Dec 31st!* ``` event: :tier_gold_on_track ``` ### Reached the gold tier *Congrats on achieving Gold status at Pizza Merchant! Open up the app to see your new perks!* ``` event: :tier_gold_reached ``` ### Tier status expiring soon *Your Gold status runs out in four weeks. Spend \$450.24 to keep it for another year!* ``` event: :tier_status_expiring ``` ## Vip notifications As users earn toward VIP status, they receive the following messages. ### VIP active *You're a Pizza Merchant VIP! Open up the app to check out your VIP Reward!* ``` event: :vip_active ``` ### VIP at risk *You're almost out of time! You still need to spend \$35 before Dec 1st to remain a Pizza Merchant VIP.* ``` event: :vip_at_risk ``` ### VIP eligible *You're eligible for VIP this month at Pizza Merchant! Spend \$50 before the end of the month to earn VIP status through Jan 1st!* ``` event: :vip_eligible ``` ### VIP on track *Your spending makes you eligible to earn VIP at Pizza Merchant! Spend \$50 next month to earn a free pizza all month!* ``` event: :vip_on_track ``` ### VIP nearly there *You're almost a Pizza Merchant VIP! Spend \$45 before Dec 1st to earn a free cactus all month!* ``` event: :vip_visible ``` ## Reward notifications ### A reward is issued This text is customizable by the merchant when they run a campaign. If customized text isn't provided, the following text is used. *You have a new reward from Pizza Merchant!* ``` event: :reward_issued ``` Additional payload keys: ``` reward_id: 'ri3of2o5i46o32iu4u4k' ``` ### A reward is expiring *Heads up! Your \$5 off at Pizza Merchant expires on 12/15! Don’t miss out!* ``` event: :reward_expiring ``` Additional payload keys: ``` reward_id: 'ri3of2o5i46o32iu4u4k' ``` ### A reward was granted The merchant issued a user a reward as a result of NPS feedback. *Pizza Merchant granted you a new reward: a free pizza!* ``` event: :reward_granted ``` Additional payload keys: ``` reward_id: 'ri3of2o5i46o32iu4u4k' ``` ### Reminder about an unused reward *Don't forget! You have a reward (\$15 off) waiting for you at Pizza Merchant!* ``` event: :reward_reminder ``` Additional payload keys: ``` reward_id: 'ri3of2o5i46o32iu4u4k' ``` ## Other notifications ### NPS prompt *How was your visit to Pizza Merchant?* ``` event: :purchase_nps_prompt ``` Additional payload keys: ``` purchase_id: 'to35yu2o4i6y34io2j24' ``` ``` feedback_id: 'ghjh2k34j5l23kj44566' ``` # Get Locations Source: https://docs.thanx.com/consumer/locations/get-locations GET /locations This endpoint describes locations accessible for the provided client ID. If a merchant_id is provided the locations will be further filtered. Please review proper request headers [here](/consumer/usage/headers). ### Parameters Only return locations for this merchant ### Response Location ID Merchant ID Location's street address Location's city Location's state Location's zip code The name of the location if it has one The phone number of the location Redemption type setup at the location (`direct`, `indirect`, `none`) | Type | Description | Codes | | ---------- | -------------------------------------------------- | -------------------------------- | | `direct` | Thanx has an API integration built with the POS | Custom Thanx codes: Alphanumeric | | `indirect` | POS partner has built an integration to Thanx | Custom Thanx codes: 5-digits | | `none` | There is no integration between Thanx and the POS. | Merchant managed codes | ```bash Get Locations theme={null} curl https://api.thanxsandbox.com/locations \ -X GET \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" ``` ```json theme={null} { "locations": [ { "id": "92b7b0dac4", "merchant_id": "9a1f0772c9ac", "street": "123 Pizza Lane", "city": "Smalltown", "state": "CA", "zip": "12345", "name": "Pizza Town Co", "phone": "(415) 555-3728", "loyalty_redemption_type": "direct" } ], "pagination": { "total_page": 1, "per_page": 10, "current_page": 1 } } ``` # Get Loyalty Statuses Source: https://docs.thanx.com/consumer/loyalty/get-loyalty-statuses GET /loyalty_statuses This endpoint describes the user's current loyalty statuses. Please review proper request headers [here](/consumer/usage/headers). ### Parameters Only return loyalty status for this merchant ### Response The ID of the settings record The ID of the user The ID of the merchant The user's loyalty information The user's progress toward their reward, out of 100 Whether the user earns progress via how much they spend or how many times they visit. Returns `spend` or `visit`. How much the user needs to spend or how many visits the user needs to make to earn the reward. Describes the reward the user would earn How the reward can be redeemed (`manual`, `automatic`) Description of what the reward is Where the reward can be used: (`instore`, `online`, `all`) # Overview Source: https://docs.thanx.com/consumer/overview These APIs are designed to be leveraged by brands or partners integrating Thanx loyalty into consumer experiences. If you are an existing merchant that is using the Thanx platform via the Thanx-managed branded experiences and is looking to transition to a self-managed API-integrated solution, please reach out to our success team at [merchant.success@thanx.com](mailto:merchant.success@thanx.com) to discuss what a transition may look like. If you are a new partner that builds consumer UX and is interested in establishing a partnership with Thanx, please reach out to [partnerships@thanx.com](mailto:partnerships@thanx.com). If you are an existing integration partner that is looking for technical integration support, please reach out to [developer.support@thanx.com](mailto:developer.support@thanx.com). ## Environments Thanx provides a sandbox environment for you to develop against. The data in the sandbox environment is isolated from production data. All new development must be validated and tested against the sandbox environment prior to being released into production. Do not create test artifacts in production. The Consumer API is served from the following base URLs: | Environment | Base URL | | ----------- | ------------------------------ | | Sandbox | `https://api.thanxsandbox.com` | | Production | `https://api.thanx.com` | All examples in this reference use the sandbox base URL. Swap in the production URL once your integration has been certified and production credentials have been issued. ## Credentials Thanx will provide you with a Client ID and Client Secret to use in communicating with our API. These values will be different for sandbox and production. We strongly recommend that these credentials are never used in an app build for security reasons. You should proxy your app's calls to Thanx resources through your own server whenever possible. ## Postman API Collection Here you will find the **Consumer API Postman Collection** to import directly within your API testing tool. This collection is already completed and includes sample values for the credentials. Please replace them with the ones provided by your Thanx representative in order to achieve successful API calls. You can find more information about credentials and headers on the [following page](/consumer/usage/headers), or check the documentation for the specific API endpoint you want to call to ensure that all credentials are placed correctly. Download Postman Collection # Exchange Points Product Source: https://docs.thanx.com/consumer/points/exchange-product POST /points_products/:id/rewards This endpoint exchanges the user's points for the specified points product Please review proper request headers [here](/consumer/usage/headers). ### Parameters The points product ID ### Response ```bash Exchange Point Products theme={null} curl https://api.thanxsandbox.com/points_products/:id/rewards \ -X POST \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" ``` ```json theme={null} { "reward": { "id": "222441e34626", "olo_uid": "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn", "user_id": "werofsdf", "merchant_id": "weroif", "campaign_id": "85133c3c1258", "state": "available", "earn": { "type": "points_exchange", "text": "description" }, "redeem": { "type": "manual", "text": "Garlic fries", "window": 60, "venue": "all" }, "coupon_code": { "code": null, "type": null, "display": null }, "fine_print": "Can't be used for alcohol purchases", "instructions": "Example staff instructions", "available_at": "2019-12-25T19:00:00Z", "activated_at": "2020-01-01T20:00:00Z", "retire_at": null, "used_at": null, "images": { "index": { "small": "https://...png", "large": "https://...png" }, "detail": { "small": "https://...png", "large": "https://...png" }, "advertising": { "small": "https://...png", "large": "https://...png" } }, "uses_dynamic_coupon_codes": false } } ``` # Get Points Experience Source: https://docs.thanx.com/consumer/points/get-experience GET /points_experiences/:id This endpoint returns a single points experience specified by ID. Please review proper request headers [here](/consumer/usage/headers). ### Parameters The ID of the points experience ### Response ```bash Get Points Experience theme={null} curl https://api.thanxsandbox.com/points_experiences/:id \ -X GET \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" ``` ```json theme={null} { "points_experience": { "id": "590485d6f0", "merchant_id": "woeri34", "name": "Merchant Points", "currency": { "name": "Star", "plural": "Stars", "description": "Collect 1 star for every 1 dollar spent", "conversion": 1.0 }, "images": { "earn": { "small": "https://...png", "default": "https://...png", "large": "https://...png" }, "currency_primary": { "small": "https://...png", "medium": "https://...png", "default": "https://...png", "large": "https://...png" }, "currency_secondary": { "small": "https://...png", "medium": "https://...png", "default": "https://...png", "large": "https://...png" } } } } ``` # Get Points Experiences Source: https://docs.thanx.com/consumer/points/get-experiences GET /points_experiences This endpoint returns the points experiences for the merchant. Please review proper request headers [here](/consumer/usage/headers). ### Parameters Only return points experiences configured for this merchant ### Response ```bash Get Points Experiences theme={null} curl https://api.thanxsandbox.com/points_experiences \ -X GET \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" ``` ```json theme={null} { "points_experiences": [ { "id": "590485d6f0", "merchant_id": "woeri34", "name": "Merchant Points", "currency": { "name": "Star", "plural": "Stars", "description": "Collect 1 star for every 1 dollar spent", "conversion": 1.0 }, "images": { "earn": { "small": "https://...png", "default": "https://...png", "large": "https://...png" }, "currency_primary": { "small": "https://...png", "medium": "https://...png", "default": "https://...png", "large": "https://...png" }, "currency_secondary": { "small": "https://...png", "medium": "https://...png", "default": "https://...png", "large": "https://...png" } } } ] } ``` # Get Points Balance Source: https://docs.thanx.com/consumer/points/get-points-balance GET /points_experiences/:id/balance This endpoint returns the specified points experience balance for the given user Please review proper request headers [here](/consumer/usage/headers). ### Response The user's current balance of the currency of the points experience ```bash Get Points Balance theme={null} curl https://api.thanxsandbox.com/points_experiences/:id/balance \ -X GET \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" ``` ```json theme={null} { "balance": 10.0 } ``` # Get Points Multipliers Source: https://docs.thanx.com/consumer/points/get-points-multipliers GET /points_multipliers This endpoint returns the configured points multipliers for the experience. Please review proper request headers [here](/consumer/usage/headers). ### Parameters Only return points products configured for this points experience ### Response ```bash Get Points Multipliers theme={null} curl https://api.thanxsandbox.com/points_multiplier \ -X GET \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" ``` ```json theme={null} { "points_multipliers": [ { "id": "dq7xkm2ph0my36n", "points_experience_id": "5nxe1pxwhqg2kmr", "factor": "1.9", "date_range_starts_on": "2023-12-19", "date_range_ends_on": "2023-12-25" } ] } ``` # Get Points Products Source: https://docs.thanx.com/consumer/points/get-products GET /points_products This endpoint returns the configured points products. Please review proper request headers [here](/consumer/usage/headers). ### Parameters Only return points products configured for this merchant Only return points products configured for this points experience ### Response ```bash Get Points Products theme={null} curl https://api.thanxsandbox.com/points_products \ -X GET \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" ``` ```json theme={null} { "points_products": [ { "id": "9xw6543wh8jmde0", "olo_uid": "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn", "points_experience_id": "590485d6f0", "cost": 10, "exchange_start_at": "2022-01-02T00:00:01.000Z", "exchange_end_at": "2022-02-02T00:00:01.000Z", "fine_print": "...", "redeem": { "type": "manual", "venue": "instore", "window": 60, "text": "Onion rings", "detail": "Crispy, golden brown and bursting with flavor, our onion rings are the perfect addition to any meal.", "restrictions": "Redemption restriction description" }, "valid_locations": [ "80925z17h8j7vmk" ], "image": { "small": "https://...png", "default": "https://...png", "large": "https://...png" }, "uses_dynamic_coupon_codes": false } ] } ``` # Create Purchase Source: https://docs.thanx.com/consumer/purchases/create-purchase POST /purchases This endpoint submits a purchase to our system for processing. Because this purchase is processed asynchronously, there is no response JSON. Please allow up to a couple minutes to receive this purchase back from the GET /purchases endpoint. **This endpoint is only available in SANDBOX** Please review proper request headers [here](/consumer/usage/headers). ### Response The merchant ID Location ID The purchase amount Time the purchase was made in ISO8601-format The card the user used, if it is registered in Thanx ```bash theme={null} curl https://api.thanxsandbox.com/purchases \ -X POST \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" -d '{ "purchase": { "merchant_id": "weoru", "location_id": "hljkfd2345", "user_id": "wgljsdwer23", "amount": 13.45, "purchased_at": "2020-09-15T00:52:10.655+00:00", "card_id": null } }' ``` ```json theme={null} {} ``` # Get Purchase Source: https://docs.thanx.com/consumer/purchases/get-purchase GET /purchases/:id This endpoint returns the purchase associated with the id in the path. Please review proper request headers [here](/consumer/usage/headers). ### Parameters The purchase ID ### Response The purchase ID The user ID The merchant ID Location ID Time the purchase was made in ISO8601-format The purchase amount Provides information about the associated order, if any The ID of the order in the provider's system The online ordering provider (`OLO`, `Toast`, `Other`) ```bash Get Purchease theme={null} curl https://api.thanxsandbox.com/purchases/:id \ -X GET \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" ``` ```json theme={null} { "purchase": { "id": "92b7b0dac4", "user_id": "weori235", "merchant_id": "9a1f0772c9ac", "location_id": "e7183da044", "purchased_at": "2020-01-01T20:00:00Z", "amount": 9.99, "order": { "provider": "OLO", "id": "YWEI2342F" } } } ``` # Get Purchases Source: https://docs.thanx.com/consumer/purchases/get-purchases GET /purchases This section describes endpoints that enable a third party to fetch a user's purchases. This endpoint describes all available purchases. Please review proper request headers [here](/consumer/usage/headers). ### Parameters Only return purchases for this merchant Only return purchases for this location Only return purchases for this user. Note: the bearer token will be used to determine which user's purchases are being requested when the request is made by a logged in user. ### Response The ID of the purchase record The user ID The merchant ID Location ID Time the purchase was made in ISO8601-format The purchase amount Provides information about the associated order, if any The ID of the order in the provider's system The online ordering provider (`OLO`, `Toast`, `Other`) ```bash Get Purcheases theme={null} curl https://api.thanxsandbox.com/purchases \ -X GET \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" ``` ```json theme={null} { "purchases": [ { "id": "92b7b0dac4", "user_id": "weori235", "merchant_id": "9a1f0772c9ac", "location_id": "e7183da044", "purchased_at": "2020-01-01T20:00:00Z", "amount": 9.99, "order": { "provider": "OLO", "id": "YWEI2342F" } } ], "pagination": { "total_page": 1, "per_page": 10, "current_page": 1 } } ``` # Update Purchase Tags Source: https://docs.thanx.com/consumer/purchases/update-tags PUT /purchases/:id/tags This endpoint updates an attribute tag for the given purchase. The tag associated with the key in the request will be created or updated with the values passed in. Please review proper request headers [here](/consumer/usage/headers). ### Parameters Purchase ID Tag key Array of attributes tags ### Response Tag ID Purchase ID Tag key Array of attribute tags ```bash theme={null} curl https://api.thanxsandbox.com/purchases/wourhfiwer/tags \ -X PUT \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "X-ClientId: ${client_id}" -d '{ "tag": { "key": "server_satisfaction", "values": [ "10" ] } }' ``` ```json theme={null} { "tag": { "id": "werwerr", "purchase_id": "wourhfiwer", "key": "server_satisfaction", "values": [ "10" ] } } ``` # Create Push Registration Source: https://docs.thanx.com/consumer/push/create-push-registration PUT /push_registrations This endpoint creates or updates a push registration record for a user's device. Please review proper request headers [here](/consumer/usage/headers). ### Parameters The type of device: (`ios`, `android`) The token returned by the local push notification library ### Response The type of device: (`ios`, `android`) The token returned by the local push notification library ```bash theme={null} curl https://api.thanxsandbox.com/push_registrations \ -X PUT \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" -d '{ "push_registration": { "device_type": "ios", "token": "wourdweroi238432423425fsgd" } }' ``` ```json theme={null} { "push_registration": { "token": "wourdweroi238432423425fsgd", "device_type": "ios" } } ``` # Create Receipt Source: https://docs.thanx.com/consumer/receipts/create-receipt POST /receipts This endpoint submits a receipt for processing. Please review proper request headers [here](/consumer/usage/headers). ### Parameters Merchant ID The amount of the receipt (`card`, `cash`, `other`) The timestamp of the purchase, in ISO8601 The path of the uploaded image Any user-entered notes The card the user used, if it is registered in Thanx ### Response ```bash theme={null} curl https://api.thanxsandbox.com/receipts \ -X POST \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" -d '{ "receipt": { "merchant_id": "weoru", "amount": 13.45, "payment_type": "cash", "purchased_at": "2020-09-15T00:52:10.655+00:00", "image_path": "uploads/receipts/image_5051555_1534872299.jpeg", "user_comments": "credit card reader was not working", "card_id": null } }' ``` ```json theme={null} { "receipt": { "id": "92b7b0dac4", "user_id": "weorufsdf", "merchant_id": "werouf", "state": "pending", "rejection_text": null, "amount": 13.45, "payment_type": "cash", "purchased_at": "2020-09-15T00:52:10.655+00:00", "submitted_at": "2020-09-15T00:55:11.876+00:00", "user_comments": "credit card reader was not working", "card_id": null, "image": { "small": "https://d1uv7brpxddy46.cloudfront.net/images/363/thumbnail/thumbnail-612c5e1821440637c0137be46d141e07.jpg?1604507010", "large": "https://d1uv7brpxddy46.cloudfront.net/images/363/medium/medium-612c5e1821440637c0137be46d141e07.jpg?1604507010", "default": "https://d1uv7brpxddy46.cloudfront.net/images/363/mobile/mobile-612c5e1821440637c0137be46d141e07.jpg?1604507010" } } } ``` # Get Receipts Source: https://docs.thanx.com/consumer/receipts/get-receipts GET /receipts This endpoint describes the receipts in Thanx. Please review proper request headers [here](/consumer/usage/headers). ### Parameters User ID. Note: the bearer token will be used to determine which user's receipts are being requested when the request is made by a logged in user. Merchant ID ### Response ```bash Get Receipts theme={null} curl https://api.thanxsandbox.com/receipts \ -X GET \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" ``` ```json theme={null} { "receipts": [ { "id": "92b7b0dac4", "user_id": "weorufsdf", "merchant_id": "werouf", "state": "pending", "rejection_text": null, "amount": 13.45, "payment_type": "cash", "purchased_at": "2020-09-15T00:52:10.655+00:00", "submitted_at": "2020-09-15T00:55:11.876+00:00", "user_comments": "credit card reader was not working", "card_id": null, "image": { "small": "https://d1uv7brpxddy46.cloudfront.net/images/363/thumbnail/thumbnail-612c5e1821440637c0137be46d141e07.jpg?1604507010", "large": "https://d1uv7brpxddy46.cloudfront.net/images/363/medium/medium-612c5e1821440637c0137be46d141e07.jpg?1604507010", "default": "https://d1uv7brpxddy46.cloudfront.net/images/363/mobile/mobile-612c5e1821440637c0137be46d141e07.jpg?1604507010" } } ] } ``` # Get Upload URL Source: https://docs.thanx.com/consumer/receipts/get-upload-url GET /upload_url This endpoint provides a pre-signed url where an image or file can be uploaded. In order to submit a receipt to Thanx, you must first make a request to the API to get a pre-signed upload URL. Once you have uploaded the image to this URL, make a `POST /receipts` request to create the receipt in Thanx. Please review proper request headers [here](/consumer/usage/headers). The `file_path` can be used as the input to the `POST /receipts` endpoint. ### Parameters The type of upload; currently only option is (`receipt`) ### Response Url to upload the image to Path where the image will be saved ```bash Get Upload Url theme={null} curl https://api.thanxsandbox.com/upload_url \ -X GET \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" ``` ```json theme={null} { "upload_url": { "url": "https://thanx.s3.amazonaws.com/uploads/receipts/image_5051555_1534872299.jpeg?AWS-PARAMS", "file_path": "uploads/receipts/image_5051555_1534872299.jpeg" } } ``` # Overview Source: https://docs.thanx.com/consumer/receipts/overview # How to Upload a Receipt Image Using a Presigned URL This guide explains the complete workflow for uploading receipt images using the Thanx API ## Overview of the Flow Thanx uses two separate endpoints for handling receipt uploads: 1. [Get Upload URL](/consumer/receipts/get-upload-url) — to obtain a presigned aws s3 url. 2. [Create Receipt](/consumer/receipts/create-receipt) — to create a receipt referencing the uploaded image via `image_path`. *** ## Step 1 — [Request a Presigned Upload URL](/consumer/receipts/get-upload-url) ### Example Request ```curl theme={null} curl -X GET "https://api.thanxsandbox.com/upload_url?upload_type=receipt" \ -H "Authorization: Bearer <token>" \ -H "Accept-Version: v4.0" ``` ### Successful Response ``` { "url": "https://thanx-sandbox.s3.amazonaws.com/uploads/receipt/...", "image_path": "uploads/receipt/image_<unique>.jpeg" } ``` The presigned URL expires. Make sure to upload your file before it does. *** ## Step 2 — Upload the Image to S3 Using the Presigned URL The upload must be **raw binary**. Multipart uploads will corrupt the file and cause validation errors. ### Correct Upload Using curl ``` curl -X PUT "presigned_url;" \ -H "Content-Type: image/jpeg" \ --data-binary @"my_receipt.jpg" ``` ### Correct Upload Using Postman * Method → **PUT** * URL → paste the full presigned URL * Body → select **binary** * Click **Select File** * Headers → add: `Content-Type: image/jpeg` ### Do Not Use * form-data * raw * file upload inside raw * multipart/form-data These formats produce the error: ``` Image content type is not a valid image ``` *** ## Step 3 — [Submit the Receipt](/consumer/receipts/create-receipt) Once the image is successfully uploaded to S3, you can submit the receipt. ### Example Request ``` curl https://api.thanxsandbox.com/receipts \ -X POST \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Authorization: Bearer " \ -d '{ "receipt": { "merchant_id": "abc123", "amount": 13.45, "payment_type": "cash", "purchased_at": "2024-09-15T00:52:10.655+00:00", "image_path": "uploads/receipt/image_.jpeg", "user_comments": "Card reader was down" } }' ``` ### Internal Note The Thanx backend temporarily downloads the image from S3 for processing and deletes the temporary upload afterward. *** ## Common Errors & Fixes ### Error: `Image content type is not a valid image` **Cause:** The file was uploaded using multipart/form-data.\ **Fix:** Re-upload using raw binary. *** ### Error: `Image file is empty or corrupted` **Causes:** * Missing `--data-binary` * Incorrect `Content-Type` * Expired presigned URL **Fix:** Ensure: * Correct content type * URL is still valid * Upload is binary *** ## Summary * 1 Request presigned URL via `/upload_url` * 2 Upload the image to S3 using a PUT binary request * 3 Submit the receipt using the returned `image_path` # Activate Reward Source: https://docs.thanx.com/consumer/rewards/activate-reward PATCH /rewards/:id/activate This endpoint activates the reward, transitioning reward state from available to active. For bonus points (also know as static rewards), this endpoint sets the reward state to used after activation (see [overview](/consumer/rewards/overview) for more information). Please review proper request headers [here](/consumer/usage/headers). When a reward has `uses_dynamic_coupon_codes: true`, activating the reward will generate a unique coupon code from the associated coupon pool. The generated code will be returned in the `coupon_code` field of the response. ### Parameters The reward ID The location ID at which the reward was redeemed ### Response ```bash Activate Reward theme={null} curl https://api.thanxsandbox.com/rewards/:id/activate \ -X PATCH \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" ``` ```json theme={null} { "reward": { "id": "222441e34626", "olo_uid": "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn", "user_id": "werofsdf", "merchant_id": "weroif", "campaign_id": "85133c3c1258", "state": "active", "earn": { "type": "intro" }, "redeem": { "type": "manual", "text": "$10 off", "detail": "Long description", "window": 60, "venue": "all" }, "coupon_code": { "code": null, "type": null, "display": null }, "fine_print": "Can't be used for alcohol purchases", "instructions": "Example staff instructions", "available_at": "2019-12-25T19:00:00Z", "activated_at": "2020-01-01T20:00:00Z", "retire_at": null, "used_at": null, "images": { "index": { "small": "https://...png", "large": "https://...png" }, "detail": { "small": "https://...png", "large": "https://...png" }, "advertising": { "small": "https://...png", "large": "https://...png" } }, "uses_dynamic_coupon_codes": false } } ``` # Finalize Reward Source: https://docs.thanx.com/consumer/rewards/finalize-reward PATCH /rewards/:id/finalize This endpoint marks an unused reward as used, transitioning the reward state from active to used. Please review proper request headers [here](/consumer/usage/headers). ### Parameters The reward ID ### Response ```bash theme={null} curl https://api.thanxsandbox.com/rewards/grant \ -X POST \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" -d '{ "user_id": "weoru", "campaign_id": "weroui234890f" }' ``` ```json theme={null} { "reward": { "id": "222441e34626", "olo_uid": "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn", "user_id": "werofsdf", "merchant_id": "weroif", "campaign_id": "85133c3c1258", "state": "used", "earn": { "type": "intro" }, "redeem": { "type": "manual", "text": "$10 off", "detail": "Long description", "window": 60, "venue": "all" }, "coupon_code": { "code": null, "type": null, "display": null }, "fine_print": "Can't be used for alcohol purchases", "instructions": "Example staff instructions", "available_at": "2019-12-25T19:00:00Z", "activated_at": "2020-01-01T20:00:00Z", "retire_at": null, "used_at": null, "images": { "index": { "small": "https://...png", "large": "https://...png" }, "detail": { "small": "https://...png", "large": "https://...png" }, "advertising": { "small": "https://...png", "large": "https://...png" } }, "uses_dynamic_coupon_codes": false } } ``` # Get Reward Source: https://docs.thanx.com/consumer/rewards/get-reward GET /rewards/:id This endpoint returns the reward corresponding to the ID in the path. Please review proper request headers [here](/consumer/usage/headers). ### Parameters The reward ID ### Response ```bash Get Reward theme={null} curl https://api.thanxsandbox.com/rewards/:id \ -X GET \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" ``` ```json theme={null} { "reward": { "id": "222441e34626", "olo_uid": "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn", "user_id": "werofsdf", "merchant_id": "weroif", "campaign_id": "85133c3c1258", "state": "available", "earn": { "type": "intro" }, "redeem": { "type": "manual", "text": "$10 off", "detail": "Long description", "window": 60, "venue": "all" }, "coupon_code": { "code": null, "type": null, "display": null }, "fine_print": "Can't be used for alcohol purchases", "instructions": "Example staff instructions", "available_at": "2019-12-25T19:00:00Z", "activated_at": "2020-01-01T20:00:00Z", "retire_at": null, "used_at": null, "images": { "index": { "small": "https://...png", // width: 563px "large": "https://...png" // width: 1125px }, "detail": { "small": "https://...png", // width: 642px "large": "https://...png" // width: 1284px }, "advertising": { "small": "https://...png", // width: 430px "large": "https://...png" // width: 860px } }, "redemption_location_id": "92b7b0dac4", "uses_dynamic_coupon_codes": false } } ``` # Get Rewards Source: https://docs.thanx.com/consumer/rewards/get-rewards GET /rewards This endpoint returns a user's rewards. Please review proper request headers [here](/consumer/usage/headers). ### Parameters Only rewards in these states will be returned. Valid options are: (`available`, `active`, `used`). The default is to return all rewards in these 3 states. Use array bracket notation: `states[]=available`. For multiple states: `states[]=available&states[]=active`. | State | Description | | ----------- | ------------------------------------------ | | `available` | This reward is `available` to use | | `active` | The user has activated this reward for use | | `used` | The reward has been used | Only return features for this merchant if you have access to multiple merchants Only return rewards for this user. Note: the bearer token will be used to determine which user's rewards are being requested when the request is made by a logged in user. ### Response ```bash Get Rewards theme={null} curl "https://api.thanxsandbox.com/rewards?states[]=available" \ -X GET \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" ``` ```json theme={null} { "rewards": [ { "id": "222441e34626", "olo_uid": "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn", "user_id": "werofsdf", "merchant_id": "weroif", "campaign_id": "85133c3c1258", "state": "available", "earn": { "type": "intro" }, "redeem": { "type": "manual", "text": "$10 off", "detail": "Long description", "window": 60, "venue": "all" }, "coupon_code": { "code": null, "type": null, "display": null }, "fine_print": "Can't be used for alcohol purchases", "instructions": "Example staff instructions", "available_at": "2019-12-25T19:00:00Z", "activated_at": "2020-01-01T20:00:00Z", "retire_at": null, "used_at": null, "images": { "index": { "small": "https://...png", "large": "https://...png" }, "detail": { "small": "https://...png", "large": "https://...png" }, "advertising": { "small": "https://...png", "large": "https://...png" } }, "uses_dynamic_coupon_codes": false } ] ``` # Grant Reward Source: https://docs.thanx.com/consumer/rewards/grant-reward POST /rewards/grant This endpoint grants the user a reward associated with the campaign provided. Please review proper request headers [here](/consumer/usage/headers). This endpoint is only available in SANDBOX ### Parameters The campaign id to grant the reward for. Must be the campaign's **hashid** (e.g., `85133c3c1258`), not the numeric program ID. The user to grant the reward for ### Response ```bash Grant Reward theme={null} curl https://api.thanxsandbox.com/rewards/grant \ -X POST \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" ``` ```json theme={null} { "reward": { "id": "222441e34626", "olo_uid": "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn", "user_id": "werofsdf", "merchant_id": "weroif", "campaign_id": "85133c3c1258", "state": "available", "earn": { "type": "intro" }, "redeem": { "type": "manual", "text": "$10 off", "detail": "Long description", "window": 60, "venue": "all" }, "coupon_code": { "code": null, "type": null, "display": null }, "fine_print": "Can't be used for alcohol purchases", "instructions": "Example staff instructions", "available_at": "2019-12-25T19:00:00Z", "activated_at": "2020-01-01T20:00:00Z", "retire_at": null, "used_at": null, "images": { "index": { "small": "https://...png", "large": "https://...png" }, "detail": { "small": "https://...png", "large": "https://...png" }, "advertising": { "small": "https://...png", "large": "https://...png" } }, "uses_dynamic_coupon_codes": false } } ``` # Reward Overview Source: https://docs.thanx.com/consumer/rewards/overview The Thanx platform supports a number of different reward redemption types — allowing for significant flexibility in what brands can offer to their users. ## Redemption Types #### Manual Rewards (in-store redemption) These rewards are intended to be used for in-store redemption. Rewards of this type are indicated in the API by the `redeem.type` set to `manual` with a `redeem.venue` set to `instore` or `all` (both digital and in-store). These rewards should be [activated](/consumer/rewards/activate-reward) by the customer. After activation, the user has a given number of minutes indicated by the `redeem.window` attribute to use the reward in-store. We recommend displaying a timer to the user indicating how long a user has left to redeem the reward. In addition, we recommend adding a "mark as used" button which, when pressed, should call the [finalize reward](/consumer/rewards/finalize-reward) endpoint. Manual rewards optionally have a code associated with it in a variety of formats that can be displayed on the "active reward" screen to the user. Upon activation, should a reward be configured with a code, the `coupon_code` attribute will be populated. The `coupon_code.type` attribute is used to indicate what format the `coupon_code.code` should be encoded in format indicated by the `coupon_code.type` attribute. If `coupon_code.display` is set, the `coupon_code.code` value should still be the value used for encoding, but the `coupon_code.display` value can be displayed as a text label below the encoded coupon code value. #### Manual Rewards (digital redemption) These rewards are intended to be used for digital redemption. Rewards of this type are indicated in the API by the `redeem.type` set to `manual` with a `redeem.venue` set to `online` or `all` (both digital and in-store). Thanx is integrated with a number of online ordering providers, like Olo. Given existing integrations with these providers, Thanx rewards can be redeemed for a digital order via the ordering provider's APIs. Please refer to the ordering platform's API documentation for additional details. Upon placement of an order via the ordering platform's API, the rewards in Thanx will be automatically marked as `used`. #### Static rewards (bonus points) Bonus points are special rewards given to customers participating in a points-based rewards or loyalty program. These rewards can be awarded during specific promotions, campaigns, or when a customer advances to a new tier in the loyalty program. Rewards of this type are indicated in the API by the `redeem.type` set to `points`. However, the process for redeeming bonus points differs from regular rewards. The reward is immediately redeemed, and there is no expiry window. Consequently, once bonus points are [activated](/consumer/rewards/activate-reward), they are instantly marked as used, eliminating the need to call the [finalize reward](/consumer/rewards/finalize-reward) endpoint. The digital experience is responsible for activating the bonus points when users open that experience in a logged-in state. This ensures that users who do not open the app during the period when the bonus point reward is available will not receive the additional bonus points, encouraging customer engagement. #### Experience (access pass) These rewards can be offered by brands to enable experiential incentives for users. Rewards of this type are indicated in the API by the `redeem.type` set to `experience`. Despite their power, they are actually quite simple. Like manual rewards, a user can [activate](/consumer/rewards/activate-reward) a reward of this type. Upon activation, the image specified in `images.detail` is intended to be displayed to the user. The image can be optionally hyperlinked to the `redeem.url` if a URL has been configured for the reward. Given an "Access Pass" is simply a reward with an image and optional URL that can be displayed to a user upon activation, this allows for significant flexibility and creativity in what experiential reward is offered to end-users. #### Automatic Rewards (statement credit) These rewards are intended to be used for automatic application of a statement credit directly back to a user's credit card. Rewards of this type are indicated in the API by the `redeem.type` set to `automatic`. A reward of this type should be [activated](/consumer/rewards/activate-reward), after which it will continue to be in the `active` state until a qualifying purchase is detected by Thanx. Upon detection of a purchase, the reward will automatically be transitioned to the `used` state and a statement credit will be pushed directly to the user's credit card. If your brand would like to deploy statement credit rewards, please discuss with your success manager — as this pre-funding of a balance that can be used for statement credit rewards. # Update reward Source: https://docs.thanx.com/consumer/rewards/update-reward PATCH /rewards/:id This endpoint updates the redemption location for an active reward. Please review proper request headers [here](/consumer/usage/headers). ### Parameters The reward ID The ID of the new redemption location to update for the reward. ### Response ```bash Update Reward theme={null} curl https://api.thanxsandbox.com/rewards/:id \ -X PATCH \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" ``` ```json theme={null} { "reward": { "id": "222441e34626", "olo_uid": "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn", "user_id": "werofsdf", "merchant_id": "weroif", "campaign_id": "85133c3c1258", "state": "available", "earn": { "type": "intro" }, "redeem": { "type": "manual", "text": "$10 off", "detail": "Long description", "window": 60, "venue": "all" }, "coupon_code": { "code": null, "type": null, "display": null }, "fine_print": "Can't be used for alcohol purchases", "instructions": "Example staff instructions", "available_at": "2019-12-25T19:00:00Z", "activated_at": "2020-01-01T20:00:00Z", "retire_at": null, "used_at": null, "images": { "index": { "small": "https://...png", // width: 563px "large": "https://...png" // width: 1125px }, "detail": { "small": "https://...png", // width: 642px "large": "https://...png" // width: 1284px }, "advertising": { "small": "https://...png", // width: 430px "large": "https://...png" // width: 860px } }, "redemption_location_id": "92b7b0dac4", "uses_dynamic_coupon_codes": false } } ``` # Get Signup Program Source: https://docs.thanx.com/consumer/signup-programs/get-signup-program GET /signup_programs/:handle This endpoint returns a specific signup program by its handle. This endpoint returns a specific active signup program identified by its handle. If the program is not found or not accessible, a 404 error is returned. This endpoint is publicly accessible and does not require authentication. Programs are filtered based on the OAuth application context. ### Parameters The URL-friendly handle of the signup program ### Response ```bash Get Signup Program theme={null} curl https://api.thanxsandbox.com/signup_programs/welcome-reward \ -X GET \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "X-ClientId: ${client_id}" ``` ```json theme={null} { "program": { "id": "awe833ke24", "merchant_id": "ghwou3457f", "name": "Welcome Reward", "handle": "welcome-reward", "redeem": { "type": "manual", "text": "$5 off your next purchase", "detail": "Use this reward on your next visit", "window": 60, "venue": "all" } } } ``` # Get Signup Programs Source: https://docs.thanx.com/consumer/signup-programs/get-signup-programs GET /signup_programs This endpoint returns active signup programs. This endpoint returns a list of active signup programs (earn\_intro\_premium) that are available for the merchant. These programs are typically displayed to users during the signup flow. This endpoint is publicly accessible and does not require authentication. Programs are filtered based on the OAuth application context. ### Response ```bash Get Signup Programs theme={null} curl https://api.thanxsandbox.com/signup_programs \ -X GET \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "X-ClientId: ${client_id}" ``` ```json theme={null} { "programs": [ { "id": "awe833ke24", "merchant_id": "ghwou3457f", "name": "Welcome Reward", "handle": "welcome-reward", "redeem": { "type": "manual", "text": "$5 off your next purchase", "detail": "Use this reward on your next visit", "window": 60, "venue": "all" } } ] } ``` # Acquire Access Token Source: https://docs.thanx.com/consumer/sso/acquire-access-token POST /oauth/token Use this endpoint to acquire a user's access token. This same endpoint supports refreshing an access token using the `client_id`, `client_secret`, and `refresh_token`, with `grant_type` set to `refresh_token`. ### Parameters authorization\_code is the required value OAuth Client ID OAuth Client Secret The authorization code received from Thanx via redirect or API The same redirect\_uri should be used as in the request for the authorization code ### Response The type of token, usually "Bearer" This will be 'passwordless' The number of seconds since the epoch The user's access token, for use in accessing other API endpoints If needed, a refresh token to get another access token ```bash theme={null} curl https://api.thanxsandbox.com/oauth/token \ -X POST \ -H "Content-Type: application/json" \ -d '{ "grant_type": "authorization_code", "client_id": "${client_id}", "client_secret": "${client_secret}", "code": "${code}", "redirect_uri": "https://www.example.com/oauth/callback" }' ``` ```json Response Example theme={null} { "token_type": "Bearer", "scope": "passwordless", "created_at": 1577836800, "access_token": "945148251b603ae34561d90acfe4050e67494d6d1e65d4d3d52798407f03c0bd", "refresh_token": "c74334301a7c74d21b714c905fd3047177dab56de6a86899e6f6b7f71bab7d55" } ``` ```json 401 (Unauthorized) theme={null} { "error": "invalid_grant", "error_description": "The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client." } ``` # Acquire Authorization Code Source: https://docs.thanx.com/consumer/sso/acquire-auth-code POST /oauth/authorize This endpoint triggers the passwordless login flow. Calling this endpoint will send a passwordless email to the email address specified as the `username`. The response to this request will be a `200` and an empty response body. The passwordless email will contain a link to log in which will redirect the user to the specified `redirect_uri` with the authorization code included in the query params (`?code=...`). The `redirect_uri` must be whitelisted for your integration by our developer support team. If you need a URL added or changed, feel free to write to [developer.support@thanx.com](mailto:developer.support@thanx.com). `redirect_uri` is validated by **exact string match**. Register every URI you use — including native custom-scheme deeplinks (`yourscheme://magic`, `yourscheme://open`) **verbatim and separately** from your HTTPS web callbacks. Registering only HTTPS callbacks makes native sign-in fail with `invalid_redirect_uri`. Custom schemes are kept as-is — do not convert them to `https`. Note that abitrary data can be passed through this authentication process by using custom query parameters. For example, for the whitelisted `redirect_uri` of `https://www.example.com/oauth/callback`, query parameters can be appended to the URL and will be passed through the entire auth process. As an example, `https://www.example.com/oauth/callback?table=1` as the input `redirect_uri` to the API request would preserve `table=1`. Note that the `code` value is a reserved parameter that should not be used, as that will conflict with the access code that will be appended to the `redirect_uri`. If an account does not exist for the specified email, a 401 error will be returned. To create an account, the [POST /users](/consumer/users/create-user) endpoint should be used. ```bash theme={null} curl https://api.thanxsandbox.com/oauth/authorize \ -X POST \ -H "Content-Type: application/json" \ -d '{ "client_id": "${client_id}", "redirect_uri": "https://www.example.com/oauth/callback", "response_type": "code", "scope": "passwordless", "username": "john.smith@example.com" }' ``` ```json 200 theme={null} "" ``` ```json 401 (Access Denied) theme={null} { "error": "access_denied", "error_description": "The resource owner or authorization server denied the request." } ``` ```json 401 (Invalid Redirect URI) theme={null} { "error": "invalid_redirect_uri", "error_description": "The redirect uri included is not valid." } ``` ### Request OAuth Client ID Where you want the user to be redirected `code` is the required value `passwordless` is the required value The user's email # Acquire Authorization Code (Cross-Domain) Source: https://docs.thanx.com/consumer/sso/acquire-auth-code-cross-domain POST /oauth/authorize-cross-domain Generate an OAuth authorization code for an authenticated user without sending email. This endpoint allows applications to generate OAuth authorization codes for users who are already authenticated, enabling seamless cross-domain authentication flows. Unlike the standard `/oauth/authorize` endpoint, this endpoint: * Requires an existing access token (Bearer authentication) * Does NOT send a passwordless email * Immediately returns an authorization code * Is designed for cross-domain authentication transfers ## Use Cases This endpoint is primarily designed for: * Cross-domain authentication (e.g., rewards.thanx.com → order.thanx.com) * Single sign-on flows where the user is already authenticated * Mobile app to web transitions ## Security Considerations * Codes expire in 10 minutes * Codes are single-use only * Requires valid access token for the target user * `redirect_uri` must be whitelisted for your integration ```bash theme={null} curl https://api.thanxsandbox.com/oauth/authorize-cross-domain \ -X POST \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "client_id": "f4bf04a6fc27b5fa926a7318933b76440642c25cde037d8e867b3d18d771ad86", "redirect_uri": "https://order.example.com/merchant-handle/passwordless-login", "response_type": "code", "scope": "passwordless" }' ``` ```json 200 theme={null} { "code": "def50200a8d9c3f2e1b4a7c6d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0", "expires_in": 600, "redirect_uri": "https://order.example.com/merchant-handle/passwordless-login" } ``` ```json 401 (Access Denied) theme={null} { "error": "access_denied", "error_description": "The access token is invalid or has expired." } ``` ```json 401 (Invalid Redirect URI) theme={null} { "error": "invalid_redirect_uri", "error_description": "The redirect uri included is not valid." } ``` ### Request OAuth Client ID (same as your application's OAuth credentials) Where the authorization code should be valid for redemption. Must be whitelisted. Must be `code` Must be `passwordless` ### Response The authorization code that can be exchanged for an access token Code expiration time in seconds (typically 600 = 10 minutes) Echo of the redirect URI for validation # Legal Requirements Source: https://docs.thanx.com/consumer/sso/legal-requirements The following notice with hyperlinks to the Thanx Privacy Policy and Terms of Service must be displayed in all experiences where a user signs up: *By signing up you agree to our [privacy policy](https://dashboard.thanx.com/privacy) and our [terms of service](https://dashboard.thanx.com/terms)* Note that you may style this sentence as you'd like. You may replace the default agreement links above with the corresponding brand-specific agreement links Thanx generates for your app: | Agreement Type | URL Pattern | | ---------------- | ------------------------------------------- | | Privacy Policy | `https://dashboard.thanx.com/privacy/BRAND` | | Terms of Service | `https://dashboard.thanx.com/terms/BRAND` | `BRAND` denotes your designated Thanx platform handle. # Single Sign-On (SSO) Overview Source: https://docs.thanx.com/consumer/sso/overview This section describes the process of authenticating with Thanx via Thanx SSO. Thanx SSO authenticates the user via a password-less flow using email authentication, rather than a password. This reduces the friction of a user having to manage yet another password as well as reduces the friction of transitioning an existing user-base to Thanx. Thanx follows the standard OAuth 2.0 spec, using the Authorization Code grant type. Refer to the [OAuth 2.0 Authorization Framework RFC: Section 4.1](https://www.rfc-editor.org/rfc/rfc6749#section-4.1) for additional details. ## Authentication Flows Thanx supports two OAuth authentication flows: ### Standard Passwordless Flow Here is what the standard flow would look like: 1. User navigates to the partner website and clicks an authentication button. 2. The partner website prompts the user to input an email address 3. The partner website makes a request to the `POST /oauth/authorize` endpoint described below. (Continue to #4 or #5) 4. If no account exists for the specified email address, a 401 error is thrown. A user can be created via the `POST /users` endpoint. 5. If an account exists for the specified email address, an auth email is sent to specified email. The user clicks the auth email link which redirects to the partner website at the specified `redirect_uri` with an authorization code in the params. 6. Partner website exchanges the authorization code for an access token via the `POST /oauth/token` endpoint described below. User is now authenticated with the Thanx system through the returned access token. SSO authenticates a user and issues a token — it does **not** enroll them with the merchant. A user who signs in via SSO but has no membership will get empty tier/reward responses until enrolled via [`POST /users`](/consumer/users/create-user). ### Cross-Domain Flow For users who are already authenticated on one domain and need to be transferred to another domain (e.g., rewards.thanx.com → order.thanx.com), Thanx provides a seamless cross-domain authentication flow: 1. User is already authenticated on the source domain with a valid access token. 2. Source application makes a request to the `POST /oauth/authorize-cross-domain` endpoint with the user's access token. 3. The endpoint immediately returns an authorization code (no email is sent). 4. Source application redirects the user to the target domain with the authorization code: `target-domain.com/path?code=...` 5. Target domain exchanges the authorization code for an access token via the `POST /oauth/token` endpoint. User is now authenticated on the target domain. This flow enables seamless cross-domain single sign-on without requiring users to check their email or re-authenticate. # Revoke Access Token Source: https://docs.thanx.com/consumer/sso/revoke-access-token POST /oauth/revoke Use this endpoint to revoke a user's access token. ### Parameters OAuth Client ID OAuth Client Secret OAuth Access Token ```bash theme={null} curl https://api.thanxsandbox.com/oauth/revoke \ -X POST \ -H "Content-Type: application/json" \ -d '{ "client_id": "${client_id}", "client_secret": "${client_secret}", "token": "${token}" }' ``` ```json Response Example theme={null} {} ``` # Delete Tag Source: https://docs.thanx.com/consumer/tags/delete-tag DELETE /tags/:id This endpoint deletes an attribute tag with the given ID. Please review proper request headers [here](/consumer/usage/headers). ### Parameters Tag ID ```bash Delete Tag theme={null} curl https://api.thanxsandbox.com/tags/:id \ -X GET \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" ``` ```json theme={null} {} ``` # Get Tags Source: https://docs.thanx.com/consumer/tags/get-tags GET /tags This section describes endpoints that enable a third party to fetch and update a user's tags. This endpoint describes all attribute tags for the given user. Please review proper request headers [here](/consumer/usage/headers). ### Parameters Only return tags for this merchant ### Response ```bash Get Tags theme={null} curl https://api.thanxsandbox.com/tags \ -X GET \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" ``` ```json theme={null} { "tags": [ { "id": "92b7b0dac4", "user_id": "werofsdf", "merchant_id": "weroif", "key": "allergens", "values": ["gluten", "soy", "dairy"] } ] } ``` # Update Tags Source: https://docs.thanx.com/consumer/tags/update-tags PUT /tags This endpoint updates an attribute tag for the given user. The tag associated with the key in the request will be created or updated with the values passed in. Please review proper request headers [here](/consumer/usage/headers). ### Parameters Only return tags for this merchant Tag key Array of attributes tags ### Response ```bash theme={null} curl https://api.thanxsandbox.com/tags \ -X PUT \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" -d '{ "tag": { "key": "allergens", "merchant_id": "weroifs", "values": [ "gluten", "soy", "dairy", "honey" ] } }' ``` ```json theme={null} { "tag": { "id": "werwerr", "user_id": "werofsdf", "merchant_id": "weroif", "key": "allergens", "values": ["gluten", "soy", "dairy", "honey"] } } ``` # Get Tiers Configurations Source: https://docs.thanx.com/consumer/tiers/get-configs GET /tier_configurations This section describes endpoints that enable a third party to fetch the configuration of a merchant's tiers. This endpoint describes tier configurations for the merchants accessible via the provided credentials. Please review proper request headers [here](/consumer/usage/headers). An empty `tier_configurations` array (HTTP 200) means tiers aren't returnable — not necessarily that none are configured. It is empty unless the merchant has at least one tier configured, tiers are enabled for the merchant, and (when a user token is sent) the user has an active membership at the merchant. ### Parameters Only return tier configuration for this merchant ### Response The merchant ID Describes the configuration for the bronze tier The identifer of the tier record The display name for the tier Describes the perks of the tier. Can return markdown. The hex color to use for this tier. How much the user needs to spend to be part of the tier. The image configured to render on the progress bar for tiers The url for the small version of this image The url for the large version of this image The url for the version of the image usually used by Thanx The image configured to render as the background for the tier The url for the small version of this image The url for the large version of this image The url for the version of the image usually used by Thanx The image configured to render as the icon for the tier The url for the small version of this image The url for the large version of this image The url for the version of the image usually used by Thanx Describes the configuration for the silver tier The identifer of the tier record The display name for the tier Describes the perks of the tier. Can return markdown. The hex color to use for this tier. How much the user needs to spend to be part of the tier. The image configured to render on the progress bar for tiers The url for the small version of this image The url for the large version of this image The url for the version of the image usually used by Thanx The image configured to render as the background for the tier The url for the small version of this image The url for the large version of this image The url for the version of the image usually used by Thanx The image configured to render as the icon for the tier The url for the small version of this image The url for the large version of this image The url for the version of the image usually used by Thanx Describes the configuration for the gold tier The identifer of the tier record The display name for the tier Describes the perks of the tier. Can return markdown. The hex color to use for this tier. How much the user needs to spend to be part of the tier. The image configured to render on the progress bar for tiers The url for the small version of this image The url for the large version of this image The url for the version of the image usually used by Thanx The image configured to render as the background for the tier The url for the small version of this image The url for the large version of this image The url for the version of the image usually used by Thanx The image configured to render as the icon for the tier The url for the small version of this image The url for the large version of this image The url for the version of the image usually used by Thanx The image configured to render as the progress bar for tiers The url for the small version of this image The url for the large version of this image The url for the version of the image usually used by Thanx ```bash Get Tier Configurations theme={null} curl https://api.thanxsandbox.com/tier_configurations \ -X GET \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" ``` ```json theme={null} { "tier_configurations": [ { "merchant_id": "weoru", "bronze_tier": { "id": "wyreo23", "name": "Bronze", "description": "- $10 off purchase of $25+ - complimentary birthday dessert - special event invitations", "color": "#ba7556", "spend_threshold": 0, "progress_paddle_image": { "small": "https://d1uv7brpxddy46.cloudfront.net/images/401/two_x/two_x-792ff91da8f50f9b5bfed570cef94295.png?1607038403", "default": "https://d1uv7brpxddy46.cloudfront.net/images/401/three_x/three_x-792ff91da8f50f9b5bfed570cef94295.png?1607038403", "large": "https://d1uv7brpxddy46.cloudfront.net/images/401/three_x/three_x-792ff91da8f50f9b5bfed570cef94295.png?1607038403" }, "background_image": { "small": "https://d1uv7brpxddy46.cloudfront.net/images/400/two_x/two_x-463afd8be775b5ac6909bbaabf692353.jpg?1607038403", "default": "https://d1uv7brpxddy46.cloudfront.net/images/400/three_x/three_x-463afd8be775b5ac6909bbaabf692353.jpg?1607038403", "large": "https://d1uv7brpxddy46.cloudfront.net/images/400/three_x/three_x-463afd8be775b5ac6909bbaabf692353.jpg?1607038403" }, "icon_image": { "small": "https://d1uv7brpxddy46.cloudfront.net/images/397/two_x/two_x-73db1207a1143a6f68374b119f826aa9.png?1607038181", "default": "https://d1uv7brpxddy46.cloudfront.net/images/397/three_x/three_x-73db1207a1143a6f68374b119f826aa9.png?1607038181", "large": "https://d1uv7brpxddy46.cloudfront.net/images/397/three_x/three_x-73db1207a1143a6f68374b119f826aa9.png?1607038181" } }, "silver_tier": { "id": "fh457", "name": "Silver", "description": "Everything in Bronze, plus: - early reservations to community dinners when you reach Silver Tier", "color": "#bdbec0", "spend_threshold": 1500, "progress_paddle_image": { "small": "https://d1uv7brpxddy46.cloudfront.net/images/403/two_x/two_x-432dd66aa8b2f7aededebc434fa36232.png?1607038424", "default": "https://d1uv7brpxddy46.cloudfront.net/images/403/three_x/three_x-432dd66aa8b2f7aededebc434fa36232.png?1607038424", "large": "https://d1uv7brpxddy46.cloudfront.net/images/403/three_x/three_x-432dd66aa8b2f7aededebc434fa36232.png?1607038424" }, "background_image": { "small": "https://d1uv7brpxddy46.cloudfront.net/images/402/two_x/two_x-1fbd60df2de3891d3f41d915bd2afef4.jpg?1607038423", "default": "https://d1uv7brpxddy46.cloudfront.net/images/402/three_x/three_x-1fbd60df2de3891d3f41d915bd2afef4.jpg?1607038423", "large": "https://d1uv7brpxddy46.cloudfront.net/images/402/three_x/three_x-1fbd60df2de3891d3f41d915bd2afef4.jpg?1607038423" }, "icon_image": { "small": "https://d1uv7brpxddy46.cloudfront.net/images/398/two_x/two_x-f7a86c1434d71199a717d2b0caa256ac.png?1607038197", "default": "https://d1uv7brpxddy46.cloudfront.net/images/398/three_x/three_x-f7a86c1434d71199a717d2b0caa256ac.png?1607038197", "large": "https://d1uv7brpxddy46.cloudfront.net/images/398/three_x/three_x-f7a86c1434d71199a717d2b0caa256ac.png?1607038197" } }, "gold_tier": { "id": "ert235", "name": "Gold", "description": "Everything in Silver, plus: - complimentary seasonal pizza per year when you reach Gold Tier", "color": "#c8b55e", "spend_threshold": 3000, "progress_paddle_image": { "small": "https://d1uv7brpxddy46.cloudfront.net/images/405/two_x/two_x-33c3dc14517c5d08b2c0869ef52c652b.png?1607038443", "default": "https://d1uv7brpxddy46.cloudfront.net/images/405/three_x/three_x-33c3dc14517c5d08b2c0869ef52c652b.png?1607038443", "large": "https://d1uv7brpxddy46.cloudfront.net/images/405/three_x/three_x-33c3dc14517c5d08b2c0869ef52c652b.png?1607038443" }, "background_image": { "small": "https://d1uv7brpxddy46.cloudfront.net/images/404/two_x/two_x-3fbfb464595f7e136cfccebf36f2b1d8.jpg?1607038443", "default": "https://d1uv7brpxddy46.cloudfront.net/images/404/three_x/three_x-3fbfb464595f7e136cfccebf36f2b1d8.jpg?1607038443", "large": "https://d1uv7brpxddy46.cloudfront.net/images/404/three_x/three_x-3fbfb464595f7e136cfccebf36f2b1d8.jpg?1607038443" }, "icon_image": { "small": "https://d1uv7brpxddy46.cloudfront.net/images/399/two_x/two_x-a44437b769db59fb777c922088ec840d.png?1607038208", "default": "https://d1uv7brpxddy46.cloudfront.net/images/399/three_x/three_x-a44437b769db59fb777c922088ec840d.png?1607038208", "large": "https://d1uv7brpxddy46.cloudfront.net/images/399/three_x/three_x-a44437b769db59fb777c922088ec840d.png?1607038208" } }, "progress_bar_image": { "small": "https://d1uv7brpxddy46.cloudfront.net/images/423/two_x/two_x-ecbb385cc1850f090c6305fcc427293b.png?1608147464", "default": "https://d1uv7brpxddy46.cloudfront.net/images/423/three_x/three_x-ecbb385cc1850f090c6305fcc427293b.png?1608147464", "large": "https://d1uv7brpxddy46.cloudfront.net/images/423/three_x/three_x-ecbb385cc1850f090c6305fcc427293b.png?1608147464" } } ] } ``` # Get Tier Statuses Source: https://docs.thanx.com/consumer/tiers/get-statuses GET /tier_statuses This endpoint describes the user's current tier statuses. Please review proper request headers [here](/consumer/usage/headers). ### Parameters Only return tier configuration for this merchant ### Response The ID of the tier status record The user ID The merchant ID Current tier state (`bronze`, `silver`, `gold`) Description of what the user needs to do in order to earn the next tier Amount spent so far Current tier status expiration in ISO8601-format Name of current tier Name of next tier. This will be blank if the user has `gold` status ```bash theme={null} curl https://api.thanxsandbox.com/tier_statuses \ -X GET \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" ``` ```json theme={null} { "tier_statuses": [ { "id": "weourif", "user_id": "woeru", "merchant_id": "werouwer", "level": "bronze", "action_text": "Spend $100 before the end of the year to earn Silver.", "progress": 50, "expires_at": "2021-01-01T20:00:00Z", "current_tier_name": "Bronze", "next_tier_name": "Silver" } ] } ``` # Grant Tier Status Source: https://docs.thanx.com/consumer/tiers/grant-status PATCH /tier_statuses/:id Grant Tier Status Please review proper request headers [here](/consumer/usage/headers). This endpoint is only available in SANDBOX ### Parameters The desired tier (`bronze`, `silver`, `gold`) The tier status id ### Response The ID of the tier status record The user ID The merchant ID Current tier state (`bronze`, `silver`, `gold`) Description of what the user needs to do in order to earn the next tier Amount spent so far Current tier status expiration in ISO8601-format Name of current tier Name of next tier. This will be blank if the user has `gold` status ```json theme={null} { "tier_statuses": [ { "id": "weourif", "user_id": "woeru", "merchant_id": "werouwer", "level": "bronze", "action_text": "Spend $100 before the end of the year to earn Silver.", "progress": 50, "expires_at": "2021-01-01T20:00:00Z", "current_tier_name": "Bronze", "next_tier_name": "Silver" } ] } ``` ```bash theme={null} curl https://api.thanxsandbox.com/tier_statuses/:id \ -X PATCH \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "X-ClientId: ${client_id}" -d '{ "tier_status": { "level": "silver" } }' ``` ```json theme={null} { "tier_status": { "id": "weourif", "user_id": "woeru", "merchant_id": "werouwer", "level": "bronze", "action_text": "Spend $100 before the end of the year to earn Silver.", "progress": 50, "expires_at": "2021-01-01T20:00:00Z", "current_tier_name": "Bronze", "next_tier_name": "Silver" } } ``` # Certification Source: https://docs.thanx.com/consumer/usage/certification A Consumer API integration must be certified before production credentials are made available. ## Process To initiate the certification process, a build (app or web) should be submitted to the Thanx Developer Support team ([developer.support@thanx.com](mailto:developer.support@thanx.com)). Once a build is submitted for certification, feedback will be delivered within **ten business days**. If no critical feedback is provided, the build will be certified and production API credentials will be issued. If critical feedback is provided, integration partners should address the feedback and resubmit a new certification candidate build, after which the **10 business day** certification review cycle will begin again. ## Submission Depending on the experience being developed, the following submission formats are supported: * **Web** * URL of web experience * **iOS** * Firebase App Distribution link * TestFlight build. For the specific emails to whitelist, please request them from [developer.support@thanx.com](mailto:developer.support@thanx.com). * **Android** * Firebase App Distribution link * APK file All the above experiences must be pointing the Thanx Sandbox APIs. A build should be submitted for each experience (web, iOS, Android). ## Legal Requirements * User must agree to the Thanx Privacy Policy and Terms of Service when creating a loyalty account. The language should read > By signing up you agree to our > **[privacy policy](https://dashboard.thanx.com/privacy)** and our > **[terms of service](https://dashboard.thanx.com/terms)** * User must be able to navigate to the Thanx Privacy Policy and Terms of service from both App and Web experiences when logged in (may also be mentioned in another document that’s readily available in the app, e.g. the brand's Terms) * Any screen where the user is enrolling their credit card for loyalty tracking must have the correct legal text (see [enrollment best practices](/consumer/best-practices/enrollment#requirements-for-implementation)) * There must be 2 buttons * One button must include “Register card” * The other allow to skip enrolling the card * Legal content should be visible at all times * Links must be visible and clickable ## General * API requests must include all [required headers](/consumer/usage/headers) * API requests must not be unnecessarily duplicated * API error messages should be displayed to the user * API requests should only be issued on a reasonable frequency and in response to end-user interactions (e.g. Don't rapidly poll API for changes) ## Account Creation & Authentication * Thanx must be the only authentication provider available for users * Thanx tools do not work when other authentication mechanisms are in place (eg. Google SSO, email/password) * User can create account via the [create user endpoint](/consumer/users/create-user) * User can authenticate via passwordless email following [Thanx SSO](/consumer/sso/overview) guidelines * Users should be required to provide a name to complete registration * A new user should be prompted to sign up * An existing user should be sent a login email (experience should display a message about an email being sent) ## Account Management * User can [view](/consumer/users/get-user) and [update](/consumer/users/update-user) account details (email, first name, last name, etc) * User can submit a request for [account closure](/consumer/users/delete-user) * User can [view](/consumer/communication-settings/get) and [update](/consumer/communication-settings/update) communication settings ## Card Management * [API-based enrollment](/consumer/cards/create-card) * User can enroll a credit card * User can [archive a credit card](/consumer/cards/delete-card) * Experience should support displaying a list of cards * Experience should allow a user to link a card (Visa, Mastercard, American Express) * Experience should allow a user to delete a card ## Purchases * User can view [recent purchases](/consumer/purchases/get-purchases) ## Reward Redemption * User can [view available rewards](/consumer/rewards/get-rewards) * User can [activate](/consumer/rewards/activate-reward) and [finalize](/consumer/rewards/finalize-reward) a reward * Reward type support * Only in-use reward types need to be supported * `manual` - redemption conducted manually (e.g. in-store, showing server/cashier) * `automatic` - cash-back pushed directly to a user's credit card once a qualifying purchase is made * Supported coupon code formats: * Only in-use coupon code types need to be supported * `raw` * `qrcode` * `barcode39` * `barcode39extended` * `barcode93` * `barcode128` * `barcode_upc_a` * `barcode_ean_8` * `barcode_ean_13` * `barcode25interleaved` * Reward activation request should be made only on user action * Manual redemption rewards should display a countdown timer When testing fraud-protected reward types (intro, invite, birthday, winback, newsletter), use a **unique, real card per test account**. Shared test cards (e.g. Visa `4111…`) match on card fingerprint across accounts and merchants, which flags the reward as fraudulent and makes it disappear on activation. General API testing with shared test cards is fine — only fraud-protected reward activation hits this. ## Expression of Loyalty * The following expressions of loyalty are optional and the usage of these can be determined by an integration partner's creative/marketing teams. * That said, a requirement of the card networks is that a user must be able to receive value in exchange for enrolling their card and authorizing Thanx for automated data capture. Support for points, tiers, or both is required to satisfy this requirement. * Points * User can see [their current points balance](/consumer/points/get-points-balance) * User can view [info of how they earn points](/consumer/points/get-experiences) * User can view [configured rewards in the marketplace (points products)](/consumer/points/get-products) * User can [exchange points for points products](/consumer/points/exchange-product) * Tiers * User can see [tier info](/consumer/tiers/get-configs), including thresholds and a description of tier perks * User can [view their current tier status](/consumer/tiers/get-statuses) ## Push Notifications (Mobile Only) * For custom app builds, push notification certificates (Apple APNS and Google FCM) must be provided to Thanx developer support * APNS push notification certificate should be provided to Thanx * FCM server key and server ID should be provided to Thanx * User can [register for push notifications](/consumer/push/create-push-registration) and the app should make a call to register the push notification token with Thanx ## Feedback (Optional) * This functionality is optional and will only be validated if implemented * User can [get feedback prompts](/consumer/feedbacks/get-feedbacks) (created post purchase creation) * User can [submit feedback](/consumer/feedbacks/update-feedback) (rating and review) * Experience should submit numerical rating and optional text feedback * Experience should present the option to leave text feedback for each purchase * Rating should be on a 10 point scale ## Receipt Submission (Optional) * This functionality is optional and will only be validated if implemented * User can view [pending receipts](/consumer/receipts/get-receipts) * User can [upload](/consumer/receipts/get-upload-url) and [submit](/consumer/receipts/create-receipt) a receipt * Experience should request all required information from the user * Experience should allow the user to choose a card to associate the receipt with, if they have any ## Product Guide ## Postman API Collection Here you will find the **Custom App - Web Experience API Postman Collection** to import directly within your API testing tool. This collection is already completed and includes sample values for the credentials. Please replace them with the ones provided by your Thanx representative in order to achieve successful API calls. You can find more information about credentials and headers on the [following page](/consumer/usage/headers), or check the documentation for the specific API endpoint you want to call to ensure that all credentials are placed correctly. Download Postman Collection # Errors Source: https://docs.thanx.com/consumer/usage/errors Thanx uses standard HTTP error codes to communicate the success / failure of a request. An HTTP 400 Bad Request will always be accompanied by an object containing two properties: code (see below) and message. The code will remain static though the associated message may change at any time. Thanx can expand this list at any time. | Code | Sample Message | | ------------------------- | ------------------------------------------------------- | | `BAD_REQUEST` | "An error occurred." | | `FORBIDDEN` | "You do not have access to this resource." | | `GENERIC_ERROR ` | "Something went wrong" | | `RESOURCE_NOT_FOUND` | "The resource you requested was not found." | | `AUTHENTICATION_GENERIC` | "There was an error authenticating you." | | `USER_EMAIL_INVALID` | "The email entered is invalid." | | `USER_PHONE_INVALID` | "The phone entered is invalid." | | `USER_NAME_REQUIRED` | "First and last name are required fields." | | `REWARD_ALREADY_USED` | "This reward has already been used." | | `REWARD_EXPIRED` | "This reward is no longer valid." | | `REWARD_INAPPLICABLE` | "Required item not present." | | `REWARD_FRAUDULENT` | "You appear to have already used one of these rewards." | | `CARD_GENERIC` | "Unable to register this card due to an issue at Visa." | | `CARD_INVALID` | "This type of card is not accepted." | | `POINTS_EXCHANGE_FAILURE` | "Points exchange has failed." | ```bash Response (401 Unauthorized) theme={null} { "error": { "code": "AUTHENTICATION_GENERIC", "message": "There was an error authenticating you." } } ``` ```bash Response (404 NOT FOUND) theme={null} { "error": { "code": "RESOURCE_NOT_FOUND", "message": "The resource you requested was not found." } } ``` ```bash Response (400 Bad Request) theme={null} { "error": { "code": "USER_EMAIL_INVALID", "message": "The email entered is invalid." } } ``` # Headers Source: https://docs.thanx.com/consumer/usage/headers This section describes the headers expected by the Thanx API. ```bash theme={null} STANDARD_HEADERS = '-H "Content-Type: application/json" ' \ '-H "Accept-Version: v4.0" '\ '-H "Accept: application/json" '\ '-H "X-ClientId: 293487fhs98345yswoeir245789" '\ AUTH_HEADERS = '-H "Content-Type: application/json" ' \ '-H "Accept-Version: v4.0" '\ '-H "Accept: application/json" '\ '-H "Authorization: Bearer 945148251b603ae34561d90acfe4050e67494d6d1e65d4d3d52798407f03c0bd" '\ '-H "X-ClientId: 293487fhs98345yswoeir245789" '\ ``` All Thanx Loyalty API endpoints are protected and must be authorized via end user access tokens. These access tokens can be retrieved through an integration with Thanx SSO. The format of the header should be: `Bearer access_token`. Some endpoints don't require a user to be signed in; these are called out in their separate sections. Example: `Bearer d6d6533c5ab9b528526f3e48a51e90b62` The only accepted value is `application/json` or empty if no body The Accept-Version header specifies which version of the Thanx API that should be used. The current version is v4.0. This header is required for every request. Thanx will notify you when a new API version is available. Example: `v4.0` The only accepted value is `application/json` Thanx will provide you with this value. Example: `f050d74b5c2b12ae17c85bd510addd7ba2` # Legal Source: https://docs.thanx.com/consumer/usage/legal ## General requirements User must be able to navigate to the Thanx Privacy Policy and Terms of Service from the App and the Web Ordering experience after initial sign up has completed when they are using the app on an ongoing basis. Linking to the Thanx Terms of Service and Privacy Policy from another like document that is readily available in the app is sufficient. ## User creation The following notice with hyperlinks to the Thanx Privacy Policy and Terms of Service must be displayed in all experiences where a user signs up: By signing up you agree to our [privacy policy](https://dashboard.thanx.com/privacy) and our [terms of service](https://dashboard.thanx.com/terms) Note that you may style this sentence as you'd like. You may replace the default agreement links above with the corresponding brand-specific agreement links Thanx generates for your app: | Agreement Type | URL Pattern | | ---------------- | ------------------------------------------- | | Privacy Policy | `https://dashboard.thanx.com/privacy/BRAND` | | Terms of Service | `https://dashboard.thanx.com/terms/BRAND` | `BRAND` denotes your designated Thanx platform handle. ## Card linkage Any screen that register credit cards with the Thanx platform must be explicitly approved by Thanx team for design and content, as subsequent approvals with the credit card networks (Visa, Mastercard, American Express) are required. # Patterns Source: https://docs.thanx.com/consumer/usage/patterns This section calls out some patterns in this API. * Every ID returned by the API is an alphanumeric, lowercase string. * Every endpoint's payload contains a top-level key (aside from SSO). * A bearer token is required for a user to access their own resources. If an endpoint provides filtering by user\_id and the bearer token is provided, the user\_id filter is ignored. # Get Check In Code Source: https://docs.thanx.com/consumer/users/check-in-code GET /users/:id/check_in_code This endpoint will return the check-in code for a user. The check-in code can be matched to a location. The check-in code can use specific formats for different merchants/locations. If no location or merchant is provided, the check-in code provided will be automatically matched to the merchant account to which the user belongs to. Please review proper request headers [here](/consumer/usage/headers). ### Parameters Retrieve a check-in code for this location ### Response The check-in code ```bash Get Check-in Code theme={null} curl https://api.thanxsandbox.com/users/:id/check_in_code \ -X GET \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" ``` ```json Response Example theme={null} { "check_in_code": "1234s6", } ``` ```json Response Example theme={null} { "check_in_code": "LSTR|1234s6||LEND" } ``` # Create User Source: https://docs.thanx.com/consumer/users/create-user POST /users This endpoint creates a user, but it also facilitates signing an existing platform user up with the client brand in scenarios where the SSO flow wouldn't be appropriate (i.e., the user is not signing in to an authenticated experience). If a user with the specified email already exists, it signs the user up with the client brand before returning a 400 level error. This endpoint also returns authorization information for a successfully created user, including an access\_token that can be used to access other API endpoints. Experiences utilizing this endpoint must adhere to the [legal requirements for user creation](/consumer/usage/legal). Please review proper request headers [here](/consumer/usage/headers). ### Body The user's email The user's phone number in [E.164 format](https://www.twilio.com/docs/glossary/what-e164), with the country code prefix (e.g. `+14157582345`). Phones submitted without the country code prefix are stored as-is — this endpoint does not normalize them — and will fail later phone-based lookups (such as Partner Auth Token) that depend on E.164 parsing. The user's first name The user's last name The user's birthday information The user's birth year The user's birth month The user's birth day The user's zip code The Program ID to associate with this user signup. This is used to track which signup program the user enrolled through. The program must be active and belong to the merchant. If the program is invalid, it will be silently ignored without preventing user creation. Only applied to new users; existing users will not have their signup\_program\_id updated. This endpoint permits minimal requests that only contain an `email` parameter for the purposes of signing up an existing platform user with the client brand. If the email belongs to an existing user, it signs the user up with the brand before returning a 400 level error. ```bash Create a new user theme={null} curl https://api.thanxsandbox.com/users/ \ -X POST \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "X-ClientId: ${client_id}" \ -d '{ "user": { "email": "jane.smith@example.com", "phone": "+14158672345", "first_name": "Jane", "last_name": "Smith", "birth_date": { "month": 8, "day": 14 }, "zip_code": "12345" } }' ``` ```bash Create user with signup program theme={null} curl https://api.thanxsandbox.com/users/ \ -X POST \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "X-ClientId: ${client_id}" \ -d '{ "user": { "email": "jane.smith@example.com", "phone": "+14158672345", "first_name": "Jane", "last_name": "Smith", "birth_date": { "month": 8, "day": 14 }, "zip_code": "12345", "signup_program_id": "awe833ke24" } }' ``` ```bash User does not existing theme={null} curl https://api.thanxsandbox.com/users/ \ -X POST \ $STANDARD_HEADERS \ -d '{ "user": { "email": "jane.smith@example.com" } }' ``` ```bash Without SSO theme={null} curl https://api.thanxsandbox.com/users/ \ -X POST \ $STANDARD_HEADERS \ -d '{ "user": { "email": "jane.smith@example.com" } }' ``` ### Response The newly created user The authorization type of the created user The type of token, usually "Bearer" This will be 'passwordless' The number of seconds since the epoch The user's access token, for use in accessing other API endpoints If needed, a refresh token to get another access token ```json 201 theme={null} { "user": { "id": "wroeiu2304hfwf", "email": "jane.smith@example.com", "phone": "+14158672345", "first_name": "Jane", "last_name": "Smith", "birth_date": { "year": 1987, "month": 8, "day": 14 }, "zip_code": "12345" }, "authorization": { "token_type": "Bearer", "scope": "passwordless", "created_at": 1577836800, "access_token": "945148251b603ae34561d90acfe4050e67494d6d1e65d4d3d52798407f03c0bd", "refresh_token": "c74334301a7c74d21b714c905fd3047177dab56de6a86899e6f6b7f71bab7d55" } } ``` ```json 400 theme={null} { "error": { "code": "USER_NAME_REQUIRED", "message": "First and last name are required fields." } } ``` ```json 400 theme={null} { "error": { "code": "BAD_REQUEST", "message": "User account exists" } } ``` # Delete User Source: https://docs.thanx.com/consumer/users/delete-user DELETE /users/me Submits a request for user account closure This endpoint submits a request for account closure for the currently authenticated user. The Thanx support team will review the request and interface directly with that user to complete account closure. This endpoint optionally accepts additional user input, though none is required. For non-production environments, the API request will succeed but no support ticket will be filed. For custom app builds, this endpoint can be used in conjunction with a custom form to satisfy [Apple](https://developer.apple.com/support/offering-account-deletion-in-your-app/) and [Google](https://support.google.com/googleplay/android-developer/answer/13327111?hl=en)'s requirements for account deletion. Please review proper request headers [here](/consumer/usage/headers). ### Parameters Optionally specified message that can be used to specify the user's reason for submitting a deletion request. ### Response Message describing the status of the deletion request ```bash Submit user deletion request theme={null} curl https://api.thanxsandbox.com/users/me \ -X DELETE \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" -d '{"message": "Optional message"}' ``` ```json 202 theme={null} { "message": "User deletion request has been submitted" } ``` ```json 503 theme={null} { "message": "Failed to create deletion request" } ``` # Get User Source: https://docs.thanx.com/consumer/users/get-user GET /users/me This endpoint will return information for the currently logged in user. The user's phone number is not gathered by Thanx with the permission to use it for marketing. Please review proper request headers [here](/consumer/usage/headers). ### Response ```bash Get User theme={null} curl https://api.thanxsandbox.com/users/me \ -X GET \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" ``` ```json Response Example theme={null} { "user": { "id": "wroeiu2304hfwf", "email": "john.smith@example.com", "phone": "+14158672345", "first_name": "Jane", "last_name": "Smith", "birth_date": { "year": 1987, "month": 8, "day": 14 }, "zip_code": "12345" } } ``` # Update User Source: https://docs.thanx.com/consumer/users/update-user PATCH /users/:id This endpoint updates the specified user's information. The user's phone number is not gathered by Thanx with the permission to use it for marketing. Please review proper request headers [here](/consumer/usage/headers). ```bash theme={null} curl https://api.thanxsandbox.com/users/:id \ -X PATCH \ -H "Content-Type: application/json" \ -H "Accept-Version: v4.0" \ -H "Accept: application/json" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" \ -d '{ "user": { "email": "", "first_name": "", "last_name": "" } }' ``` ### Parameters The user's id ### Body The user's email The user's phone number in [E.164 format](https://www.twilio.com/docs/glossary/what-e164), with the country code prefix (e.g. `+14157582345`). Phones submitted without the country code prefix are stored as-is — this endpoint does not normalize them — and will fail later phone-based lookups (such as Partner Auth Token) that depend on E.164 parsing. The user's first name The user's last name The user's birthday information The user's birth year The user's birth month The user's birth day The user's zip code ### Response ```json Response Example theme={null} { "user": { "id": "wroeiu2304hfwf", "email": "john.smith@example.com", "phone": "+14158672345", "first_name": "Jane", "last_name": "Smith", "birth_date": { "year": 1987, "month": 8, "day": 14 }, "zip_code": "12345" } } ``` # Changelog Source: https://docs.thanx.com/data/changelog Any data export schema changes will be captured in the below changelog. ## Schema management policy **All consumers of Thanx SFTP exports are required to build their integrations to comply with the rules below.** New attributes will be added over time as the platform evolves, and your downstream pipelines must tolerate them without manual intervention. If your integration breaks when a new column is added, **update your pipeline** to handle these additive schema changes — they are expected and will continue. * **Attribute addition.** New attributes will be added as new columns to the **right side** of each CSV export for SFTP exports. Consumers must parse CSVs by header name, not by column position, and must ignore unknown columns rather than failing. * **Attribute removal.** Attributes are not removed from the schema under normal operations, to prevent breaking existing integrations. If a column must be retired (e.g., for regulatory or security-driven reasons), the column remains present in the schema but will be empty. * **Attribute update.** Attribute data types will not be adjusted. Changes to any calculation will be announced in the changelog below and applied to all exports on the listed date. Thanx Connex automatically handles schema changes in the downstream source. The following attributes will be added: * [memberships](/data/models/memberships) * `alternate_pos_id` - An alternate user identifier sent to certain in-store POS systems when loyalty is applied at the register. Currently only used by the Toast POS integration, where it matches the `APPLIED_LOYALTY_ID` field on Toast POS reports. The following attributes will be added: * [rewards](/data/models/rewards) * `redemption_pos_order_id` - POS ID of the order with which this reward was redeemed. Set for merchants with in-store POS integrations enabled for rewards that were redeemed in-store. * `redemption_pos_provider` - POS provider for the integrated in-store redemption. * [purchases](/data/models/purchases) * `pos_id` - POS ID of the order. Set for brands using POS check-in loyalty when a purchase is created via an in-store check-in. * `pos_provider` - POS provider of the order. Only present when a purchase is created via an in-store check-in for brands using POS check-in loyalty. Improved accuracy of: * [rewards](/data/models/rewards) * `discount` - more accurate discount amounts for integrated redemption. # Athena Source: https://docs.thanx.com/data/connex/athena Configuring your AWS Athena destination. ## Prerequisites * [ ] By default, Athena authentication uses role-based access. You will need the trust policy prepopulated with the data-syncing service's identifier to grant access. It should look similar to the following JSON object with a proper service account identifier: ```json theme={null} { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "sts:AssumeRoleWithWebIdentity" ], "Principal": { "Federated": "accounts.google.com" }, "Condition": { "StringEquals": { "accounts.google.com:sub": "" } } } ] } ``` ## Step 1: Create a destination bucket, service policy, and role ### Create Athena target bucket Follow these steps to create a bucket to be used for staging data before transferring to a destination. 1. Navigate to the **S3** service page. 2. Click **Create bucket**. 3. Enter a **Bucket name**, select an **AWS Region**, and modify any of the default settings as desired. Note: **Object Ownership** can be set to "**ACLs disabled**" and **Block Public Access settings for this bucket** can be set to "**Block all public access**" as recommended by AWS. Make note of the Bucket name and AWS Region. 4. Click **Create bucket**. ### Create Athena access policy 1. Navigate to the **IAM** service page, click on the **Policies** navigation tab, and click **Create policy**. 2. Click the JSON tab, and paste the following policy, being sure to replace `ACCOUNT_ID`, `WORKGROUP`, `BUCKET_NAME` and `SCHEMA` with the your account information. * `WORKGROUP` should be `primary` unless otherwise specified during connection configuration. * `BUCKET` should refer to the bucket created in the previous step. * `SCHEMA` used below does not need to be created ahead of time. If it does not exist, it will be created automatically before transferring data. ```json JSON policy theme={null} { "Version": "2012-10-17", "Statement": [ { "Sid": "AllowAthenaAccess", "Effect": "Allow", "Action": [ "athena:GetQueryResults", "athena:StartQueryExecution", "athena:StartSession", "athena:GetDatabase", "athena:GetDataCatalog", "athena:GetWorkGroup", "athena:GetTableMetadata", "athena:GetQueryExecution" ], "Resource": [ "arn:aws:athena:*:ACCOUNT_ID:workgroup/WORKGROUP" ] }, { "Sid": "AllowGlueAccessToDestinationDatabaseAndTables", "Effect": "Allow", "Action": [ "glue:GetDatabases", "glue:GetDatabase", "glue:GetTables", "glue:GetTable", "glue:GetPartitions", "glue:CreateTable", "glue:CreateDatabase", "glue:UpdateTable", "glue:DeleteTable" ], "Resource": [ "arn:aws:glue:*:ACCOUNT_ID:catalog", "arn:aws:glue:*:ACCOUNT_ID:database/SCHEMA", "arn:aws:glue:*:ACCOUNT_ID:database/default", "arn:aws:glue:*:ACCOUNT_ID:table/SCHEMA/*" ] }, { "Sid": "AllowS3AccessToBucket", "Effect": "Allow", "Action": [ "s3:PutObject", "s3:ListBucket", "s3:GetBucketLocation", "s3:GetObject", "s3:DeleteObject" ], "Resource": [ "arn:aws:s3:::BUCKET_NAME", "arn:aws:s3:::BUCKET_NAME/*" ] } ] } ``` **Athena vs. S3 permissions** Because Athena uses S3 as the underlying storage layer, the Resource access requested in the policy is scoped down via resource-specific permissions in the S3 actions. **Schema vs. Database** During destination onboarding, you will be asked to provide both a "schema" and a "database". Though those are mostly synonymous in Athena, they are used for two different purposes here: * `schema` should be the name of the folder in S3 under which the final data will be written. * `database` should be the name of the folder in S3 in which the Athena query results are written (i.e., the automatically generated `athena_output/` data). 3. Click through to the **Review** step, choose a **name** for the policy, for example, `transfer-service-policy` (this will be referenced in the next step), add a description, and click **Create policy**. ### Create role 1. Navigate to the **IAM** service page. 2. Navigate to the **Roles** navigation tab, and click **Create role**. 3. Select **Custom trust policy** and paste the provided trust policy (from the prerequisite) to allow AssumeRole access to this role. Click **Next**. 4. Add the permissions policy created above, and click **Next**. 5. Enter a **Role name**, for example, `transfer-role`, and click **Create role**. 6. Once successfully created, search for the created role in the Roles list, click the role name, and make a note of the **ARN** value. **Alternative authentication method: AWS User with HMAC Access Key ID & Secret Access Key** Role based authentication is the preferred authentication mode for Athena based on AWS recommendations, however, HMAC Access Key ID & Secret Access Key is an alternative authentication method that can be used if preferred. 1. Navigate to the **IAM** service page. 2. Navigate to the **Users** navigation tab, and click **Add users**. 3. Enter a **User name** for the service, for example, `transfer-service`, click **Next**. Under **Select AWS access type**, select the **Access key - Programatic access** option. Click **Next: Permissions**. 4. Click the **Attach existing policies directly** option, and search for the name of the policy created in the previous step. Select the policy, and click **Next: Tags**. 5. Click **Next: Review** and click **Create user**. 6. In the **Success** screen, record the **Access key ID** and the **Secret access key**. ## Step 2: Add your destination 1. Securely share your **database**, **schema**, **workgroup**, **bucket name**, **bucket region**, and **IAM Role ARN** with us to complete the connection. # AWS RDS & Aurora MySQL Source: https://docs.thanx.com/data/connex/aws-mysql ## Prerequisites * [ ] If your MySQL database is protected by security groups or other firewall settings, you will need to have the data-syncing service's static IP available to complete **Step 1**. ## Step 1: Allow access Allow write access to a portion of your Aurora MySQL database. ### Configure the Security Group 1. In your **Amazon RDS** > **Databases** list, click the MySQL instance you want to send data to. 2. In the database page, in the **Connectivity & security** tab, make note of the **Endpoint** and the **Port** number. Note that you may need to select the "**Writer instance**" in the DB identifier list to reveal the endpoint. ![](https://storage.googleapis.com/prequel_docs/images/aws-mysql-endpoint-port.png "mysql endpoint port.png") 3. To ensure that the destination is accessible from outside your VPC, click "**Modify**" in the top right, and in the "**Connectivity**" section, within the **Additional configuration** dropdown, confirm the **Publicly accessible** setting is set to **Yes** . Note that it is still only accessible through whitelisted IPs at this point. ![](https://storage.googleapis.com/prequel_docs/images/aws-mysql-publicly-accessible.png "mysql publicly accessible.png") 4. Returning to the database page, within the "**Writer instance**" details, click one of the VPC security groups (usually `default`). Note: VPC groups are permissive (vs. restrictive) and for instances with multiple VPC security groups, only one needs to be configured with the new inbound rule. ![](https://storage.googleapis.com/prequel_docs/images/aws-mysql-default-security-group.png "vsg.png") 5. In the **Security Groups** section, select the **Inbound rules** tab. 6. Click **Edit inbound rules** and then click **Add rule**. 7. Edit the newly created rule of type **Custom TCP** with the **Port range** noted in the first step (usually `5432`) and a `Custom` **Source** value that includes all of the service IPs. Note: you will need to add `/32` to the end of each IP (CIDR notation). 8. Click **Save rules**. ![](https://storage.googleapis.com/prequel_docs/images/postgres-add-rule.png "add rule.png") ### Configure network ACLs (access control list) For database instances in a VCP 1. In your RDS dashboard, select the MySQL instance. 2. Click the link to the instance's VPC. 3. Click the **VPC ID**. ![](https://storage.googleapis.com/prequel_docs/images/postgres-vpc-id.png "vpc id.png") 4. In the **Details** section, click on the link under **Main network ACL**. ![](https://storage.googleapis.com/prequel_docs/images/postgres-main-network-acl-id.png "network acl id.png") 5. Click on the network ACL ID. ![](https://storage.googleapis.com/prequel_docs/images/postgres-network-acl-id.png "network acl id.png") #### Edit the inbound rules 6. Click on the **Inbound rules** tab, and check if there is an existing rule with a Source of `0.0.0.0/0` set to `Allow`. (This is a default rule created by AWS. If this rule already exists, skip to **Edit outbound rules**.) ![](https://storage.googleapis.com/prequel_docs/images/postgres-inbound-rules.png "inbound rules.png") 7. Create the inbound rule (if it doesn't exist). Click **Edit inbound rules** and either **Add new rule** or edit an existing rule to allow access to the **port number** of your database instance (usually `5432`) from the Prequel static IP. Click **Save changes**. #### Edit the outbound rules 8. In the ACL menu, select the **Outbound rules** tab, and check if there is an existing rule with a Destination of `0.0.0.0/0` set to `Allow`. (This is a default rule created by AWS. If this rule already exists, skip to the next step.) ![](https://storage.googleapis.com/prequel_docs/images/postgres-outbound-rules.png "outbound rules.png") 9. Create the outbound rule (if it doesn't exist). Click **Edit outbound rules** and edit the rules to allow outbound traffic to ports 1024-65535 for **Destination** `0.0.0.0/0`. ## Step 2: Create writer user Create a database user to perform the writing of the source data. 1. Open a connection to your Aurora MySQL database. 2. Create a user for the data transfer by executing the following SQL command. ```sql theme={null} CREATE USER @'%' IDENTIFIED BY ''; ``` 3. Grant user required privileges on the database. ```sql theme={null} GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, CREATE TEMPORARY TABLES, CREATE VIEW ON *.* TO @'%'; ``` **If the `schema/database` already exists:** By default, the service creates a new schema (*in MySQL, `schema` is synonymous with `database`*). If you prefer to create the schema yourself before connecting the destination, you must ensure that the writer user has the proper permissions on the schema, using `GRANT ALL PRIVILEGES ON .* TO @'%';` ## Step 3: Add your destination Securely share your **host name**, **database name**, **port**, your chosen **schema name**, **username**, and **password** with us to complete the connection. # AWS RDS & Aurora Postgres Source: https://docs.thanx.com/data/connex/aws-postgres Configuring your AWS Postgres (RDS or Aurora) destination. ## Prerequisites * [ ] If your Postgres database is protected by security groups or other firewall settings, you will need to have the data-syncing service's static IP available to complete **Step 1**. ## Step 1: Allow access Allow write access to a portion of your RDS or Aurora PostgreSQL database. ### Configure the Security Group 1. In your **Amazon RDS** > **Databases** list, click the PostgreSQL instance you want to send data to. 2. In the database page, in the **Connectivity & security** tab, make note of the **Endpoint** and the **Port** number. ![](https://storage.googleapis.com/prequel_docs/images/postgres-endpoint.png "endpoint + port.png") 3. In the **Security** section, ensure that set the **Publicly accessible** setting is set to **Yes** to ensure that the destination is accessible from outside your VPC. Note that it is still only accessible through whitelisted IPs at this point. ![](https://storage.googleapis.com/prequel_docs/images/postgres-publicly-accessible.png "publicly accessible.png") 4. Click one of the VPC security groups (usually `default`). Note: VPC groups are permissive (vs. restrictive) and for instances with multiple VPC security groups, only one needs to be configured with the new inbound rule. ![](https://storage.googleapis.com/prequel_docs/images/postgres-vpc-security-groups.png "vsg.png") 5. In the **Security Groups** section, select the **Inbound rules** tab. 6. Click **Edit inbound rules** and then click **Add rule**. 7. Edit the newly created rule of type **Custom TCP** with the **Port range** noted in the first step (usually `5432`) and a `Custom` **Source** value that includes all of the service IPs. Note: you will need to add `/32` to the end of each IP (CIDR notation). 8. Click **Save rules**. ![](https://storage.googleapis.com/prequel_docs/images/postgres-add-rule.png "add rule.png") ### Configure network ACLs (access control list) For database instances in a VCP 1. In your RDS dashboard, select the PostgreSQL instance. 2. Click the link to the instance's VPC. 3. Click the **VPC ID**. ![](https://storage.googleapis.com/prequel_docs/images/postgres-vpc-id.png "vpc id.png") 4. In the **Details** section, click on the link under **Main network ACL**. ![](https://storage.googleapis.com/prequel_docs/images/postgres-main-network-acl-id.png "network acl id.png") 5. Click on the network ACL ID. ![](https://storage.googleapis.com/prequel_docs/images/postgres-network-acl-id.png "network acl id.png") #### Edit the inbound rules 6. Click on the **Inbound rules** tab, and check if there is an existing rule with a Source of `0.0.0.0/0` set to `Allow`. (This is a default rule created by AWS. If this rule already exists, skip to **Edit outbound rules**.) ![](https://storage.googleapis.com/prequel_docs/images/postgres-inbound-rules.png "inbound rules.png") 7. Create the inbound rule (if it doesn't exist). Click **Edit inbound rules** and either **Add new rule** or edit an existing rule to allow access to the **port number** of your database instance (usually `5432`) from the Prequel static IP. Click **Save changes**. #### Edit the outbound rules 8. In the ACL menu, select the **Outbound rules** tab, and check if there is an existing rule with a Destination of `0.0.0.0/0` set to `Allow`. (This is a default rule created by AWS. If this rule already exists, skip to the next step.) ![](https://storage.googleapis.com/prequel_docs/images/postgres-outbound-rules.png "outbound rules.png") 9. Create the outbound rule (if it doesn't exist). Click **Edit outbound rules** and edit the rules to allow outbound traffic to ports 1024-65535 for **Destination** `0.0.0.0/0`. ## Step 2: Create writer user Create a database user to perform the writing of the source data. 1. Open a connection to your Amazon RDS PostgreSQL database. 2. Create a user for the data transfer by executing the following SQL command. ```sql theme={null} CREATE USER PASSWORD ''; ``` 3. Grant user `create` and `temporary` privileges on the database. `create` allows the service to create new schemas and `temporary` allows the service to create temporary tables. ```sql theme={null} GRANT CREATE, TEMPORARY ON DATABASE TO ; ``` **If the `schema` already exists:** By default, the service creates a new schema based on the destination configuration (in the next step). If you prefer to create the schema yourself before connecting the destination, you must ensure that the writer user has the proper permissions on the schema, using `GRANT ALL ON schema TO ;` ## Step 3: Add your destination Securely share your **host name**, **database name**, **port**, your chosen **schema name**, **username**, and **password** with us to complete the connection. # Azure Blob Storage Source: https://docs.thanx.com/data/connex/azure-blob-storage Configuring your Azure Blob Storage destination. ## Step 1: Create Azure storage account 1. In the Azure portal, navigate to the **Storage accounts** service and click **+ Create**. 2. In the "Basics" tab of the "Create a storage account" form, fill in the required details. 3. In the "Advanced" settings, under "Security" make sure **Enable storage account key access** is turned on. You may turn off (deselect) "Allow enabling public access on containers". Under "Data Lake Storage Gen2", select **Enable hierarchical namespace**. 4. In the "Networking" settings, you may limit "Network access" to either **Enable public access from all networks** or **Enable public access from selected virtual networks and IP addresses**. If the latter is selected, be sure to add the service's static IP to the address range of the chosen virtual network. All other settings can use the default selections. 5. In the "Data protection" settings, you must turn off **Enable soft delete for blobs**, **Enable soft delete for containers**, and **Enable soft delete for file shares**. 6. Once the remaining options have been configured to your preference, click **Create**. ## Step 2: Create container and access token 1. In the Azure portal, navigate to the **Storage accounts** service and click on the account that was created in the previous step. 2. In the navigation pane, under "Data storage", click **Containers**. Click **+ Container**, choose a name for the container, and click **Create**. 3. In the navigation pane, under "Security + networking", click **Shared access signature**. 4. Update the required accessible services and permissions: 1. Under "Allowed services": select **Blob** and **File**. 2. Under "Allowed resource types": select **Container** and **Object**. 3. Under "Allowed permissions": select **Read**, **Write**, **Delete**, **List**, **Add**, **Create**, and **Permanently Delete**. 5. Select a "Start and expiry date/time" based on your security posture (e.g., set the expiration date 6 months into the future), and click **Generate SAS and connection string**. 6. Make a note of the **SAS token** that is generated. ## Step 3: Add your destination Securely share your **storage account name**, **container name**, your chosen **folder name** for the data, and your **Storage account SAS token** with us to complete the connection. # BigQuery Source: https://docs.thanx.com/data/connex/bigquery Configuring your BigQuery destination. ## Prerequisites * [ ] By default, BigQuery authentication uses role-based access. You will need the data-syncing service's service account name available to grant access. It should look like `some-name@some-project.iam.gserviceaccount.com`. ## Step 1: Create service account in BigQuery project 1. In the GCP console, navigate to the **IAM & Admin** menu, click into the **Service Accounts** tab, and click **Create service account** at the top of the menu. ![](https://storage.googleapis.com/prequel_docs/images/gcp-create-service-account-menu.png "create service account menu.png") 2. In the first step, name the user and click **Create and Continue**. ![](https://storage.googleapis.com/prequel_docs/images/gcp-service-account-name-options.png "service account name options.png") 3. In the second step, grant the user the role **BigQuery User**. ![](https://storage.googleapis.com/prequel_docs/images/gcp-bigquery-user.png) **Understanding the BigQuery User role** The BigQuery User role is a predefined IAM role that allows for the creation of new datasets, with the creator granted BigQuery Data Owner on the new dataset. If you would like to avoid using the BigQuery User role, the minimum required permissions are: * On the **Project level**: * `bigquery.datasets.create` * `bigquery.datasets.get` * `bigquery.jobs.create` *Note: These minimum permissions assume that the dataset has not been created ahead of time. If you create the dataset ahead of time, see the following note.* **Loading data into a Dataset that already exists** By default, a new dataset (with a name you provide) will be created in the BigQuery project. If instead you create the dataset ahead of time, you will need to grant the **BigQuery Data Owner** role to this Service Account at the dataset level. In BigQuery, click on the existing dataset. In the dataset tab, click **Sharing**, then **Permissions**. Click **Add Principals**. Enter the Service Account name, and add the Role: **BigQuery Data Owner** Specifically, the minimum permissions required can be granted to the principal and applied to the **Dataset**: * `bigquery.tables.create` * `bigquery.tables.delete` * `bigquery.tables.get` * `bigquery.tables.getData` * `bigquery.tables.list` * `bigquery.tables.update` * `bigquery.tables.updateData` * `bigquery.routines.get` * `bigquery.routines.list` On the **Project** level, you will still need `bigquery.jobs.create`, but you will not need `bigquery.datasets.create` or `bigquery.datasets.get`. 4. In the third step (**Grant users access to this service account** step), within the **Service account users role** field, enter the provided **Service account** (see prerequisite) and click **Done**. 5. Once successfully created, search for the created service account in the service accounts list, click the **Service account** name to view the details, and make a note of the **email** (note: this is a different email than the service's service account). 6. Select the permissions tab, find the provided principal name (**Service account** from the prerequisite), click the **Edit principal** button (pencil icon), click **Add another role**, select the **Service Account Token Creator** role, and click **Save**. > ![](https://storage.googleapis.com/prequel_docs/images/gcp-grant-role.png) **Alternative authentication method: Granting direct access to service account** Role based authentication is the preferred authentication mode for BigQuery based on GCP recommendations, however, providing a service account key to directly log-in to the created service account is an alternative authentication method that can be used if preferred. 1. Back in the **Service accounts** menu, click the Actions dropdown next to the newly created service account and click **Manage keys**. ![](https://storage.googleapis.com/prequel_docs/images/gcp-manage-service-account-keys.png "manage sa keys.png") 2. Click **Add key** and then **Create new key**. ![](https://storage.googleapis.com/prequel_docs/images/gcp-create-new-key.png "create new key sa.png") 3. Select the **JSON** Key type and click **Create** and make note of the key that is generated. ## Step 2: Create a staging bucket 1. Log into the Google Cloud Console and navigate to **Cloud Storage**. Click **Create** to create a new bucket. ![](https://storage.googleapis.com/prequel_docs/images/gcp-create-gcs-bucket.png) 1. Choose a **name** for the bucket. Click **Continue**. Select a **location** for the staging bucket. Make a note of both the **name** and the **location** (region). **Choosing a `location` (region)** The location you choose for your staging bucket must match the location of your destination dataset in BigQuery. When creating your bucket, be sure to choose a region in which BigQuery is supported [(see BigQuery regions)](https://cloud.google.com/bigquery/docs/locations) * If the dataset **does not** exist yet, the dataset will be created for you in the same region where you created your bucket. * If the dataset **does** exist, the dataset region must match the location you choose for your bucket. 2. Click **continue** and select the following options according to your preferences. Once the options have been filled out, click **Create**. 3. On the **Bucket details** page that appears, click the **Permissions** tab, and then click **Add**. ![](https://storage.googleapis.com/prequel_docs/images/gcp-add-permission-to-bucket.png) 4. In the **New principles** dropdown, add the Service Account created in **Step 1**, select the **Storage Admin** role, and click **Save**. ![](https://storage.googleapis.com/prequel_docs/images/gcp-storage-admin.png) ## Step 3: Find Project ID 1. Log into the Google Cloud Console and select the projects list dropdown. 2. Make note of the BigQuery **Project ID**. ![](https://storage.googleapis.com/prequel_docs/images/gcp-project-id.png "project id.png") ## Step 4: Add your destination 1. Securely share your **Project ID**, **Bucket Name**, **Bucket Location**, **Destination Schema Name** and **Service Account name** with us to complete the connection. # ClickHouse Source: https://docs.thanx.com/data/connex/click-house Configuring your ClickHouse destination. ## Prerequisites * [ ] If your ClickHouse security posture requires IP whitelisting, have our data syncing service's static IP available during the following steps. It will be required in Step 1. ## Step 1: Allow access Create a rule in a security group or firewall settings to whitelist: 1. incoming connections to your host and port (usually `9440`) from the static IP. 2. outgoing connections from ports `1024` to `65535` to the static IP. ## Step 2: Create writer user Create a database user to perform the writing of the data. 1. Open a connection to your ClickHouse database. 2. Create a user for the data transfer by executing the following SQL command. ```sql theme={null} CREATE USER @'%' IDENTIFIED BY ''; ``` 3. Grant user required privileges on the database. ```sql theme={null} GRANT CREATE, INSERT, DROP, ALTER, OPTIMIZE, SHOW ON TO @'%'; grant CREATE TEMPORARY TABLE, S3 on *.* to @'%'; ``` **Understanding the `CREATE TEMPORARY TABLE, S3` permissions** The `CREATE TEMPORARY TABLE` and `S3` permissions are required to efficiently transfer data to ClickHouse. Under the hood, these permissions are used to stage data in object storage as compressed files, COPY INTO temporary tables, and finally merge into the target tables. By definition, the temporary table will not exist outside of the session. ## Step 3: Setup staging bucket ClickHouse sources require a staging bucket to efficiently transfer data. Configure your staging bucket using one of the following types of ClickHouse supported object storage: * S3 * GCS * Implicit **Using the `implicit` bucket option** ClickHouse supports the ability to configure staging resources with [environment credentials](https://clickhouse.com/docs/en/integrations/s3#managing-credentials). If this setting is enabled on your ClickHouse cluster, you may choose to use the configured implicit staging resources using the `implicit` option for the staging bucket selection. ## Step 4: Add your destination Securely share your **host name**, **port**, **cluster**, **database name**, **schema name**, **username**, **password**, and staging bucket details with us to complete the connection. **Understanding the `database` vs. `schema` fields (`connection database` vs. `write database`)** Depending on the version of your integration, you may be asked for both a `database` and `schema`, or a `connection database` and `write database`. * `database` (also referred to as `connection_database`): is the **database** used to establish the connection with ClickHouse. * `schema` (also referred to as `write_database`): is the **database/schema** within which data will be written These can be (and often are) the same values, but do not need to be. ## Using the ClickHouse data **Querying ClickHouse data without duplicates** The resulting ClickHouse tables use the [ReplacingMergeTree](https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/replacingmergetree) table engine in order to efficiently upsert changes. To properly query this data, the `FINAL` keyword must be used when selecting from these tables guarantee duplicates are removed. For example: ``` SELECT * FROM schema.table FINAL WHERE foo = bar ORDER BY foo LIMIT 10; ``` # Databricks Source: https://docs.thanx.com/data/connex/databricks Configuring your Databricks destination. ## Prerequisites * [ ] By default, this Databricks integration makes use of Unity Catalog data governance features. You will need Unity Catalog enabled on your Databricks Workspace. ## Step 1: Create a SQL warehouse Create a new SQL warehouse for data writing. 1. Log in to the Databricks account. 2. In the navigation pane, click into the workspace dropdown and select **SQL**. 3. In the SQL console, in the SQL navigation pane, click **Create** and then **SQL warehouse**. ![](https://storage.googleapis.com/prequel_docs/images/databricks-sql-endpoint.png "sql_endpoint.png") 4. In the New SQL Warehouse menu, choose a **name** and **configure the options** for the new SQL warehouse. Under "Advanced options" turn "Unity Catalog" to the **On** position, select the **Preview** channel, and click **Create**. ![](https://storage.googleapis.com/prequel_docs/images/databricks-new-sql-endpoint.png "new_sql_endpoint.png") ## Step 2: Configure Access Collect connection information and create an access token for the data transfer service. 1. In the **SQL Warehouses** console, select the SQL warehouse you created in **Step 1**. ![](https://storage.googleapis.com/prequel_docs/images/databricks-endpoints-console.png "endpoints_console.png") 2. Click the **Connection Details** tab, and make a note of the **Server hostname**, **Port**, and **HTTP path**. ![](https://storage.googleapis.com/prequel_docs/images/databricks-server-port-path.png "server_port_path.png") 3. Click the link to Create a **personal access token**. ![](https://storage.googleapis.com/prequel_docs/images/databricks-create-personal-access-token.png "create_a_personal_access_token.png") 4. Click **Generate New Token**. ![](https://storage.googleapis.com/prequel_docs/images/databricks-generate-new-token.png "create_new_token.png") 5. Name the token with a descriptive comment and assign the token lifetime. A longer lifetime will ensure you do not have to update the token as often. Click **Generate**. 6. In the pop up that follows, **copy the token** and securely save the token. **Using a Service Principal & Token instead of your Personal Access Token** You may prefer to create a **Service Principal** to use for authentication instead of using a Personal Access Token. To do so, use the following steps to create a Service Principal and generate an access token. 1. In your Databricks workspace, click your username in the top right, click **Admin Settings**, **Identity and access**, and next to the **Service Principals** options, click **Manage**. 2. Click the **Add service principal** button, click **Add new** in the modal, enter a display name and click **Add**. 3. Click on the newly created Service Principal, and under **Entitlements** select **Databricks SQL Access** and **Workspace Access**. Click **Update**, and make a note of the **Application ID** of your newly created Service Principal. 4. Back in the **Admin Settings** menu, click the **Advanced** section (under the **Workspace admin** menu). In the **Access Control** section, next to the **Personal Access Tokens** row, click **Permission Settings**. Search for and select the **Service Principal** you created, select the **Can use** permission, click **Add**, and then **Save**. 5. Navigate back to the **SQL Warehouses** section of your Workspace, click the **SQL Warehouses** tab, and select the **SQL Warehouse** you created in **Step 1**. Click **Permissions** in the top right, search for and select the **Service Principal** you created, select the **Can use** permission, and click **Add**. 6. Use your terminal to generate a **Service Principal Access Token** using your Personal Access Token generated above. Record the **token value**. This token can now be used as the access token for the connection. ```curl cURL request theme={null} curl --request POST "https://.cloud.databricks.com/api/2.0/token-management/on-behalf-of/tokens" \ --header "Authorization: Bearer " \ --data '{ "application_id": "", "lifetime_seconds": , "comment": "" }' ``` 7. In the Databricks UI, select the **Catalog** tab, and select the target **Catalog**. Within the catalog **Permissions** tab, click **Grant**. In the following modal, select the **principal** for which you generated the access token, select `USE CATALOG`, and click **Grant**. 8. Under the target **Catalog**, select the target **schema** (e.g., `main.default`, or create a new target schema). Within the schema **Permissions** tab, click **Grant**. In the following modal, select the **principal** for which you generated the access token, and select either `ALL PRIVILEGES` or the following 9 privileges and then click **Grant**: * `USE SCHEMA` * `APPLY TAG` * `MODIFY` * `READ VOLUME` * `SELECT` * `WRITE VOLUME` * `CREATE MATERIALIZED VIEW` * `CREATE TABLE` * `CREATE VOLUME` ## Step 3: Add your destination 1. Securely share your **server hostname**, **HTTP path**, **catalog**, your chosen **schema name**, and **access token** with us to complete the connection. # Google Cloud Storage Source: https://docs.thanx.com/data/connex/google-cloud-storage Configuring your Google Cloud Storage destination. ## Prerequisites * [ ] By default, GCS authentication uses role-based access. You will need the data-syncing service's service account name available to grant access. It should look like `some-name@some-project.iam.gserviceaccount.com`. ## Step 1: Create a service account 1. In the GCP console, navigate to the **IAM & Admin** menu, click into the **Service Accounts** tab, and click **Create service account** at the top of the menu. 2. In the first step, name the service account that will be used to transfer data into Cloud Storage and click **Create and Continue**. Click **Continue** in the following optional step without assigning any roles. 3. In the **Grant users access to this service account** step, within the **Service account users role** field, enter the provided **Service account** (see prerequisite) and click **Done**. 4. Once successfully created, search for the created service account in the service accounts list, click the **Service account** name to view the details, and make a note of the **email** (note: this is a different email than the service's service account). 5. Select the permissions tab, find the provided principal name (**Service account** from the prerequisite), click the **Edit principal** button (pencil icon), click **Add another role**, select the **Service Account Token Creator** role, and click **Save**. > ![](https://storage.googleapis.com/prequel_docs/images/gcp-grant-role.png) **Alternative authentication method: HMAC Access Key & Secret** Role based authentication is the preferred authentication mode for Google Cloud Storage based on GCP recommendations, however, HMAC Access Key ID & Secret Access Key is an alternative authentication method that can be used if preferred. An HMAC key is a type of credential and can be associated with a service account or a user account to access Google Cloud Storage. 1. Navigate to the **Cloud Storage** page. 2. Click into the **Settings** tab on the left side menu. ![](https://storage.googleapis.com/prequel_docs/images/gcs-bucket-settings.png) 3. Navigate to the **Interoperability** tab and click the **Create a key for a Service Account** button. 4. Select the **Service Account** created in **Step 1**, and click **Create key**. ![](https://storage.googleapis.com/prequel_docs/images/gcs-select-service-account-hmac.png) 5. Make a note of the **Access key** and **Secret**. ## Step 2: Create destination GCS bucket 1. Navigate to the **Cloud Storage** page. 2. Click **Create**. 3. Enter a **bucket name**, choose a **region**. **Note**: at the **Choose how to control access to objects** step, we recommend selecting **Enforce public access prevention on this bucket**. ![](https://storage.googleapis.com/prequel_docs/images/gcs-prevent-public-access.png) 4. After choosing your preferences for the remaining steps, click **Create**. 5. On the **Bucket details** page for the bucket you created, select the **Permissions** tab, and click **Grant access**. 6. Grant access to the principal (Service Account) you created in **Step 1** (*Note: this is the service account you created, not the service account from the prerequisite*), and assign the Role: **Storage Legacy Bucket Writer**. Click **Save**. ![](https://storage.googleapis.com/prequel_docs/images/gcp-storage-legacy-bucket-writer.png) ## Step 3: Add your destination Securely share your **bucket name**, your chosen **folder name** for the data, and your **Service account email** with us to complete the connection. # Google Sheets Source: https://docs.thanx.com/data/connex/google-sheets Configuring your Google Sheets destination. ## Step 1: Create a new Google Sheet and share with the generated Service Account 1. Navigate to the your Google Drive or the Google Sheets homepage and create a new Google Sheet in a folder of your choice. 2. In the Google Sheet menu, click **Share** in the top right corner, and enter the Service Account email address generated in the destination onboarding form. Grant the Service Account **Editor** permission, and click **Send**. ## Step 2: Add your destination Test your connection and save the destination to complete the connection. During the initial sync, data tables will be loaded as individual tabs, and refreshed at the designated frequency. # Generic MySQL Source: https://docs.thanx.com/data/connex/mysql Configuring your generic MySQL destination. ## Prerequisites * [ ] If your MySQL database is protected by security groups or other firewall settings, you will need to have the data-syncing service's static IP available to complete **Step 1**. ## Step 1: Allow access Create a rule in a security group or firewall settings to whitelist: * incoming connections to your host and port (usually `3306`) from the static IP. * outgoing connections from ports `1024` to `65535` to the static IP. ## Step 2: Create writer user Create a database user to perform the writing of the source data. 1. Open a connection to your MySQL database. 2. Create a user for the data transfer by executing the following SQL command. ```sql theme={null} CREATE USER @'%' IDENTIFIED BY ''; ``` 3. Grant user required privileges on the database. ```sql theme={null} GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, CREATE TEMPORARY TABLES, CREATE VIEW ON *.* TO @'%'; ``` **If the `schema`/`database` already exists** By default, the service creates a new schema (*in MySQL, `schema` is synonomous with `database`*). If you prefer to create the schema yourself before connecting the destination, you must ensure that the writer user has the proper permissions on the schema, using `GRANT ALL PRIVILEGES ON .* TO @'%';` ## Step 3: Add your destination Securely share your **host name**, **database name**, **port**, your chosen **schema name**, **username**, and **password** with us to complete the connection. # Generic Postgres Source: https://docs.thanx.com/data/connex/postgres Configuring your generic Postgres destination. ## Prerequisites * [ ] If your Postgres database is protected by security groups or other firewall settings, you will need to have the data-syncing service's static IP available to complete Step 1. ## Step 1: Allow access Create a rule in a security group or firewall settings to whitelist: * incoming connections to your host and port (usually `5432`) from the static IP. * outgoing connections from ports `1024` to `65535` to the static IP. ## Step 2: Create writer user Create a database user to perform the writing of the source data. 1. Open a connection to your PostgreSQL database. 2. Create a user for the data transfer by executing the following SQL command. ```sql theme={null} CREATE USER PASSWORD ''; ``` 3. Grant user `create` and `temporary` privileges on the database. `create` allows the service to create new schemas and `temporary` allows the service to create temporary tables. ```sql theme={null} GRANT CREATE, TEMPORARY ON DATABASE TO ; ``` **If the `schema` already exists** By default, the service creates a new schema based on the destination configuration (in the next step). If you prefer to create the schema yourself before connecting the destination, you must ensure that the writer user has the proper permissions on the schema, using `GRANT ALL ON schema TO ;` ## Step 3: Add your destination Securely share your **host name**, **database name**, **port**, your chosen **schema name**, **username**, and **password** with us to complete the connection. # Redshift Source: https://docs.thanx.com/data/connex/redshift Configuring your Redshift destination. ## Prerequisites * [ ] If your Redshift security posture requires IP whitelisting, have our data syncing service's static IP available during the following steps. It will be required in Step 2. * [ ] By default, Redshift authentication uses role-based access. You will need the trust policy prepopulated with the data-syncing service's identifier to grant access. It should look similar to the following JSON object with a proper service account identifier: ```json theme={null} { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "sts:AssumeRoleWithWebIdentity" ], "Principal": { "Federated": "accounts.google.com" }, "Condition": { "StringEquals": { "accounts.google.com:sub": "" } } } ] } ``` ## Step 1: Create a Limited User in Redshift 1. Connect to Redshift using the SQL client. 2. Execute the following query to create a user to write the data (replace `` with a password of your choice). ```sql theme={null} CREATE USER PASSWORD ''; ``` **Creating a user without a password.** Role based auth does not require a password. You may create the user using `CREATE USER PASSWORD DISABLE;`. 3. Grant user `create` and `temporary` privileges on the database. `create` allows the service to create new schemas and `temporary` allows the service to create temporary tables. ```sql theme={null} GRANT CREATE, TEMPORARY ON DATABASE TO ; ``` **The schema will be created during the first sync** The schema name supplied as part of Step 4 will be created during the first connection. It does not need to be created manually in the destination ahead of time. **If the `schema` already exists** By default, the service creates a new schema based on the destination configuration. If you prefer to create the schema yourself before connecting the destination, you must ensure that the writer user has the proper permissions on the schema, using `GRANT ALL ON schema TO ;` Once you've provided the `GRANT ALL` permission on the schema, you can safely remove the `CREATE` permission on the database (but you must retain the `TEMPORARY` permission on the database). ## Step 2: Whitelist connection 1. In the Redshift console, click **Clusters**, and make a note of the **cluster** name. 2. Select the cluster you would like to connect. 3. In the **General information** pane, make note of the **Endpoint** details. You may need to use the **copy** icon to copy the full details to discover the full endpoint and port number. ![](https://storage.googleapis.com/prequel_docs/images/redshift-endpoint-details.png "redshift endpoint details.png") 4. Click the **Properties** tab. 5. Scroll down to the **Network and security settings** section. 6. In the VPC security group field, select a security group to open it. ![](https://storage.googleapis.com/prequel_docs/images/redshift-vpc-security-groups.png "redshift vpc s groups.png") 7. In the Security Groups window, click **Inbound rules**. 8. Click **Edit inbound rules**. 9. In the Edit the Inbound rules window, follow the steps below to create custom TCP rules for the static IP: * Select **Custom TCP** in the drop-down menu. * Enter your Redshift port number. (likely `5439`) * Enter the **static IP**. * Click **Add rule**. ## Step 3: Create a staging bucket ### Create staging bucket 1. Navigate to the S3 service page. 2. Click Create bucket. 3. Enter a **Bucket name** and modify any of the default settings as desired. Note: **Object Ownership** can be set to "**ACLs disabled**" and **Block Public Access settings for this bucket** can be set to "**Block all public access**" as recommended by AWS. Make note of the Bucket name and AWS Region. 4. Click **Create bucket**. ### Create policy 1. Navigate to the **IAM** service page, click on the **Policies** navigation tab, and click **Create policy**. 2. Click the JSON tab, and paste the following policy, being sure to replace `BUCKET_NAME` with the name of the bucket chosen above, and REGION\_NAME, ACCOUNT\_ID, CLUSTER\_NAME, USERNAME, and DATABASE\_NAME with the proper Redshift values. * **Note**: the first bucket permission in the list applies to `BUCKET_NAME` whereas the second permission applies only to the bucket's contents — `BUCKET_NAME/*` — an important distinction. ```json JSON policy theme={null} { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "s3:ListBucket", "Resource": "arn:aws:s3:::BUCKET_NAME" }, { "Effect": "Allow", "Action": [ "s3:PutObject", "s3:GetObject", "s3:DeleteObject" ], "Resource": "arn:aws:s3:::BUCKET_NAME/*" }, { "Effect": "Allow", "Action": "redshift:GetClusterCredentials", "Resource": [ "arn:aws:redshift:REGION_NAME:ACCOUNT_ID:dbuser:CLUSTER_NAME/USERNAME", "arn:aws:redshift:REGION_NAME:ACCOUNT_ID:dbname:CLUSTER_NAME/DATABASE_NAME" ] } ] } ``` 3. Click through to the **Review** step, choose a **name** for the policy, for example, `transfer-service-policy` (this will be referenced in the next step), add a description, and click **Create policy**. ### Create role 1. Navigate to the **IAM** service page. 2. Navigate to the **Roles** navigation tab, and click **Create role**. 3. Select **Custom trust policy** and paste the provided trust policy (from the prerequisite) to allow AssumeRole access to this role. Click **Next**. 4. Add the permissions policy created above, and click **Next**. 5. Enter a **Role name**, for example, `transfer-role`, and click **Create role**. 6. Once successfully created, search for the created role in the Roles list, click the role name, and make a note of the **ARN** value. **Alternative authentication method: AWS User with HMAC Access Key ID & Secret Access Key** Role based authentication is the preferred authentication mode for Redshift based on AWS recommendations, however, HMAC Access Key ID & Secret Access Key is an alternative authentication method that can be used if preferred. 1. Navigate to the **IAM** service page. 2. Navigate to the **Users** navigation tab, and click **Add users**. 3. Enter a **User name** for the service, for example, `transfer-service`, click **Next**. Under **Select AWS access type**, select the **Access key - Programatic access** option. Click **Next: Permissions**. 4. Click the **Attach existing policies directly** option, and search for the name of the policy created in the previous step. Select the policy, and click **Next: Tags**. 5. Click **Next: Review** and click **Create user**. 6. In the **Success** screen, record the **Access key ID** and the **Secret access key**. ## Step 4: Add your destination 1. Securely share your **host**, **database**, **cluster**, your chosen **schema**, **IAM role ARN**, and **staging bucket details** with us to complete the connection. # S3 Source: https://docs.thanx.com/data/connex/s3 Configuring your AWS S3 destination. ## Prerequisites * [ ] By default, S3 authentication uses role-based access. You will need the trust policy prepopulated with the data-syncing service's identifier to grant access. It should look similar to the following JSON object with a proper service account identifier: ```json theme={null} { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "sts:AssumeRoleWithWebIdentity" ], "Principal": { "Federated": "accounts.google.com" }, "Condition": { "StringEquals": { "accounts.google.com:sub": "" } } } ] } ``` ## Step 1: Set up destination S3 bucket ### Create bucket 1. Navigate to the **S3** service page. 2. Click **Create bucket**. 3. Enter a **Bucket name** and modify any of the default settings as desired. Note: **Object Ownership** can be set to "ACLs disabled" and **Block Public Access settings for this bucket** can be set to "Block all public access" as recommended by AWS. Make note of the **Bucket name** and **AWS Region**. 4. Click **Create bucket**. ## Step 2: Create policy and IAM role ### Create policy 1. Navigate to the **IAM** service page. 2. Navigate to the **Policies** navigation tab, and click **Create policy**. 3. Click the **JSON** tab, and paste the following policy, being sure to replace `BUCKET_NAME` with the name of the bucket chosen in Step 1. ```json JSON policy theme={null} { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["s3:PutObject", "s3:DeleteObject"], "Resource": "arn:aws:s3:::BUCKET_NAME/*" } ] } ``` **Understanding the s3:DeleteObject requirement** By default, a connection test is performed against the destination during initial configuration and `s3:DeleteObject` is required to clean up test artifacts. Once the test has been performed successfully and the destination added, this action can be safely removed, as S3 destinations are append-only by default. 4. Click **Next: Tags**, click **Next: Review**. 5. Name the policy, add a description, and click **Create policy**. ### Create role 1. Navigate to the **IAM** service page. 2. Navigate to the **Roles** navigation tab, and click **Create role**. 3. Select **Custom trust policy** and paste the provided trust policy to allow AssumeRole access to the new role. Click **Next**. 4. Add the permissions policy created above, and click **Next**. 5. Enter a **Role name**, for example, `transfer-role`, and click **Create role**. 6. Once successfully created, search for the created role in the Roles list, click the role name, and make a note of the **ARN** value. **Alternative authentication method: AWS User with HMAC Access Key ID & Secret Access Key** Role based authentication is the preferred authentication mode for S3 based on AWS recommendations, however, HMAC Access Key ID & Secret Access Key is an alternative authentication method that can be used if preferred. 1. Navigate to the **IAM** service page. 2. Navigate to the **Users** navigation tab, and click **Add users**. 3. Enter a **User name** for the service, for example, `transfer-service`, click **Next**. Under **Select AWS access type**, select the **Access key - Programatic access** option. Click **Next: Permissions**. 4. Click the **Attach existing policies directly** option, and search for the name of the policy created in the previous step. Select the policy, and click **Next: Tags**. 5. Click **Next: Review** and click **Create user**. 6. In the **Success** screen, record the **Access key ID** and the **Secret access key**. ## Step 3: Add your destination Securely share your **bucket name**, **bucket region**, and **role ARN** with us to complete the connection. # S3 Compatible Source: https://docs.thanx.com/data/connex/s3-compatible Configuring your S3 compatible destination. Many object storage platforms offer "S3 compatibility" enabling writing to and reading from the object storage using the S3 protocol. The S3 protocol uses an HMAC key comprised of an access ID and a secret to authenticate and write data. ## Step 1: Create an HMAC Access ID and Secret Consult your object storage platform's documentation to learn how to generate an HMAC Access ID and Secret. ## Step 2: Add your destination Securely share your **bucket host**, **bucket name**, chosen **folder name**, **HMAC access ID**, and **HMAC secret** with us to complete the connection. # Connex Setup Source: https://docs.thanx.com/data/connex/setup Thanx Connex allows for direct loading of Thanx data into the destination of your choice. To enable this functionality, follow the below steps. Let your success manager know that your team is interested in leveraging Thanx Connex for direct data loading and what type of destination (eg. Snowflake, BigQuery, MySQL, etc) you are looking to configure for data loading. Thanx Connex incurs pass-through fees of \$300/mo per destination to cover underlying technology services. Follow the appropriate guide to configure your destination in preparation for data loading: * [Snowflake](/data/connex/snowflake) * [BigQuery](/data/connex/bigquery) * [Redshift](/data/connex/redshift) * [Databricks](/data/connex/databricks) * [Athena](/data/connex/athena) * [ClickHouse](/data/connex/click-house) * [Postgres](/data/connex/postgres) * [AWS Postgres (RDS & Aurora)](/data/connex/aws-postgres) * [MySQL](/data/connex/mysql) * [AWS MySQL (RDS & Aurora)](/data/connex/aws-mysql) * [SQL Server](/data/connex/sql-server) * [S3](/data/connex/s3) * [S3 Compatible](/data/connex/s3-compatible) * [Google Cloud Storage](/data/connex/google-cloud-storage) * [Azure Blob Storage](/data/connex/azure-blob-storage) * [Google Sheets](/data/connex/google-sheets) In order to provision a setup link, your success manager will ask you to provide additional details depending on the desired destination. For example, database hostname (databases) or bucket name (object storage). Once provided, your success manager will send you a setup link to finalize the setup process. Once setup is complete and you see a success message, Thanx Connex will automatically provision tables and manage any schema changes and begin to load data into your destination. The initial data load may take a number of hours, after which incremental data will be synced every 24 hours. # Snowflake Source: https://docs.thanx.com/data/connex/snowflake Configuring your Snowflake destination. ## Prerequisites * [ ] In order to complete the following setup steps, you or a Snowflake admin on your team must have the securityadmin and sysadmin roles. (To check your account for these roles, run `SHOW GRANTS TO USER ;` and review the `role` column.) * [ ] If your Snowflake data warehouse is using Snowflake Access Policies, you will need to have the data-syncing service's static IP available to complete Step 2. ## Step 1: Create role, user, warehouse, and database in the data warehouse 1. Review and make any changes to the following setup script. ```sql theme={null} begin; -- create variables for user / password / role / warehouse / database set role_name = 'TRANSFER_ROLE'; -- all letters must be uppercase set user_name = 'TRANSFER_USER'; -- all letters must be uppercase set user_password = 'some_password'; -- alphanumeric only, special characters are not allowed set warehouse_name = 'TRANSFER_WAREHOUSE'; -- all letters must be uppercase set database_name = 'TRANSFER_DATABASE'; -- all letters must be uppercase -- change role to securityadmin for user / role steps use role securityadmin; -- create role for data transfer service create role if not exists identifier($role_name); grant role identifier($role_name) to role SYSADMIN; -- establish SYSADMIN as the parent of the new role. Note: this does not grant the access privileges of SYSADMIN to the new role. -- create a user for data transfer service using key-based authentication create user if not exists identifier($user_name) -- this public key should be copied from the connection form in the onboarding UI RSA_PUBLIC_KEY='MIIBIjANBgkqh...'; -- set default role and warehouse to new user alter user identifier($user_name) SET default_role = $role_name; alter user identifier($user_name) SET default_warehouse = $warehouse_name; grant role identifier($role_name) to user identifier($user_name); -- change role to sysadmin for warehouse / database steps use role sysadmin; -- create a warehouse for data transfer service create warehouse if not exists identifier($warehouse_name) warehouse_size = xsmall warehouse_type = standard auto_suspend = 60 auto_resume = true initially_suspended = true; -- create database for data transfer service create database if not exists identifier($database_name); -- grant service role access to warehouse grant USAGE on warehouse identifier($warehouse_name) to role identifier($role_name); -- grant service access to database grant CREATE SCHEMA, MONITOR, USAGE on database identifier($database_name) to role identifier($role_name); commit; ``` **Using an existing `schema`** By default, a new schema (with a name you provide) will be created in the target Snowflake database upon the initial connection. If instead you create the `schema` ahead of time, you may remove the `CREATE SCHEMA` permission, and instead `grant ALL PRIVILEGES` on the target `schema` for the designated `role`. The script below can be used to complete this step: ```sql theme={null} set role_name = 'TRANSFER_ROLE'; set database_name = 'TRANSFER_DATABASE'; set schema_name = 'PRECREATED_SCHEMA'; use database identifier($database_name); grant ALL PRIVILEGES on schema identifier($schema_name) to role identifier($role_name); ``` **Using an existing `warehouse` or `database`** By default, this script creates a new warehouse and a new database. If you'd prefer to use an existing warehouse/database, change the `warehouse_name` variable from `TRANSFER_WAREHOUSE` to the name of the warehouse to be shared/`database_name` variable from `TRANSFER_DATABASE` to the name of the database to be shared. 2. In the Snowflake interface, select the dropdown next to the "Run" button, and click **Run All**. This will run every query in the script at once. If successful, you will see `Statement executed successfully` in the query results. ## Step 2: Configure the Snowflake access policy If your Snowflake data warehouse is using Snowflake Access Policies, a new policy must be added to allow the transfer service static IP to write to the warehouse. 1. Review current network policies to check for existing IP safelists. ```sql theme={null} SHOW NETWORK POLICIES; ``` 2. If there is no existing Snowflake Network Policies (the `SHOW` query returns no results), you can skip to Step 3. 3. If there is an existing Snowflake Network Policy, you must alter the existing policy or create a new one to safelist the data transfer service static IP address. Use the `CREATE NETWORK POLICY` command to specify the IP addresses that can access your Snowflake warehouse. ```sql theme={null} CREATE NETWORK POLICY ALLOWED_IP_LIST = ('5.4.7.8/32'); ``` **Creating your first network policy** If you have no existing network policies and you create your first as part of this step, all other IPs outside of the `ALLOWED_IP_LIST` will be blocked. Snowflake does not allow setting a network policy that blocks your current IP address. (An error message results while trying to create a network policy that blocks the current IP address.) But be careful when setting your first network policy. ## Step 3: Add your destination Securely share your **host name**, **database name**, your chosen **schema name**, **username**, and **password** with us to complete the connection. # SQL Server Source: https://docs.thanx.com/data/connex/sql-server Configuring your SQL Server destination. ## Prerequisites * [ ] If your SQL Server database is protected by security groups or other firewall settings, you will need to have the data-syncing service's static IP available to complete Step 1. * [ ] Confirm that your SQL Server database is configured to allow TCP/IP connections. ## Step 1: Allow access Create a rule in a security group or firewall settings to whitelist: * incoming connections to your host and port (usually `1433`) from the static IP. * outgoing connections from ports `1024` to `65535` to the static IP. ## Step 2: Create writer user Create a database user to perform the writing of the source data. 1. Open a connection to your SQL Server database. 2. Create a user for the data transfer by executing the following SQL command. The should be the target destination database. ```sql theme={null} USE ; CREATE LOGIN WITH PASSWORD = ''; CREATE USER FOR LOGIN ; ``` 3. Grant user `CREATE TABLE` privileges on the database. ```sql theme={null} GRANT CREATE TABLE TO ; ``` **Understanding the `CREATE TABLE` permission in SQL Server** The `CREATE TABLE` permission is a database level permission that allows for the creation of new tables in a given database. The user must also have the `ALTER` permission granted on a given schema in order to create new tables in that schema (see the next step for details). 4. Grant user `CREATE SCHEMA` privileges on the database *if the schema does not exist*. ```sql theme={null} GRANT CREATE SCHEMA TO ; ``` **If the `SCHEMA` already exists** By default, the service creates a new schema based on the destination configuration. If you prefer to create the schema yourself before connecting the destination, you may must ensure that the writer user has the proper permissions on the schema, using `GRANT SELECT, INSERT, UPDATE, DELETE, ALTER ON SCHEMA :: TO ;`. If the `SCHEMA` already exists, the user does not need the `GRANT CREATE SCHEMA` permission. ## Step 3: Add your destination Securely share your **host name**, **database name**, **port**, your chosen **schema name**, **username**, and **password** with us to complete the connection. # Campaigns Source: https://docs.thanx.com/data/models/campaigns The campaigns model represents the Thanx marketing campaigns. This model contains basic configuration information as well as aggregated campaign result data. Sample campaigns.csv Table name: `campaigns` ## Attributes | Column | Data Type | Description | | ---------------------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------- | | `campaign_id` | `string` | The unique identifier of the campaign in Thanx. | | `merchant_id` | `string` | The unique identifier of the merchant in Thanx. | | `name` | `string` | The name of the campaign. This is defined by the merchant. | | `start_earn_at` | `timestamp` | The date and time the campaign can start engaging customers. This is in UTC. | | `end_earn_at` | `timestamp` | The date and time the campaign will stop engaging customers. This is in UTC. | | `start_redeem_at` | `timestamp` | The date and time the reward starts being redeemable. This is in UTC. | | `end_redeem_at` | `timestamp` | The date and time the reward stops being redeemable. This is in UTC. | | `net_revenue` | `number` | The net revenue was generated from customers who received the campaign and made a purchase in the following 14 days. | | `unique_sent_email_users` | `number` | The number of users that were sent an email. | | `unique_delivered_email_users` | `number` | The number of users that were successfully delivered an email. | | `unique_clicked_email_users` | `number` | The number of users that clicked a link in the email. | | `unique_opened_email_users` | `number` | The number of users that opened the email. | | `unique_sent_push_users` | `number` | The number of users that were sent a push notification. | | `unique_delivered_push_users` | `number` | The number of users that were successfully delivered a push notification. | | `unique_sent_sms_users` | `number` | The number of users that were sent an SMS. (Deprecated) | | `unique_delivered_sms_users` | `number` | The number of users that were successfully delivered an SMS. (Deprecated) | | `unique_sent_email_variant_a_users` | `number` | The number of users that were sent an email for Variant A of the campaign. | | `unique_delivered_email_variant_a_users` | `number` | The number of users that were successfully delivered an email for Variant A of the campaign. | | `unique_clicked_email_variant_a_users` | `number` | The number of users that clicked a link in the email for Variant A of the campaign. | | `unique_opened_email_variant_a_users` | `number` | The number of users that opened the email for Variant A of the campaign. | | `unique_sent_email_variant_b_users` | `number` | The number of users that were sent an email for Variant B of the campaign. | | `unique_delivered_email_variant_b_users` | `number` | The number of users that were successfully delivered an email for Variant B of the campaign. | | `unique_clicked_email_variant_b_users` | `number` | The number of users that clicked a link in the email for Variant B of the campaign. | | `unique_opened_email_variant_b_users` | `number` | The number of users that opened the email for Variant B of the campaign. | | `unique_sent_email_variant_c_users` | `number` | The number of users that were sent an email for Variant C of the campaign. | | `unique_delivered_email_variant_c_users` | `number` | The number of users that were successfully delivered an email for Variant C of the campaign. | | `unique_clicked_email_variant_c_users` | `number` | The number of users that clicked a link in the email for Variant C of the campaign. | | `unique_opened_email_variant_c_users` | `number` | The number of users that opened the email for Variant C of the campaign. | | `unique_sent_email_variant_d_users` | `number` | The number of users that were sent an email for Variant D of the campaign. | | `unique_delivered_email_variant_d_users` | `number` | The number of users that were successfully delivered an email for Variant D of the campaign. | | `unique_clicked_email_variant_d_users` | `number` | The number of users that clicked a link in the email for Variant D of the campaign. | | `unique_opened_email_variant_d_users` | `number` | The number of users that opened the email for Variant D of the campaign. | | `unique_sent_push_variant_a_users` | `number` | The number of users that were sent a push notification for Variant A of the campaign. | | `unique_delivered_push_variant_a_users` | `number` | The number of users that were successfully delivered a push notification for Variant A of the campaign. | | `unique_sent_push_variant_b_users` | `number` | The number of users that were sent a push notification for Variant B of the campaign. | | `unique_delivered_push_variant_b_users` | `number` | The number of users that were successfully delivered a push notification for Variant B of the campaign. | | `unique_sent_push_variant_c_users` | `number` | The number of users that were sent a push notification for Variant C of the campaign. | | `unique_delivered_push_variant_c_users` | `number` | The number of users that were successfully delivered a push notification for Variant C of the campaign. | | `unique_sent_push_variant_d_users` | `number` | The number of users that were sent a push notification for Variant D of the campaign. | | `unique_delivered_push_variant_d_users` | `number` | The number of users that were successfully delivered a push notification for Variant D of the campaign. | | `unique_sent_sms_variant_a_users` | `number` | The number of users that were sent an SMS for Variant A of the campaign. | | `unique_delivered_sms_variant_a_users` | `number` | The number of users that were successfully delivered an SMS for Variant A of the campaign. | | `unique_sent_sms_variant_b_users` | `number` | The number of users that were sent an SMS for Variant B of the campaign. | | `unique_delivered_sms_variant_b_users` | `number` | The number of users that were successfully delivered an SMS for Variant B of the campaign. | | `unique_sent_sms_variant_c_users` | `number` | The number of users that were sent an SMS for Variant C of the campaign. | | `unique_delivered_sms_variant_c_users` | `number` | The number of users that were successfully delivered an SMS for Variant C of the campaign. | | `unique_sent_sms_variant_d_users` | `number` | The number of users that were sent an SMS for Variant D of the campaign. | | `unique_delivered_sms_variant_d_users` | `number` | The number of users that were successfully delivered an SMS for Variant D of the campaign. | | `unique_sent_variant_a_users` | `number` | The number of users that were sent any communication (email, push, and/or SMS) for Variant A of the campaign. | | `unique_delivered_variant_a_users` | `number` | The number of users that successfully received any communication (email, push, and/or SMS) for Variant A of the campaign. | | `unique_sent_variant_b_users` | `number` | The number of users that were sent any communication (email, push, and/or SMS) for Variant B of the campaign. | | `unique_delivered_variant_b_users` | `number` | The number of users that successfully received any communication (email, push, and/or SMS) for Variant B of the campaign. | | `unique_sent_variant_c_users` | `number` | The number of users that were sent any communication (email, push, and/or SMS) for Variant C of the campaign. | | `unique_delivered_variant_c_users` | `number` | The number of users that successfully received any communication (email, push, and/or SMS) for Variant C of the campaign. | | `unique_sent_variant_d_users` | `number` | The number of users that were sent any communication (email, push, and/or SMS) for Variant D of the campaign. | | `unique_delivered_variant_d_users` | `number` | The number of users that successfully received any communication (email, push, and/or SMS) for Variant D of the campaign. | | `unique_sent_users` | `number` | The number of users that were sent any communication (email, push, and/or SMS). | | `unique_delivered_users` | `number` | The number of users that successfully received any communication (email, push, and/or SMS). | # Communication Preferences Source: https://docs.thanx.com/data/models/communication-preferences The communication preferences model includes a user's opt in or opt out status of various communication preference settings. Sample communication\_preferences.csv Table name: `communication_preferences` ### Fields Description | Column | Data Type | Description | | ----------------------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `merchant_id` | `string` | The unique identifier of the merchant in Thanx. | | `user_id` | `string` | The unique identifier of the user in Thanx. | | `enabled_email_reward_earned` | `boolean` | User's selection for email notifications for "When I get a new reward" field. | | `enabled_email_reward_unused` | `boolean` | User's selection for email notifications for "When I have an unused reward" field. | | `enabled_email_reward_offer` | `boolean` | User's selection for email notifications for "When I have a special offer" field. | | `enabled_email_reward_progress` | `boolean` | User's selection for email notifications for "When I earn progress towards a reward" field. | | `enabled_email_payment_receipt` | `boolean` | User's selection for email notifications for "Send me a receipt" field. Only applies to merchants using exclusive deals. | | `enabled_email_marketing_general` | `boolean` | User's selection for email notifications for "General news and updates" field. Does not reflect the device-specific notifications setting (e.g. this field may still reflect "TRUE" if the user disabled the notifications from phone settings). | | `enabled_notification_reward_earned` | `boolean` | User's selection for push notifications for "When I get a new reward" field. Does not reflect the device-specific notifications setting. | | `enabled_notification_reward_unused` | `boolean` | User's selection for push notifications for "When I have an unused reward" field. Does not reflect the device-specific notifications setting. | | `enabled_notification_reward_progress` | `boolean` | User's selection for push notifications for "When I earn progress towards a reward" field. Does not reflect the device-specific notifications setting. | | `enabled_notification_feedback_available` | `boolean` | User's selection for push notifications for "To give feedback about purchases" field. Does not reflect the device-specific notifications setting. | | `created_at` | `timestamp` | The date and time the communication preference was created. This is in UTC. | | `updated_at` | `timestamp` | The date and time the communication preference was last updated by the user. This is in UTC. | # Loyalty Reward Progress (Legacy) Source: https://docs.thanx.com/data/models/loyalty-reward-progress-legacy Legacy loyalty progress export. Non-points loyalty programs are in the process of being fully retired from the Thanx platform and most brands do not use this data model. `loyalty_reward_progress_legacy.csv` *Unsupported* ### Attributes \| `merchant_id` | `string` | The unique identifier of the merchant in Thanx. | \| `user_id` | `string` | The unique identifier of the user in Thanx. | \| `loyalty_reward_progress` | `number` | User's current progress towards the loyalty reward. | # Memberships Source: https://docs.thanx.com/data/models/memberships The membership model includes information of users in your Thanx database. Sample memberships.csv Table name: `memberships` ### Attributes | Column | Data Type | Description | | ---------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `merchant_id` | `string` | The unique identifier of the merchant in Thanx. | | `user_id` | `string` | The unique identifier of the user in Thanx. | | `signup_program_id` | `string` | The unique identifier of the program that resulted in a user creating an account. | | `first_name` | `string` | The user's first name. | | `last_name` | `string` | The user's last name. | | `email` | `string` | The user's email address. | | `birthday` | `string` | The user's birthday. This is formatted as MM/DD. | | `zip_code` | `number` | The user’s zip code. | | `tier_status` | `string` | The user’s current tier status. There are three tiers: Bronze, Silver, and Gold. They are represented by a custom name set by the merchant. | | `is_user_joined` | `boolean` | Did the user has joined the loyalty program. | | `has_registered_card` | `boolean` | Did the user registered a credit card. | | `is_signup_merchant` | `boolean` | Did the user sign up to this merchant (rather than having a previously created account) | | `user_joined_at` | `timestamp` | The date the user created an account. This is in UTC. | | `user_entered_crm_at` | `timestamp` | The date the user was added to the database, regardless of whether they joined the loyalty program. This is in UTC. | | `email_last_opened_at` | `timestamp` | The date this user last opened an email. This is in UTC. | | `merchant_uid` | `string` | The unique identifier for the merchant in Thanx APIs. | | `user_uid` | `string` | The unique identifier for the user in Thanx APIs. | | `phone` | `string` | The user's phone number. This column will be empty unless the SMS opt-in consent was signed and enabled by Thanx staff. | | `alternate_pos_id` | `string` | An alternate user identifier sent to certain in-store POS systems when loyalty is applied at the register. Currently only used by the Toast POS integration, where it matches the `APPLIED_LOYALTY_ID` field on Toast POS reports. | # NPS Feedback Source: https://docs.thanx.com/data/models/nps-feedback The NPS feedback model includes [Net Promoter Score](https://www.netpromoter.com/know/) data for Thanx members leaving feedback on recent purchases. Sample nps\_feedback.csv Table name: `nps_feedback` ### Attributes | Column | Data Type | Description | | ------------------ | ----------- | --------------------------------------------------------------------------------------- | | `nps_feedback_uid` | `string` | The unique identifier for the feedback in Thanx APIs. | | `nps_feedback_id` | `string` | The unique identifier of the feedback in Thanx. | | `merchant_id` | `string` | The unique identifier of the merchant in Thanx. | | `purchase_id` | `string` | The unique identifier of the purchase in Thanx. | | `user_id` | `string` | The unique identifier of the user in Thanx. | | `state` | `string` | The state of the feedback. (`unviewed`, `viewed`, `rated`, `reviewed`, `responded`) | | `rating` | `number` | The NPS rating from 0-10. 0-6 are Detractors, 7-8 are Passives, and 9-10 are Promoters. | | `review` | `string` | The user’s written feedback. | | `response` | `string` | A staff member's written response to the user's feedback. | | `responded_by` | `string` | The name of the staff member who responded to the user. | | `created_at` | `timestamp` | The date and time the user was prompted to leave feedback. This is in UTC. | | `rated_at` | `timestamp` | The date and time the user left feedback. This is in UTC. | | `responded_at` | `timestamp` | The date and time a staff member responded to the user’s feedback. This is in UTC. | # Points Accounts Source: https://docs.thanx.com/data/models/points-accounts The points accounts model includes the current points balance of every active points account. Sample `points_accounts.csv` Table name: `points_accounts` ### Attributes | Column | Data Type | Description | | -------------------------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------- | | `points_account_id` | `string` | The unique identifier for the points accounts in Thanx. Can be mentioned as a debit\_ or credit\_account in Points Transactions report. | | `points_account_uid` | `string` | The unique identifier for the points account in Thanx APIs. | | `merchant_id` | `string` | The unique identifier of the merchant in Thanx. | | `user_id` | `string` | The unique identifier of the customer who owns the account. | | `owner_type` | `string` | Owner type of the account. (`merchant`, `user`) | | `balance` | `number` | The balance of points on the account. | | `points_program_currency` | `string` | The name of the point is configured for your points program. | | `points_program_conversion_rate` | `number` | The number of points customers collect for a qualifying action (e.g., every \$1 spent) as configured for your points program. | | `created_at` | `timestamp` | The date and time the points account was created. This is in UTC. | # Points Transactions Source: https://docs.thanx.com/data/models/points-transactions The points transaction model includes details of all events that resulted in points balance accrual or deducation for a given user. Sample `points_transactions.csv` Table name: `points_transactions` ### Attributes | Column | Data Type | Description | | ------------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `points_transaction_id` | `string` | The unique identifier of the points transaction in Thanx. This includes any action that results in a change of points balance, e.g. earning or redeeming points. | | `points_transaction_uid` | `string` | The unique identifier for the points transaction in Thanx APIs. | | `merchant_id` | `string` | The unique identifier of the merchant in Thanx. | | `user_id` | `string` | The unique identifier of the user in Thanx. | | `debit_account_id` | `string` | The unique identifier of the account where the points balance increased after the transaction. | | `credit_account_id` | `string` | The unique identifier of the account where the points balance is reduced after the transaction. | | `source_id` | `string` | The unique identifier of the source of the transaction. Use this ID to find the source of the transaction in the report mentioned in SOURCE\_TYPE. | | `source_type` | `string` | The source of the transaction. If it is empty when the reason is set to Third-party provisions. It indicates which report has the corresponding entry (use the ID in SOURCE\_ID to find the specific entry in the report mentioned as SOURCE\_TYPE). (`points transaction`, `program`, `purchase`, `reward`, `user`) | | `points_transaction_type` | `string` | The type of points transaction. | | | | `exchange` - User exchanged points for rewards. | | | | `issued` - User got points for a qualifying action (e.g., placing a purchase). | | | | `reverse` - User’s transaction was reversed (e.g., Clawbacks, Refunds). | | | | `adjust` - If a user’s balance falls below 0, it is adjusted until it is 0 since the user cannot have a negative balance. | | | | `import` - Merchant uploaded a balance (e.g., to apply progress from a previous program during transition). | | | | `expire` - Points expired. | | `reason` | `string` | The reason for the transaction to be created. (`account disabled`, `clawback`, `expiration`, `migration`, `program`, `purchase`, `refund / cancellation`, `reward`, `third-party provision`) | | `amount` | `number` | The number of points in the points transaction. | | `created_at` | `timestamp` | The date and time the points transaction was created. This is in UTC. | # Programs Source: https://docs.thanx.com/data/models/programs The program models includes basic information for both Thanx marketing campaigns and other non-campaign Thanx programs, like intro, vip, and points programs. Sample `programs.csv` Table name: `programs` ### Attributes | Column | Data Type | Description | | -------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------ | | `program_id` | `string` | The unique identifier of the program in Thanx. | | `program_uid` | `string` | The unique identifier for the program in Thanx APIs. | | `merchant_id` | `string` | The unique identifier of the merchant in Thanx. | | `redeem_title` | `string` | The title of the reward. This value is defined by the merchant when they create a reward template and visible to the consumer. | | `program_type` | `string` | The type of program that issues the reward. | | | | `automated campaign` | | | | `automated campaign - referral program` | | | | `birthday program` | | | | `exclusive deals` | | | | `feedback` | | | | `intro offer - premium` | | | | `intro offer - standard` | | | | `loyalty - incremental` | | | | `loyalty - points` | | | | `loyalty - spend` | | | | `loyalty - surprise and delight` | | | | `loyalty - visit` | | | | `one-time campaign` | | | | `one-time campaign - afternoon shoppers` | | | | `one-time campaign - close a location` | | | | `one-time campaign - evening shoppers` | | | | `one-time campaign - midday shoppers` | | | | `one-time campaign - morning shoppers` | | | | `one-time campaign - promote a location` | | | | `one-time campaign - reopen a location` | | | | `one-time campaign - vips` | | | | `one-time campaign - weekday shoppers` | | | | `one-time campaign - weekend shoppers` | | | | `reputation manager` | | | | `special offer` | | | | `special offer at a location` | | | | `vip program - spend` | | | | `vip program - visit based` | | | | `winback program` | | `handle` | `string` | The string that is used in the last section of the PROGRAM\_LINK to identify the offer. | | `program_link` | `string` | The url that the user must click to sign up for the reward (e.g. `https://thanx.com/merchant_handle/offer_handle`). | | `created_at` | `timestamp` | The date and time the program was created. This is in UTC. | # Purchases Source: https://docs.thanx.com/data/models/purchases The purchases made by your customers that have been detected by the Thanx platform. Sample `purchases.csv` Table name: `purchases` ### Attributes | Column | Data Type | Description | | ---------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | | `purchase_id` | `string` | The unique identifier for the purchase is Thanx. | | `purchase_uid` | `string` | The unique identifier for the purchase in Thanx APIs. | | `merchant_id` | `string` | The unique identifier of the merchant in Thanx. | | `user_id` | `string` | The unique identifier of the customer in Thanx. | | `card_id` | `string` | The unique identifier for the card used to place a purchase in Thanx. | | `order_id` | `string` | The ordering provider's unique identifier for the order associated with the purchase. | | `location_id` | `string` | The unique identifier for the location associated with the purchase. A location may not always be available. | | `location_name` | `string` | The name of the location associated with the purchase. This value is defined by the merchant. | | `location_street` | `string` | The street address of the location where the purchase is made. This value is defined by the merchant. | | `location_zip` | `number` | The zip code of the location where the purchase is made. This value is defined by the merchant. | | `location_category` | `string` | The category of the location where the purchase is made. This value is defined by the merchant and is relevant to Malls. | | `authorization_amount` | `number` | The purchase amount a merchant summits to the customer's issuing bank for approval. | | `settlement_amount` | `number` | The purchase amount the issuing bank transfers from the cardholder’s account to the payment processor, who then transfers the money to the acquiring bank. | | `channel` | `string` | The channel through which this purchase was made. (`digital`, `instore`) | | `purchased_at` | `timestamp` | The time and date that the customer made the purchase. This is in UTC. | | `pos_id` | `string` | POS ID of the order. Only present when a purchase is created via an in-store check-in for brands using POS check-in loyalty. | | `pos_provider` | `string` | POS provider of the order. Only present when a purchase is created via an in-store check-in for brands using POS check-in loyalty. | # Rewards Source: https://docs.thanx.com/data/models/rewards The rewards earned and redeemed by your customers. Sample `rewards.csv` Table name: `rewards` ### Attributes | Column | Data Type | Description | | ------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `reward_id` | `string` | The unique identifier of the reward in Thanx. | | `reward_uid` | `string` | The unique identifier for the reward in Thanx APIs. | | `merchant_id` | `string` | The unique identifier of the merchant in Thanx. | | `program_id` | `string` | The unique identifier of the program in Thanx. The program is what issues rewards. | | `user_id` | `string` | The unique identifier of the customer in Thanx. | | `earning_purchase_id` | `string` | The ID of the purchase that resulted in this reward reaching 100% progress. | | `redemption_purchase_id` | `string` | The ID of the purchase that is associated with this reward being redeemed. | | `redeem_title` | `string` | The title of the reward. This value is defined by the merchant when they create a reward template and visible to the consumer. | | `program_type` | `string` | The type of program that issues the reward. | | | | `automated campaign` | | | | `automated campaign - referral program` | | | | `birthday program` | | | | `exclusive deals` | | | | `feedback` | | | | `intro offer - premium` | | | | `intro offer - standard` | | | | `loyalty - incremental` | | | | `loyalty - points` | | | | `loyalty - spend` | | | | `loyalty - surprise and delight` | | | | `loyalty - visit` | | | | `one-time campaign` | | | | `one-time campaign - afternoon shoppers` | | | | `one-time campaign - close a location` | | | | `one-time campaign - evening shoppers` | | | | `one-time campaign - midday shoppers` | | | | `one-time campaign - morning shoppers` | | | | `one-time campaign - promote a location` | | | | `one-time campaign - reopen a location` | | | | `one-time campaign - vips` | | | | `one-time campaign - weekday shoppers` | | | | `one-time campaign - weekend shoppers` | | | | `reputation manager` | | | | `special offer` | | | | `special offer at a location` | | | | `vip program - spend` | | | | `vip program - visit based` | | | | `winback program` | | `state` | `string` | The state of the reward. (`active`, `delivered`, `fraudulent`, `pending use`, `refunded`, `retired`, `used`) | | `delivered_at` | `timestamp` | The time and date that the reward was delivered to the user. This is in UTC. | | `activated_at` | `timestamp` | The time and date that the user activated the reward. This is in UTC. | | `used_at` | `timestamp` | The time and date that the user used the reward. This is in UTC. | | `retired_at` | `timestamp` | The time and date that the reward expired (if it wasn’t used). This is in UTC. | | `expiration_at` | `timestamp` | The time and date this reward expires/expired. This is in UTC. | | `estimated_cost` | `number` | The estimated cost of the reward. This value is based on COGS defined by the merchant, or estimated margins. | | `discount` | `number` | The applied discount amount of the reward. When we have the exact discount amount via integrated redemption, this will be the exact amount discounted from the purchase. For some reward types with non-integrated redemption, this will be a value based on the estimate you provided when configuring the reward template in the merchant dashboard. | | `redemption_pos_order_id` | `string` | POS ID of the order with which this reward was redeemed. Set for merchants with in-store POS integrations enabled for rewards that were redeemed in-store. | | `redemption_pos_provider` | `string` | POS provider for the integrated in-store redemption. | # Overview Source: https://docs.thanx.com/data/overview The Thanx platform supports a variety of data export mechanisms. We are firm believers that data within the Thanx platform belongs to our customers. As a result, it's our responsibility to make it as easy to use as possible - both within the Thanx dashboard via tools and reporting as well as in downstream data systems. For access raw data from the Thanx platform, we provide the following access mechanisms: CSV files exported to an SFTP server Thanx data shared directly into your Snowflake account Structured data loaded directly into the destination of your choice [A changelog of data export schema adjustments can be found here](/data/changelog). ## SFTP Exports These exports are updated once every 24 hours and are a snapshot of the entire data set resident within the Thanx platform in CSV format. As an open data platform, the Thanx platform makes it easy for your team to get access to your data. This is available to all Thanx merchant customers. If you are an existing customer and would like to get access to this data, please reach out to your Thanx success manager directly and they can set this up. ### Export Formats SFTP exports are available in two formats: **Single-File Exports** * Standard CSV file format * Limited to 10 million most recent records per report * Ideal for manual analysis, reporting, and ad-hoc data exploration **Multi-File Exports** * Eliminates the 10 million record limit * Data is automatically split across multiple CSV files (up to 5GB each) * Files are organized in a folder structure with sequential numbering (e.g., `export_0.csv`, `export_1.csv`) * All files include headers for easy processing * Recommended for programmatic integrations and automated data pipelines To configure multi-file exports for your account, please reach out to your Thanx success manager. ## Snowflake Secure Data Sharing If you use Snowflake, Thanx can share your data directly into your Snowflake account using Snowflake's native secure data sharing. This is a direct Snowflake-to-Snowflake share — data is never copied, no external data-loading service is involved, and you always query the latest data Thanx has published. Because no external service is involved, **Thanx does not charge for Snowflake Secure Data Sharing.** This is distinct from Thanx Connex, which loads data through a managed service. Because Snowflake direct shares cannot cross regions or cloud platforms, this option is only available for Snowflake accounts on **AWS `us-east-1`** (the region of the Thanx provider account). Setup is a manual, one-time configuration. See the [Snowflake Secure Data Sharing](/data/snowflake-data-sharing) guide for requirements and setup steps. ## Thanx Connex Thanx has built support for fully managed loading of structured Thanx data directly into a variety of data destinations. Thanx Connex incurs pass-through fees of **\$300/mo per destination** to cover underlying technology services. | Destination | Destination Type | Link | | --------------------------------------------------------- | ---------------- | -------------------------------------------------------------------------------------------------------- | | [Snowflake](/data/connex/snowflake) | OLAP | [https://www.snowflake.com](https://www.snowflake.com) | | [BigQuery](/data/connex/bigquery) | OLAP | [https://cloud.google.com/bigquery](https://cloud.google.com/bigquery) | | [Redshift](/data/connex/redshift) | OLAP | [https://aws.amazon.com/redshift](https://aws.amazon.com/redshift) | | [DataBricks](/data/connex/databricks) | OLAP | [https://www.databricks.com](https://www.databricks.com) | | [Athena](/data/connex/athena) | OLAP | [https://aws.amazon.com/athena](https://aws.amazon.com/athena) | | [ClickHouse](/data/connex/click-house) | OLAP | [https://clickhouse.com](https://clickhouse.com) | | [Postgres](/data/connex/postgres) | OLTP | [https://www.postgresql.org](https://www.postgresql.org) | | [AWS Postgres](/data/connex/aws-postgres) | OLTP | [https://aws.amazon.com/rds/postgresql](https://aws.amazon.com/rds/postgresql) | | [MySQL](/data/connex/mysql) | OLTP | [https://www.mysql.com](https://www.mysql.com) | | [AWS MySQL](/data/connex/aws-mysql) | OLTP | [https://aws.amazon.com/rds/mysql](https://aws.amazon.com/rds/mysql) | | [SQL Server](/data/connex/sql-server) | OLTP | [https://www.microsoft.com/sql-server](https://www.microsoft.com/sql-server) | | [S3](/data/connex/s3) | Object Storage | [https://aws.amazon.com/s3](https://aws.amazon.com/s3) | | [S3 Compatible](/data/connex/s3-compatible) | Object Storage | [https://aws.amazon.com/s3](https://aws.amazon.com/s3) | | [Google Cloud Storage](/data/connex/google-cloud-storage) | Object Storage | [https://cloud.google.com/storage](https://cloud.google.com/storage) | | [Azure Blob Storage](/data/connex/azure-blob-storage) | Object Storage | [https://azure.microsoft.com/products/storage/blobs](https://azure.microsoft.com/products/storage/blobs) | | [Google Sheets](/data/connex/google-sheets) | Spreadsheet | [https://workspace.google.com/products/sheets](https://workspace.google.com/products/sheets) | This functionality allows your team to load data from Thanx directly into your destination of choice without having to worry about data pipeline tooling or data engineering work. This enables your data team to more quickly leverage this data within your existing data platform and rapidly integrate Thanx data into your organization's data ecosystem. Thanx manages creation of data schema, ongoing syncing of data, and fully managed schema management should there be any changes. ### Costs & Usage Thanx Connex has pass-through costs of ***\$300/mo per destination*** due to service provider costs necessary to facilitate this functionality. Currently, data is synced on a 24 hour basis. In the future, support for more frequent syncs will be considered depending on interest from customers. If you are an existing Thanx customer and would like to use this functionality, please reach out to your Thanx success manager directly and they can work with you on the specifics. ## Integration Partners Thanx supports bulk data sharing for integration partners. This allows for access to any mutual Thanx customer that agrees to data sharing. In order to facilitate this, a Master Data Agreement (MDA) must be in place and a merchant must grant explicit data access approval. If this is of interest, please reach out to our partnerships team at [partnerships@thanx.com](mailto:partnerships@thanx.com) for additional details. ## Models Follow the links below for detailed data model reference documentation: * [Campaigns](/data/models/campaigns) * [Communication Preferences](/data/models/communication-preferences) * [Memberships](/data/models/memberships) * [NPS Feedback](/data/models/nps-feedback) * [Points Accounts](/data/models/points-accounts) * [Points Transactions](/data/models/points-transactions) * [Programs](/data/models/programs) * [Purchases](/data/models/purchases) * [Rewards](/data/models/rewards) # Snowflake Secure Data Sharing Source: https://docs.thanx.com/data/snowflake-data-sharing Share Thanx data directly into your Snowflake account using Snowflake's native secure data sharing. Snowflake Secure Data Sharing lets Thanx share your data directly into your Snowflake account using Snowflake's native sharing capability. Data is shared account-to-account within Snowflake — no copying, no external pipeline, and no third-party data-loading service. This option is distinct from [Thanx Connex](/data/connex/setup). Connex loads data into a variety of destinations through a managed data-loading service, whereas Snowflake Secure Data Sharing is a direct Snowflake-to-Snowflake share. Because no external service is involved, **Thanx does not charge for Snowflake Secure Data Sharing.** ## How it works Thanx maintains your data in a Snowflake account and grants your Snowflake account access to a secure share. You create a database from that share in your own account and query it like any other database. Because the data is never duplicated, you always read the latest data Thanx has published, and you only pay Snowflake for the compute you use to query it. ## Requirements * [ ] **Snowflake account** — You must have your own Snowflake account that can consume a share (i.e., a standard Snowflake account, not a reader account provisioned by another provider). * [ ] **AWS `us-east-1` account** — Snowflake direct shares can only be made between accounts in the **same Snowflake region and cloud platform**. The Thanx provider account is on **AWS US East (N. Virginia), `us-east-1`**, so your Snowflake account must also be on **AWS `us-east-1`**. Accounts in other regions or on other cloud platforms (Azure, GCP) cannot consume the share — cross-region and cross-cloud sharing would require Snowflake replication or listings, which are outside the scope of this offering. * [ ] **Account identifier** — You will need to provide your Snowflake account identifier (organization and account name) so Thanx can add your account as a consumer of the share. * [ ] **`ACCOUNTADMIN` (or a role with `IMPORT SHARE` / `CREATE DATABASE` privileges)** — Creating a database from an inbound share requires sufficient privileges in your account. **Only AWS `us-east-1` is supported** Because direct shares cannot cross regions or cloud platforms, Thanx can only share data with Snowflake accounts hosted on **AWS `us-east-1`**. If your Snowflake account is in another region or on Azure or GCP, this option is not available — consider [Thanx Connex](/data/connex/setup) or [SFTP exports](/data/overview#sftp-exports) instead. **Confirming your region** To confirm the region and cloud platform of your Snowflake account, run: ```sql theme={null} SELECT CURRENT_REGION(); ``` The result must be `AWS_US_EAST_1` to be eligible for Snowflake Secure Data Sharing with Thanx. Share this value with your Thanx success manager before setup begins. ## Setup This is a manual, one-time configuration coordinated with your Thanx success manager. Let your success manager know you'd like to receive Thanx data via Snowflake Secure Data Sharing. Provide the output of `SELECT CURRENT_REGION();` and your Snowflake account identifier. The region must be `AWS_US_EAST_1` — Thanx can only share with accounts on AWS `us-east-1`. Thanx adds your account as a consumer of the secure share containing your Thanx data. In your Snowflake account, create a database from the inbound share. You can find the inbound share under **Data » Private Sharing**, or create the database directly: ```sql theme={null} -- list inbound shares to confirm the share is available SHOW SHARES; -- create a database from the inbound share CREATE DATABASE THANX_DATA FROM SHARE .; -- grant access to the roles that will query the data GRANT IMPORTED PRIVILEGES ON DATABASE THANX_DATA TO ROLE ; ``` Query the shared database like any other Snowflake database. Updates Thanx publishes to the share are reflected automatically — there is no sync delay from a copy step. # Create & Update Basket Source: https://docs.thanx.com/loyalty/create-update-basket POST https://loyalty.thanxsandbox.com/api/baskets This endpoint is used to notify Thanx of the states that a basket is in, apply rewards to the order, and accrue loyalty progress or points for the order. Integrating for the first time? Start with the [Basket Lifecycle & Troubleshooting guide](/overview/guides/basket-lifecycle) for behavioral context and common-mistake coverage. A basket can be in one of the following states: | State | Description | | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `checkout` | `required` Refers to any point before the order is placed. Any time the user updates their basket or rewards, Thanx expects to receive a request to check if discount information should be updated. | | `placed` | `required` Refers to when an order has been submitted to the system and a user can no longer modify their order through the website. If a reward is specified, the reward will be locked. If a points product is specified, the user's points balance will be deducted in exchange for specified reward and the reward will be locked. | | `billed` | `required` Refers to when the order has been trasmitted to the POS and the user's credit card has been charged. Any specified reward will be marked as used. Loyalty progress or points will be accrued upon receipt of this event. | | `completed` | `recommended` Refers to when the order has been made and transferred to the customer. | | `voided` | `recommended` Refers to an order that got canceled after entering the placed state and before entering the billed state. Any locked reward is restored to the user and available for future use. For rewards obtained through a points exchange (points products), the reward instance is finalized as refunded and the points are returned to the user's points balance — the user can re-exchange those points for a new reward. | | `refunded` | `recommended` Refers to an order being refunded / canceled any time after it enters the billed state. Any locked reward is restored to the user and available for future use. For rewards obtained through a points exchange (points products), the reward instance is finalized as refunded and the points are returned to the user's points balance — the user can re-exchange those points for a new reward. | Only a single reward, points product, or promo code can be applied per order. Supplying a promo code together with a reward or points product returns a 400. For more on the difference between locked rewards and points-product rewards when an order is voided or refunded, see [Loyalty Best Practices — Rewards vs Points Products](/consumer/best-practices/loyalty#rewards-vs-points-products). ```mermaid theme={null} flowchart LR Checkout --> Placed Placed --> Voided Placed --> Billed Billed --> Refunded Billed --> Completed Completed --> Refunded classDef default fill:transparent,stroke:#13c1bf,stroke-width:1px; ``` ## HTTP Request ### Parameters Basket unique ID. Partner-generated: your system creates this value and reuses it across every state transition for the same basket. Required for all states other than `checkout`. A `checkout` request may omit the ID; every subsequent state (`placed`, `billed`, `completed`, `voided`, `refunded`) must send the same ID the basket was created with. Basket state (`checkout`, `placed`, `billed`, `completed`, `voided`, `refunded`) When the order is wanted in **(ISO 8601 in UTC)**. If this timestamp is not provided, Thanx assumes the order is wanted ASAP. Providing this timestamp allows Thanx to determine if a reward will be valid in the future (for example, for a weekend only promotion where the user orders in advance). **Thanx Location UID** Providing this information allows Thanx to apply reward location restrictions. A mapping of Thanx location identifiers can be provided by the Thanx developer support team or fetched from the following endpoints depending on your integration type: * Consumer API [Get Locations](/consumer/locations/get-locations) endpoint. * Partner API [Get Locations](/partner/metadata/get-locations) endpoint. Reward IDs to apply to the basket. **These IDs must be obtained from the rewards field at the [Get Account API](/loyalty/get-account) response.** If you are integrating with reward codes, provide the reward code here instead. Currently only a single reward or points product can be applied to a basket. The request will 400 if multiple rewards or points products are specified in the request. Points Product IDs to apply to the basket. **These IDs must be obtained from the points\_products field at the [Get Account API](/loyalty/get-account) response.** Currently only a single reward or points product can be applied to a basket. The request will 400 if multiple rewards or points products are specified in the request. Universal Promo Code support is being rolled out and must be enabled for your account by Thanx before it can be used. Contact your Thanx representative to request access. A Universal Promo Code to apply to the basket, as a 1–64 character string. A promo code follows the same lifecycle as a reward: * `checkout` — the code is validated and the resulting `discount` is returned as a preview; nothing is redeemed yet. * `placed` / `billed` / `completed` — the discount is applied and the redemption is recorded (once per basket). * `voided` / `refunded` — any recorded redemption is released. A promo code cannot be combined with a reward or points product. Supplying both returns a 400 — apply one or the other, not both. A basket `id` is required when applying a promo code, and must be reused across every state update for the basket. The `id` keys the redemption and makes retries idempotent, so resending the same basket will not redeem twice. A member is not required to apply a promo code. If the basket is associated with a member, the order still accrues loyalty as usual; if it is not, the discount is applied and the redemption is recorded, but the order does not accrue loyalty (there is no member to credit). Array of payment methods Last 4 digits of the payment method Issuer of the payment method Required to generate the purchase and points to the user. Amount used with the payment method The timestamp of when the authorization was submitted to the issuer, in **ISO8601 format. The timestamp must be expressed in UTC.** Currently only a single object is supported. If multiple entries are provided, only the first will be validated and the rest will be ignored. Array of items Item ID in your system / POS Item name Item amount categories that describe this item Array of modifiers for this item Modifier ID in your system / POS Modifier name Modifier price adjustment Base price of the item before modifiers The subtotal of the basket in USD (before taxes & tips) Currently either `instore` or `online`, defaults to `online`. This is used to adjust which configured product IDs are returned in the applicable reward and points product entities. ### Response Response ID Basket state (`checkout`, `placed`, `billed`, `completed`, `voided`, `refunded`) Discount to apply ```bash Reward theme={null} curl https://loyalty.thanxsandbox.com/api/baskets \ -X POST \ -H "Authorization: Bearer ${token}" \ -H "Content-Type: application/json" \ -H "Accept: application/vnd.thanx-v1+json" \ -H "Merchant-Key: ${merchant_key}" \ -d '{ "id": "gwer-werwr-2134-rty", "state": "billed", "order_timestamp": "2019-05-08T18:02:05Z", "location_uid": "LG-567fhwer", "rewards": [ "fheTRR" ], "payments": [ { "issuer": "visa", "last4": "1234", "amount": 10.45, "authorized_at": "2019-05-07T18:02:05Z" } ], "items": [ { "id": "ng-23492", "name": "Cheese Pizza", "price": 9.95, "categories": [ "pizza", "vegetarian" ], "modifiers": [ { "id": "mod-123", "name": "Extra Cheese", "price": 1.50, "item_base_price": 8.45 } ] } ], "subtotal": 23.45 }' ``` ```bash Promo code theme={null} curl https://loyalty.thanxsandbox.com/api/baskets \ -X POST \ -H "Authorization: Bearer ${token}" \ -H "Content-Type: application/json" \ -H "Accept: application/vnd.thanx-v1+json" \ -H "Merchant-Key: ${merchant_key}" \ -d '{ "id": "order-abc-123", "state": "billed", "order_timestamp": "2026-06-08T18:02:05Z", "location_uid": "LG-567fhwer", "promo_code": "SUMMER10", "payments": [ { "issuer": "visa", "last4": "1234", "amount": 20.00, "authorized_at": "2026-06-07T18:02:05Z" } ], "items": [ { "id": "ng-23492", "name": "Cheese Pizza", "price": 20.00, "categories": [ "pizza" ] } ], "subtotal": 20.00 }' ``` ```json 201 theme={null} { "id": "fhwerwe-23663-ryryre", "state": "checkout", "discount": "10.25" } ``` ```bash 400 Invalid reward theme={null} { "code": 400, "message": "The reward was not found in our system" } ``` ```bash 400 Reward conflict theme={null} { "code": 400, "message": "A promo code cannot be combined with a reward or points product" } ``` ```bash 400 Invalid promo theme={null} { "code": 400, "message": "This promo code is not valid" } ``` ```bash 401 theme={null} { "code": 401, "message": "There was an error authenticating you." } ``` # Get Account Source: https://docs.thanx.com/loyalty/get-account GET https://loyalty.thanxsandbox.com/api/account This endpoint allows the retrieval of a user account information, including the user's rewards. ### Parameters Thanx Location UID. Providing this information allows Thanx to return rewards that can be used at this location. A mapping of Thanx location identifiers can be provided by the Thanx developer support team or fetched from the following endpoints depending on your integration type: * Consumer API [Get Locations](/consumer/locations/get-locations) endpoint. * Partner API [Get Locations](/partner/metadata/get-locations) endpoint. Currently either `instore` or `online`, defaults to `online`. This is used to adjust which configured product IDs are returned in the applicable reward and points product entities. Filter rewards by state. Valid values: `delivered`, `active`. Defaults to `delivered` if not provided. Multiple states can be specified to return rewards matching any of the specified states. ### Response The ID of user The user's email The user's rewards for the merchant specified in the header. This array can be empty. The Reward Identifier The value of the discount, present for 'amount' and 'percent' types The minimum spend for this reward, if applicable The maximum discount possible for this reward, if applicable The reward description The state of the reward (`redeemable`, `unredeemable`) The type of reward (`amount`, `percent`, `item`) POS Identifiers for items this discount applies to, if applicable Any fine print for the reward. Time the reward will be automatically retired in ISO8601-format if a retire date is set The list of locations the reward can be redeemed. For conditional rewards (e.g. BOGO / "buy X get Y"), `products` lists only the items the reward **discounts**, not the items required to **trigger** it, and there is no field distinguishing conditional from simple rewards. To confirm eligibility for these, send a `checkout` basket and read the returned `discount`. Some rewards may also return `type: fixed_price`. Reward IDs are not stable references — a reward leaves this list once it is used, expired, or retired. Pull a fresh `GET /account` immediately before submitting a basket and use the current `rewards[].id`; a stale ID returns a not-found error at `POST /baskets`. The merchant's configured points product available for online redemption. This array can be empty. The points product ID The points experience ID The amount of points of the given currency this points product costs The value of the discount, present for 'amount' and 'percent' types The minimum spend for the reward this points product can be exchanged for, if applicable. The maximum discount possible for the reward this points product can be exchanged for, if applicable. The description of the reward this points product can be exchanged for The state of the points product (`redeemable`, `unredeemable`). This will be `redeemable` if the user has enough points for this points product and `unredeemable` if the user does not have enough points for this points product. The type of reward (`amount`, `percent`, `item`) that this points product can be exchanged for. POS Identifiers for items the discount applies to, if applicable Any fine print for the reward this points product can be exchanged for. The list of locations the points product can be redeemed. A user's progress toward their next loyalty reward Only present for merchants that have not yet upgraded to points Percent progress toward the next loyalty reward Description of progress toward the next loyalty reward Array of information about the configured points experiences and the current user's balance at each Only present for merchants that have enabled points ID of the points experience. This matches the IDs of the points experiences returned in [GET /points\_experiences](/consumer/points/get-experiences). The points experience's currency name The plural tense of the points experience's currency name The user's current currency balance of the points experience ```bash theme={null} curl https://loyalty.thanxsandbox.com/api/account \ -H "Authorization: Bearer ${token}" \ -H "Content-Type: application/json" \ -H "Accept: application/vnd.thanx-v1+json" \ -H "Merchant-Key: ${merchant_key}" \ -G \ --data-urlencode "location_id=${location_id}" \ --data-urlencode "redemption_venue=online" \ --data-urlencode "reward_states[]=delivered" \ --data-urlencode "reward_states[]=active" ``` ```json 200 theme={null} { "id": "wer23gtTT", "email": "john.smith@example.com.com", "rewards": [ { "id": "gheTfR", "value": 10, "minimum": 20, "maximum": 20, "label": "A free hamburger", "state": "redeemable", "type": "amount", "products": ["234234-23423423", "3458-345345"], "fine_print": "Reward fine print", "retire_at": "2020-05-01T20:00:00Z", "restriction_location_ids": ["a", "b"] } ], "points_products": [ { "id": "9xw6543wh8jmde0", "points_experience_id": "590485d6f0", "points": 10, "value": 10, "minimum": 20, "maximum": 20, "label": "Onion rings", "state": "redeemable", "products": ["234234-23423423", "3458-345345"], "fine_print": "Points product fine print", "restriction_location_ids": ["a", "b"] } ], "progress": { "percentage": 20, "towards": "$5 off next purchase" }, "points": [ { "points_experience_id": "590485d6f0", "currency": { "name": "Star", "plural": "Stars" }, "balance": 10.0 } ] } ``` ```bash 401 theme={null} { "code": 401, "message": "There was an error authenticating you." } ``` # Headers Source: https://docs.thanx.com/loyalty/headers All Ordering / Loyalty integration API endpoints described below must include the following headers. | Header | Type | Required | Description | | ------------------------- | ------ | ----------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Authorization` | string | Required unless `Reward-Redemption-Token` is supplied | All Thanx Loyalty API endpoints are protected and must be authorized via end user access tokens. These access tokens can be retrieved through an integration with Thanx SSO. The format of the header should be: `Bearer access_token` | | `Content-Type` | string | Required | The only accepted value is `application/json` | | `Accept` | string | Required | The Accept header specifies which version of the Thanx API that should be used. The current version is `v1` for the vendor `thanx`. This header is required for every request. The value should be` application/vnd.thanx-v1+json`. Thanx will notify you when a new API version is available. | | `Merchant-Key` | string | Required | The Merchant key header identifies the merchant in Thanx. The value for this key will be provided to you by Thanx. | | `User-Agent` | string | Required | eg. `{partner}/1.0.0`. This value should be set to something that indicates the name of the partner. This is useful for debugging purposes. | | `Reward-Redemption-Token` | string | Optional | Token for reward redemption. | Send `Reward-Redemption-Token` only for token-only redemption flows (no user `Authorization` Bearer). When you authenticate with a Bearer token, **omit this header**. If it is present, the basket call returns `404` when the merchant does not have indirect loyalty integration enabled, or `401` when the token does not resolve to a reward. # Overview Source: https://docs.thanx.com/loyalty/overview This API is designed to provide **POS, online ordering, and kiosk providers** the ability to integrate Thanx Loyalty into their ordering systems - reward redemption & loyalty points accrual. This API provides a way to retrieve a user's rewards and apply discounts to their basket. An online ordering platform with a shared restaurant customer can integrate with these APIs to allow Thanx users to both use their discounts while placing digital orders and accrue points progress while doing so. * The `GET /account` endpoint provides a user's available rewards. * The `POST /baskets` endpoint computes a discount and marks rewards or points product as used in the Thanx system. * Ordering partners are expected to apply the discounts returned by this endpoint if a reward or points product was specified. * Finalized baskets automatically accrue points for the authenticated user. ## Environments The Loyalty API is served from a dedicated subdomain in each environment: | Environment | Base URL | | ----------- | --------------------------------------- | | Sandbox | `https://loyalty.thanxsandbox.com/api/` | | Production | `https://loyalty.thanx.com/api/` | All examples in this reference use the sandbox base URL. Swap in the production URL once your integration has been certified and production credentials have been issued. ## Certification Once your integration has been built and developed against the sandbox environment, please reach out to [developer.support@thanx.com](mailto:developer.support@thanx.com) go through a lightweight but mandatory certification process. For basic integration use-cases, certification is quick and normally takes no more than a few days depending on the scope of integration. This process is mainly designed to ensure the integration is working as intended without risking any negative impact on live customers (merchant or consumer). Each net new integration use-case should be re-certified as new use-cases will very likely require different scoping. Launching new merchants on certified integration use-cases does not require re-certification. The certification process will start with a video call with members of our developer support team. On the call, your team will demo the integration and all the supported use-cases. After the demo of all support use-cases, our team will validate the following: ### 1 - **Interactions** 1. authentication 2. loyalty lookup, such as reward or points product 3. order submission with or without loyalty redemption 4. walk through examples of all supported loyalty types: * reward redemption workflow: * amount off rewards * item-based rewards * points redemption workflow: * amount off points products * item-based points products 5. error message handling ### 2 - **API** 1. requests must include all [required headers](/loyalty/headers) 2. requests must not be unnecessarily duplicated 3. error messages should be displayed to the user 4. requests should only be issued on a reasonable frequency and in response to end-user interactions (e.g. Don't rapidly poll the API for changes) ### 3 - **Product Capabilities** The following product capabilities are **non-negotiable** within our platform and must be supported in your POS–Kiosk integration. These features are crucial to the Thanx user experience. 1. **Reward Redemption** Users must be able to look up their available rewards (via the [Get Account](/loyalty/get-account) endpoint). They must also be able to redeem these rewards (via the [Create or Update Basket](/loyalty/create-update-basket) endpoint). 2. **Points Product Exchange** Users must be able to view the products they are eligible to exchange based on their points balance (via the [Get Account](/loyalty/get-account) endpoint). They must also be able to submit those products as part of their basket to complete the exchange (via the [Create or Update Basket](/loyalty/create-update-basket) endpoint). 3. **Refunds** Users must be able to request refunds for their transactions if needed. (via the [Create or Update Basket](/loyalty/create-update-basket) endpoint). Refunds should be handled at the POS, ensuring that: * Any redeemed rewards are restored. * Any exchanged point products are reverted, and the corresponding points are credited back to the user. 4. **Automated Location Mapping** To ensure accurate tracking of purchases per location and proper filtering of location-specific rewards, baskets must be submitted with the correct **Thanx Location ID** in the `location_uid` attribute as specified [here](/loyalty/create-update-basket#param-location-uid). To simplify this process, you can automate the mapping of your own location IDs to Thanx Location IDs by using the [Get Locations](/partner/metadata/get-locations) endpoint from the Partner API. This allows your system to asynchronously communicate with the Thanx API, keeping location data up to date and ensuring seamless internal mapping between your locations and Thanx locations. ### Product Guide ## Postman API Collection Here you will find the **Loyalty API Postman Collection** to import directly within your API testing tool. This collection is already completed and includes sample values for the credentials. Please replace them with the ones provided by your Thanx representative in order to achieve successful API calls. Download Postman Collection # AWS PrivateLink Source: https://docs.thanx.com/loyalty/private-link Connect to Thanx Loyalty APIs over AWS PrivateLink Thanx exposes AWS PrivateLink endpoints in **us-east-1**. If you need to route Thanx traffic in the same region, follow these steps to set up your endpoint. ## Prerequisites * Access to AWS Management Console * VPC with subnets in **us-east-1** region * Appropriate IAM permissions to create VPC endpoints ## Setup Instructions ### 1. Request AWS Account Whitelisting Before creating the VPC endpoint, you must first get your AWS account whitelisted in Thanx's VPC endpoint security group: 1. Contact Thanx support with your AWS Account ID. 2. Request whitelisting for the Thanx Loyalty API PrivateLink service. 3. Wait for confirmation that your account has been whitelisted before proceeding to the next step. ### 2. Create the VPC Endpoint 1. Connect to the AWS Management Console and navigate to the **us-east-1** region. 2. From the VPC Dashboard, under **PrivateLink and Lattice**, select **Endpoints**. 3. Click **Create Endpoint**. 4. Select **Endpoint services that use NLBs and GWLBs**. 5. Fill in the Service Name with the Thanx Loyalty API service based on your environment: **Production:** ``` com.amazonaws.vpce.us-east-1.vpce-svc-022a091b834e98f58 ``` **Sandbox:** ``` com.amazonaws.vpce.us-east-1.vpce-svc-027f0062cef1fd3fd ``` 6. Click **Verify service**. If this does not return "Service name found", contact Thanx support. 7. Choose the VPC and subnets that should connect to the Thanx VPC service endpoint. 8. Choose the security group to control traffic to this VPC endpoint. The security group must accept inbound traffic on TCP port 443. 9. **Do not** enable the DNS name option yet. Leave "Enable DNS name" unchecked for now. 10. Click **Create endpoint** at the bottom of the screen. ### 3. Request Thanx Approval After creating the VPC endpoint: 1. Note your VPC endpoint ID from the AWS console. 2. Contact Thanx support with the following information: * Your VPC endpoint ID * Confirmation that you've created the endpoint for the loyalty API service 3. Wait for Thanx to approve your endpoint connection request. This approval is required before the endpoint becomes functional. ### 4. Enable DNS Name Once Thanx has approved your endpoint: 1. Return to the VPC Endpoints page in the AWS console. 2. Select your endpoint and click **Actions** > **Modify private DNS name**. 3. Under **Enable private DNS names**, check **Enable for this endpoint**. 4. Click **Save changes**. ### 5. Test Connection After DNS is enabled, you can route traffic to Thanx APIs using the private DNS name for your environment: **Production:** ``` privatelink-offer.thanx.com ``` **Sandbox:** ``` privatelink-offer.thanxsandbox.com ``` Your requests to Thanx Loyalty APIs will now route through the private connection instead of the public internet. ## Troubleshooting * If the service name verification fails, ensure you're in the us-east-1 region and contact Thanx support. * If connections fail after setup, verify your security group allows outbound HTTPS traffic on port 443. * Ensure your endpoint status shows as "Available" before testing connections. # Postman API Collections Source: https://docs.thanx.com/overview/api_collections Here you will find links to dedicated Postman API collections that will guide you through testing the Thanx API and integrating seamlessly with our services. Consumer API Postman Collection Partner API Postman Collection Loyalty API Postman Collection POS - Kiosk Integration Postman Collection App - Web Customer Experience Postman Collection ## Support If you need support with your integration, please contact us at [developer.support@thanx.com](mailto:developer.support@thanx.com). # Basket Lifecycle & Troubleshooting Source: https://docs.thanx.com/overview/guides/basket-lifecycle This guide explains how the Thanx basket lifecycle works end-to-end and how to diagnose the most common integration problems. It complements the [Create & Update Basket](/loyalty/create-update-basket) endpoint reference with the behavioral context that most integrations need to pass certification on the first attempt. **Who this is for:** * Partners integrating the Loyalty API directly (POS, kiosk, online ordering) * Anyone troubleshooting missing points, \$0 discounts, or unexplained basket behavior **What you'll learn:** * How a basket moves through its states and what the API does at each transition * Which fields drive points accrual, and when they must be sent * The three most common integration mistakes and how to fix them * How to debug a basket that returned 201 but produced no purchase ## The Basket State Machine A basket is an object partners manage across several API calls. Each call updates the basket's state, and points are only accrued at a specific transition. For the full state diagram, see the [Create & Update Basket](/loyalty/create-update-basket) endpoint reference. | State | When to send | What Thanx does | Required? | | ----------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | | `checkout` | Any time the user modifies the basket or rewards pre-submission | Validates reward eligibility, returns updated discount amounts | Required | | `placed` | Order has been submitted; user can no longer modify | Locks the reward; if using a points product, deducts the user's points balance | Required | | `billed` | POS charged the card / payment was captured | **Creates the purchase and accrues points.** Reward is marked used. | Required | | `completed` | Order handed to the customer | Finalizes the order record | Recommended | | `voided` | Order canceled between `placed` and `billed` | Re-delivers locked reward; points products are not re-credited but reward stays available | Recommended | | `refunded` | Order canceled after `billed` | Immediately re-delivers the locked reward, and enqueues a deferred clawback of **accrued loyalty points** for the associated purchase. Points-product balances are not automatically re-credited. | Recommended | Points are only created at `billed`. If your POS never transitions to `billed`, no purchase is created and no points accrue — even if `checkout` and `placed` succeeded. ## Three Concepts Every Integration Must Get Right ### 1. Basket ID is partner-generated The `id` field in the basket payload is an identifier **your system** creates. Thanx does not return a new ID — you reuse the same value across every state transition so the API can correlate the updates to a single basket. * Generate once when the user starts checkout. * Reuse for every subsequent request (`placed`, `billed`, `completed`, etc.). * Only `checkout` requests may omit the ID; every other state requires it. A common mistake is interpreting the endpoint reference ("Basket ID is not required when submitting a basket with 'checkout' state") to mean the API assigns the ID. It does not. If you generate a new ID for each request, each basket is treated as a separate order and points will not accrue correctly. ### 2. `payments[].amount` drives points accrual — not `items[]` or the grand total Points are calculated from the sum of `payments[].amount` values on the `billed` request. The formula is: ``` payments[].amount = subtotal + tax - discounts ``` This means: * Include tax; exclude tips. * Do not send the order's grand total (which includes tips). * Do not send the items total (which doesn't account for discounts or tax). * A gift-card **load/reload** is not a purchase — exclude it, so a load-only transaction is correctly \$0 loyalty-eligible. Paying **with** a gift card is a normal purchase and stays eligible. If `payments` is missing or empty on the `billed` request, no purchase is created. The API will return 201 but nothing lands downstream. ### 3. `items[].price` must include modifier prices When you send items, the `price` for each item must be the final item price including any modifiers (base price + modifier prices). Sending `price: 0` or the base-only price causes item-level discount rewards to calculate a \$0 discount. | Scenario | Correct `price` | | ----------------------------------- | --------------- | | Burger ($10) + Extra cheese ($1.50) | `11.50` | | Coffee (\$4) + no modifiers | `4.00` | | Combo ($15) with drink upgrade ($2) | `17.00` | ## Endpoint URLs: Sandbox vs. Production The Loyalty API lives on a dedicated subdomain. Using the wrong base URL returns 404s or routes to an unrelated service that will not accept basket requests. | Environment | Base URL | | ----------- | --------------------------------------- | | Sandbox | `https://loyalty.thanxsandbox.com/api/` | | Production | `https://loyalty.thanx.com/api/` | Do not use `https://api.thanxsandbox.com/loyalty/*` — it's a different path that is not a supported entry point for basket requests. ## Required Headers See [Loyalty API Headers](/loyalty/headers) for the full list. Two headers cause the majority of "why are my baskets silently lost" tickets: * **`Merchant-Key`** — the merchant hashid (e.g., `example-hashid-from-your-rep`), not the numeric merchant ID. Sending a numeric ID (or any value that isn't a valid hashid) returns `401 "The Merchant-Key header is missing or invalid"` — no basket or purchase is created. Your Thanx representative provides the correct key during onboarding. * **`User-Agent`** — must identify your integration; some auth paths reject generic values. Send the **same** `Merchant-Key` on every state transition, and make sure it matches the merchant your end-user token is authenticated against. A `Merchant-Key` that resolves to a different merchant than the token is rejected with `401` — so a shared or multi-brand storefront that sends the wrong brand's key on `billed` sees that call fail rather than silently accruing to the wrong merchant. ## Sandbox Testing: Expected Latency Sandbox purchase processing is noticeably slower than production. Delays of several minutes up to tens of minutes between a successful `billed` request and the purchase appearing in `GET /account` responses are common based on observed partner testing. Production is near real-time. Before reporting "points not accruing" in sandbox, wait and re-check after tens of minutes. Most "missing points" sandbox tickets resolve themselves once the worker catches up. ## Troubleshooting ### Symptom: `billed` returns 201 but no purchase appears | Likely cause | How to verify | Fix | | -------------------------------- | ------------------------------------------------------------------------------ | ---------------------------------------------------------------------------- | | Wrong `Merchant-Key` header | Check the header value sent against the one your Thanx representative provided | Use the hashid, not the numeric merchant ID | | Missing `payments[]` on `billed` | Inspect the request body — is `payments` present and non-empty? | Include `payments` with `amount`, `last4`, `issuer` | | Sandbox latency | Confirm time since request | Re-check after tens of minutes; sandbox processing is slower than production | | Wrong base URL | Check outgoing URL | Use `loyalty.thanxsandbox.com/api/`, not `api.thanxsandbox.com/loyalty/` | ### Symptom: Item-level reward discount is \$0 | Likely cause | How to verify | Fix | | ------------------------------------------------------ | ------------------------------------------------ | ------------------------------ | | `items[].price` does not include modifier prices | Compare sent `price` against POS receipt | Send base + modifier total | | `items[].id` mismatches the reward template's item IDs | Compare against the reward template's `products` | Use the exact IDs Thanx issued | ### Symptom: Points accrue for the wrong amount | Likely cause | How to verify | Fix | | -------------------------------------------- | ------------------------------------------------ | --------------------------------- | | `payments[].amount` includes tips | Compute `subtotal + tax - discounts` and compare | Send `subtotal + tax - discounts` | | `payments[].amount` excludes tax | Same as above | Same | | `payments[].amount` reflects the grand total | Same as above | Same | ### Symptom: Basket ID keeps changing between calls Your system is generating a new UUID per request instead of reusing the one from `checkout`. Generate the ID once when checkout starts, persist it, and send the same value on every state transition. ## Before You Certify Use the Pre-Certification Self-Check checklist for your integration type ([POS/Kiosk](/overview/guides/pos-kiosk), [Consumer UX](/overview/guides/consumer-ux), [Pay-at-Table](/overview/guides/pay-at-table)) to confirm your basket flow is correct before submitting for certification. The checklist mirrors the scenarios in this guide. ## Related Pages * [Create & Update Basket (endpoint reference)](/loyalty/create-update-basket) * [Loyalty API Headers](/loyalty/headers) * [Loyalty API Overview](/loyalty/overview) * [Loyalty Models Overview](/overview/loyalty-models) * [POS/Kiosk Integration Guide](/overview/guides/pos-kiosk) # Campaign & Reward Issuance Source: https://docs.thanx.com/overview/guides/campaign-reward-issuance # Overview This guide explains how to integrate **partner-initiated campaign creation and reward issuance** using the Thanx Partner API. This integration allows partners to programmatically create campaigns, configure reward variants, and issue rewards to users — all from within their own platform. Common use cases include feedback-driven service recovery, automated marketing triggers, loyalty activation based on external events, and CRM-driven reward distribution. The integration is entirely **server-to-server**. Partners trigger reward issuance on behalf of merchants by identifying users via email or phone number. By building to these endpoints, partners can deliver a unified workflow where merchants no longer need to switch between systems to act on insights and issue rewards. This reduces friction, speeds up execution, and creates a tighter feedback loop between partner platforms and Thanx loyalty. *** ## Credentials You Will Need For this kind of integration, you will be provided the following credentials: * **Client ID** * **Access Token** These credentials grant access to all merchants that have explicitly opted into the specified integration. All merchants accessible to these credentials can be listed via the [Get Merchants](/partner/metadata/get-merchants) endpoint. Each API credential is configured with an agreed upon scope — granting access to a subset of the API endpoints available. The campaign and reward issuance endpoints require the `rewards.issue` scope. Use the [Get Scopes](/partner/metadata/get-scopes) endpoint to verify which scopes your credentials have access to. *** ## Endpoints We Will Be Using The following endpoints are the minimum required for this integration: 1. [List Reward Templates](/partner/reward-templates/list-reward-templates) — Discover available reward templates for a merchant 2. [Create Campaign](/partner/campaigns/create-campaign) — Create a campaign with reward variants 3. [Issue Rewards](/partner/campaigns/issue-rewards) — Issue rewards to users by email or phone 4. [Get Issuance Job](/partner/issuance-jobs/get-issuance-job) — Poll for issuance job completion status *** ## Postman API Collection Here you will find the **Partner API Postman Collection** to import directly within your API testing tool. This collection includes sample values for credentials. Replace them with those provided by your Thanx representative to ensure successful API calls. [Partner API Postman Collection](https://docs.thanx.com/overview/api_collections) *** ## API Interaction Workflow ```mermaid theme={null} flowchart LR A["List Reward Templates"] --> B["Create Campaign"] B --> C["Issue Rewards"] C --> D["Get Issuance Job"] D -->|"pending / processing"| D D -->|"completed"| E["Done"] D -->|"failed"| F["Handle Errors"] classDef default fill:transparent,stroke:#13c1bf,stroke-width:1px; ``` *** ## Integration Flow ### 1 — Discovery Before creating campaigns or issuing rewards, the partner must discover which merchants are accessible and what reward templates each merchant has published. Call the [Get Merchants](/partner/metadata/get-merchants) endpoint to retrieve the list of merchants that have opted into the integration. For each merchant, call the [List Reward Templates](/partner/reward-templates/list-reward-templates) endpoint to retrieve available reward templates. These templates define the types of rewards that can be issued (e.g., "Free Coffee", "\$5 Off Next Visit"). Merchant and reward template data should be **cached** and refreshed periodically rather than fetched on every operation. **Endpoints used in this step:** 1. [Get Merchants](/partner/metadata/get-merchants) Lists all merchants accessible to the integration partner. 2. [List Reward Templates](/partner/reward-templates/list-reward-templates) Returns published reward templates for a given merchant. 3. [Get Reward Template](/partner/reward-templates/get-reward-template) *(Optional)* Returns details of a specific reward template. *** ### 2 — Campaign Creation A campaign defines the time window, terms, and reward variants for issuing rewards to users. Each campaign must have between 1 and 4 variants. **Treatment variants** specify a `reward_template_id` that defines the reward to be issued. **Control variants** (named "Control") do not require a `reward_template_id` and are used for A/B testing — measuring the impact of rewards versus no reward. The partner provides the following when creating a campaign: * `merchant_id` — The merchant the campaign belongs to * `name` — Campaign name (e.g., "Service Recovery - Negative Feedback") * `objective` — Campaign objective (e.g., "Re-engage guests after poor experience") * `fine_print` — Terms and conditions * `start_at` / `end_at` — Campaign active window (ISO8601) * `redeemable_from` / `redeemable_to` — When issued rewards can be redeemed (ISO8601) * `variants` — Array of 1–4 variants, each with a `name` and optional `reward_template_id` Campaigns can be created **once per use case** (e.g., one for service recovery, one for VIP rewards) and reused for multiple issuance jobs, or created on-the-fly per event depending on the partner's workflow. **Endpoints used in this step:** 1. [Create Campaign](/partner/campaigns/create-campaign) Creates a new partner-initiated campaign with reward variants for a merchant. 2. [List Campaigns](/partner/campaigns/list-campaigns) *(Optional)* Lists all active partner-initiated campaigns for a merchant. 3. [Get Campaign](/partner/campaigns/get-campaign) *(Optional)* Retrieves details of a specific campaign. *** ### 3 — Reward Issuance This is the core action. When the partner's platform determines that a user should receive a reward (e.g., a guest left negative feedback, a VIP guest made a purchase), it calls the [Issue Rewards](/partner/campaigns/issue-rewards) endpoint. Rewards are issued by identifying users via **email** or **phone number**. Phone numbers must be in E.164 format (e.g., `+12025551234`). Up to **10,000 identifiers** can be submitted per issuance job. The endpoint initiates an **asynchronous** job and returns immediately with a `202 Accepted` response containing the issuance job ID. Rewards are processed in the background. Use the `X-Idempotency-Key` header to prevent duplicate issuance jobs if the same request is retried. **Endpoints used in this step:** 1. [Issue Rewards](/partner/campaigns/issue-rewards) Initiates an asynchronous reward issuance job for a given campaign variant. *** ### 4 — Monitoring & Completion After initiating an issuance job, the partner should poll the [Get Issuance Job](/partner/issuance-jobs/get-issuance-job) endpoint to track progress. Job states progress as follows: `pending` → `processing` → `completed` or `failed`. When the job reaches the `completed` state, a `summary` field is included with: * `success_count` — Number of rewards successfully issued * `failure_count` — Number of failed issuances * `failures` — Array of failure details including `identifier_index`, `identifier_type`, and `error` message Partners should surface success and failure information to merchants as appropriate. **Alternatively**, instead of polling, partners can subscribe to webhooks (see below). **Endpoints used in this step:** 1. [Get Issuance Job](/partner/issuance-jobs/get-issuance-job) Returns the current status of a reward issuance job. *** ### 5 — Revocation (If Needed) If rewards were issued in error (e.g., fraudulent feedback, incorrect campaign), the partner can revoke all rewards from a given issuance job. Only issuance jobs in a `completed` or `failed` state can be revoked. Jobs that are `pending` or `processing` will return a `422` error. Jobs that are already `revoking` or `revoked` will also return a `422` error. Revocation is processed asynchronously. The endpoint returns `202 Accepted` and the job transitions to a `revoking` state while rewards are being revoked in the background. **Endpoints used in this step:** 1. [Revoke Issuance Job](/partner/issuance-jobs/revoke-issuance-job) Revokes all rewards issued by a given issuance job. *** ## Webhooks (Optional) Instead of polling with the [Get Issuance Job](/partner/issuance-jobs/get-issuance-job) endpoint, partners can subscribe to webhooks for real-time notifications. | Webhook | When It Fires | | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [reward.issued](/webhooks/reward-issued) | Each time an individual reward is successfully issued to a user during an issuance job. If a batch contains 100 identifiers, up to 100 individual `reward.issued` webhooks may be sent. | | [reward.batch\_completed](/webhooks/reward-batch-completed) | Once when an entire issuance job finishes processing. Includes a summary of the batch with total counts and any failures. Fires regardless of whether all rewards succeeded or some failed. | To have webhooks enabled, reach out to [developer.support@thanx.com](mailto:developer.support@thanx.com). **Webhook requirements:** * Endpoint must be a valid HTTPS URL * Must respond to POST requests within **15 seconds** * Webhooks are not configured to retry by default — any missed data can be collected via bulk data transfer mechanisms *** ## Rate Limits Integration partners should not exceed a rate of **5 requests per second** and **2,000 requests per 15 minutes**. These are hard limits and the API will return `429 Too Many Requests` once exceeded. Rate-limited requests can and should be retried. One such strategy is through an **exponential backoff** approach. Should your specific integration use-case require higher API throughput, please reach out to [developer.support@thanx.com](mailto:developer.support@thanx.com) to request an increase. *** # Certification Once your integration has been built and developed against the sandbox environment, please reach out to [developer.support@thanx.com](mailto:developer.support@thanx.com) to go through a lightweight but mandatory certification process. **Before submitting for certification**, download and complete the self-check checklist to verify your integration meets all requirements. This reduces back-and-forth during certification and helps ensure a first-attempt pass. Download Campaign & Reward Issuance Pre-Certification Self-Check For basic integration use-cases, certification is quick and normally takes no more than a few days depending on the scope of integration. This process is mainly designed to ensure the integration is working as intended without risking any negative impact on live customers (merchant or consumer). Each net new integration use-case should be re-certified as new use-cases will very likely require different scoping. Launching new merchants on certified integration use-cases does not require re-certification. The certification process will start with a video call with members of our developer support team. On the call, your team will demo the integration and all the supported use-cases. After the demo of all supported use-cases, our team will validate the following: ## **Interactions** 1. Discovery: retrieving merchants and reward templates 2. Campaign creation with appropriate variants 3. Reward issuance to users by email and/or phone 4. Issuance job monitoring (polling or webhook-based) 5. Error handling for failed issuances 6. Revocation workflow (if applicable) ## **API** 1. Requests must include all required headers (`Authorization`, `X-ClientId`, `Accept-Version`, `Content-Type`, `User-Agent`) 2. Requests must not be unnecessarily duplicated 3. Idempotency keys should be used for reward issuance requests 4. Error messages should be handled gracefully 5. Requests should only be issued at a reasonable frequency (e.g., don't rapidly poll the API for changes) ## **Product Capabilities** The following product capabilities must be supported in your campaign and reward issuance integration: ### **Campaign Configuration** Partners must be able to create campaigns with appropriate time windows, terms, and reward variants. Campaigns must reference valid reward templates retrieved from the [List Reward Templates](/partner/reward-templates/list-reward-templates) endpoint. ### **Reward Issuance** Partners must be able to issue rewards to users by email or phone number via the [Issue Rewards](/partner/campaigns/issue-rewards) endpoint. Partners should handle the asynchronous nature of issuance jobs by either polling the [Get Issuance Job](/partner/issuance-jobs/get-issuance-job) endpoint or subscribing to webhooks. ### **Error & Failure Handling** Partners must gracefully handle issuance failures. When an issuance job completes with failures, the partner should surface relevant error information (e.g., invalid email, user not found) and should not silently drop failed issuances. ## Product Guide *** # Additional Endpoints to Enhance the Experience | Endpoint | Purpose | | ------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------- | | **[Get Merchants](/partner/metadata/get-merchants)** | Retrieve the list of merchants accessible to the integration. Use this to populate merchant selection in your platform. | | **[Get Locations](/partner/metadata/get-locations)** | Retrieve locations for accessible merchants. Useful if your platform operates at the location level rather than the merchant level. | | **[Get Scopes](/partner/metadata/get-scopes)** | Verify which API scopes your credentials have access to. Useful for onboarding diagnostics. | | **[Get Reward Template](/partner/reward-templates/get-reward-template)** | Retrieve details of a specific reward template. Useful for displaying reward information to merchants in your platform. | | **[List Campaigns](/partner/campaigns/list-campaigns)** | List all active partner-initiated campaigns for a merchant. Useful for campaign management dashboards. | | **[Get Campaign](/partner/campaigns/get-campaign)** | Retrieve details of a specific campaign. Useful for displaying campaign status and configuration. | | **[Revoke Issuance Job](/partner/issuance-jobs/revoke-issuance-job)** | Revoke all rewards from a given issuance job. Useful for error correction and fraud prevention. | # Consumer UX Source: https://docs.thanx.com/overview/guides/consumer-ux # Overview This guide explains how merchants and partners can integrate their ordering systems—whether mobile apps or web ordering sites—with Thanx to create a seamless, loyalty-driven customer experience. By connecting directly to Thanx, merchants can unify ordering, payments, and rewards in one platform, allowing customers to easily log in, earn points, redeem rewards, and view their loyalty status without leaving the ordering experience. This integration not only enhances convenience for users but also helps brands strengthen customer retention, increase repeat purchases, and gain valuable insights into customer behavior. For merchants, it simplifies loyalty management by automating reward activation, receipts, and tier tracking, while maintaining a consistent and engaging brand experience across digital channels. In short, integrating with Thanx enables a more personalized, rewarding, and data-driven relationship with every customer. # Credentials You Will Need For this type of integration you will need * Client id * Client secret * Merchant id * Merchant Key # Best Practices Based on our experience, we recommend the following best practices to engage with app users and maintain the highest standards for user experience and Thanx functionality. Here are key topics to consider when maintaining best practices within your integrations: [Design Best Practices](/consumer/best-practices/design) [Card Enrollment Best Practices](/consumer/best-practices/enrollment) [Onboarding and Authentication Best Practices](/consumer/best-practices/onboarding-authentication) [Loyalty and Rewards Best Practices](/consumer/best-practices/loyalty) [Feedback and Support](/consumer/best-practices/feedback) [Messaging Best Practices](/consumer/best-practices/messaging) # Interactions When building ordering integrations with Thanx—whether for mobile apps or web ordering systems—you'll use both our Consumer API and our Loyalty API. While we recommend integrating all available endpoints from both APIs, we understand that not all are strictly required. Below is a list of the minimum required endpoints to build a successful integration with Thanx and leverage our core functionality. ### **User Authentication** User authentication should be done via our SSO flow as outlined in our docs. This ensures proper user validation and a seamless login experience. [SSO Overview](/consumer/sso/overview) [Acquire Auth Code](/consumer/sso/acquire-auth-code) [Acquire Access Token](/consumer/sso/acquire-access-token) If the user account does not exist, refer to the [Create User](/consumer/users/create-user) endpoint to create the account and obtain a user token. **User Authentication Workflow** ```mermaid theme={null} flowchart LR A["Does user exist in Thanx?"] -->|No| B["Create User → Returns Token"] A -->|Yes| E["Acquire Authorization Code"] E --> F["Acquire Access Token → Returns Token"] classDef default fill:transparent,stroke:#13c1bf,stroke-width:1px; ``` ### **Credit Card Management** (Only for card-linked loyalty merchants) For card-linked loyalty, integrate card management endpoints. This allows users to enroll, view, and delete their enrolled cards within a merchant loyalty program. [Create Card](/consumer/cards/create-card) [Get Cards](/consumer/cards/get-cards) [Delete Card](/consumer/cards/delete-card) ### **Check-in Page** (Only for check-in loyalty merchants) For check-in merchants, integrate the get check-in code endpoint. This retrieves the value that the custom experience should embed into a generated QR code. Users can then show this QR code to any system that supports QR code check-in for loyalty. [Get Check In Code](/consumer/users/check-in-code) ### **Bonus Points Automatic Activation** Implement bonus points automatic activation so users can earn points when they receive a bonus points reward—without needing to manually redeem the reward itself. [Rewards Overview](/consumer/rewards/overview) [Get Rewards](/consumer/rewards/get-rewards) [Activate Reward](/consumer/rewards/activate-reward) ### **In-Store Reward Redemption** (Only for mobile apps) For mobile apps, implement in-store reward redemption and points product redemption logic. This means displaying in-store redemption codes when users redeem rewards in-store—whether as QR codes or the merchant's preferred code format. ### **Reward Redemption at Checkout** For all ordering experiences, reward redemption and points product exchange should be available at checkout when submitting baskets. The basket submission process should work as follows: At the checkout screen, make a [Get Account](/loyalty/get-account) API call to retrieve the user's available points balance, available rewards, and points products. This allows you to display the applicable rewards and points products to the user so they can decide whether to include any benefits in their current basket. Then submit the basket to our [Create or Update Basket](/loyalty/create-update-basket) endpoint. Include the proper Thanx location\_uid with this basket submission, which can be retrieved via the [Get Locations](/consumer/locations/get-locations) endpoint. ### **Tier Information Display** Users should be able to see their current tier status and available tiers within the Thanx experience. This can be achieved using the following endpoints: [Get Tier Statuses](/consumer/tiers/get-statuses) [Get Tier Configurations](/consumer/tiers/get-configs) ### **Push Notifications** This is not a requirement for certification, but integration is possible using our API. [Create Push Registration](/consumer/push/create-push-registration) ### **Receipt Upload** (Only for card-linked loyalty merchants) For card-linked loyalty merchants, implement receipt uploads within the ordering experience using the following endpoints: [Create Receipt](/consumer/receipts/create-receipt) [Get Receipts](/consumer/receipts/get-receipts) [Get Upload Url](/consumer/receipts/get-upload-url) ### **User Account Management** A user should be able to create an account, view their user details, update their information, and request account deletion. This is possible via the following endpoints: [Create User](/consumer/users/create-user) [Get User](/consumer/users/get-user) [Update User](/consumer/users/update-user) [Delete User](/consumer/users/delete-user) # Postman API Collection Here you will find the **Mobile App - Web Ordering Integration API Postman Collection** to import directly within your API testing tool. This collection is already completed and includes sample values for the credentials. Please replace them with the ones provided by your Thanx representative in order to achieve successful API calls. Download Postman Collection # Certification Certification is a standard process that all experiences integrating with Thanx must pass before accessing our production environment. You can find more detailed information about this process on the following [page](/consumer/usage/certification) **Before submitting for certification**, download and complete the self-check checklist to verify your integration meets all requirements. This reduces back-and-forth during certification and helps ensure a first-attempt pass. Download Consumer UX Pre-Certification Self-Check To certify these types of experiences, we will need: * For mobile apps: * Access to TestFlight version for iOS builds * Access to Google Console Testing for Android builds * For web ordering experiences: * Test link for testing the online experience Once we receive the needed materials for testing, we will review all of the outlined interactions and check our logs to confirm that everything worked as expected. After every interaction has been tested and we've verified that the logs show the correct information and headers are sent properly, we will provide the corresponding production credentials. ## Product Guide # Pay-At-Table Source: https://docs.thanx.com/overview/guides/pay-at-table # Overview This guide explains how to integrate a digital, QR code–based **Pay at the Table** experience using our APIs. This feature lets guests log in to their account, view their order, pay directly from their mobile device, and automatically earn loyalty points for their purchase. The integration connects your on-premise ordering and payment systems with the Thanx loyalty platform. When a guest scans a QR code at their table, they’re prompted to sign up or sign in to their loyalty account. Once authenticated, the integration retrieves their account and order details, allowing them to earn and redeem rewards during checkout. By embedding this digital payment flow, merchants deliver a seamless, contactless experience that enhances guest satisfaction and loyalty participation while simplifying staff operations. *** ## User Experience Overview 1. The guest scans a QR code placed on their table. 2. They are directed to a digital checkout experience branded for the merchant. 3. If they do not have an account, they can quickly create one using their email. 4. If they already have an account, they can sign in directly from the same flow. 5. The guest reviews their order, applies available rewards, and completes payment from their mobile device. 6. Once the payment is complete, loyalty points are automatically accrued to their account. *** ## Credentials You Will Need For this kind of integration, you will be provided the following credentials: * **Client ID** * **Client Secret** *** ## API Interaction Workflow ```mermaid theme={null} flowchart LR A["Does user exist in Thanx?"] -->|No| B["Create User → Returns Token"] B --> C["Get Account"] C --> D["Create or Update Basket"] A -->|Yes| E["Acquire Authorization Code"] E --> F["Acquire Access Token"] F --> C classDef default fill:transparent,stroke:#13c1bf,stroke-width:1px; ``` *** ## Postman API Collection Here you will find the **Pay at the Table Integration API Postman Collection** to import directly within your API testing tool. This collection includes sample values for credentials. Replace them with those provided by your Thanx representative to ensure successful API calls. Download Postman Collection *** ## Technical Integration ### Sign Up Flow Used when the guest does not yet have an account. In this experience, the guest clicks **Create Account** and enters their email address. If the user is new, the **Create User** endpoint returns a token that can be used to retrieve their account information. If the user already has a Thanx account, it associates the account with the client brand before returning a 400 error. In this case, the integration must use the **Acquire Authorization Code** endpoint, followed by **Acquire Access Token**, since a token will not be returned when the request errors. Once the account is created or authenticated, your system can fetch user details and create or update the basket to handle purchases and reward accrual. **Endpoints used in this flow:** 1. [Create User](/consumer/users/create-user) Creates a new user and returns a token if the user is new. 2. [Acquire Authorization Code](/consumer/sso/acquire-auth-code) Used when the user already exists and a token was not returned. 3. [Acquire Access Token](/consumer/sso/acquire-access-token) Exchanges the authorization code for an access token. 4. [Get Account](/loyalty/get-account) Retrieves the user’s account details. 5. [Create or Update Basket](/loyalty/create-update-basket) Creates or updates the active basket for the user. This endpoint is responsible for granting points when purchases are made. *** ### Sign In Flow Used when the guest already has an account. In this experience, the guest clicks **Sign In** and enters their email address. They will receive an email with a link to authenticate. When the user clicks the link, they are redirected to the specified `redirect_uri` with the authorization code as a query parameter. Your integration then exchanges this authorization code for an access token, which allows you to make API calls on behalf of the user. After authentication, you can fetch their account details and create or update their basket to handle purchases and reward accrual. **Endpoints used in this flow:** 1. [Acquire Authorization Code](/consumer/sso/acquire-auth-code) Initiates sign-in and generates the authorization link sent to the user. 2. [Acquire Access Token](/consumer/sso/acquire-access-token) Exchanges the authorization code for an access token used for authenticated requests. 3. [Get Account](/loyalty/get-account) Retrieves the user’s account information. 4. [Create or Update Basket](/loyalty/create-update-basket) Creates or updates the active basket for the user. This endpoint is responsible for granting points when purchases are made. *** # Certification Once your integration has been built and developed against the sandbox environment, please reach out to [developer.support@thanx.com](mailto:developer.support@thanx.com) to go through a lightweight but mandatory certification process. **Before submitting for certification**, download and complete the self-check checklist to verify your integration meets all requirements. This reduces back-and-forth during certification and helps ensure a first-attempt pass. Download Pay-at-Table Pre-Certification Self-Check For basic integration use-cases, certification is quick and normally takes no more than a few days depending on the scope of integration. This process is mainly designed to ensure the integration is working as intended without risking any negative impact on live customers (merchant or consumer). Each net new integration use-case should be re-certified as new use-cases will very likely require different scoping. Launching new merchants on certified integration use-cases does not require re-certification. The certification process will start with a video call with members of our developer support team. On the call, your team will demo the integration and all the supported use-cases. After the demo of all support use-cases, our team will validate the following: ## **Interactions** 1. authentication 2. loyalty lookup, such as reward and points product 3. order submission with or without loyalty redemption 4. walk through examples of all supported loyalty types: * reward redemption workflow: * amount off rewards * item-based rewards * points redemption workflow: * amount off points products * item-based points products 5. error message handling ## **API** 1. requests must include all [required headers](/loyalty/headers) 2. requests must not be unnecessarily duplicated 3. error messages should be handled gracefully for users 4. requests should only be issued on a reasonable frequency and in response to end-user interactions (e.g. Don't rapidly poll the API for changes) ## **Product Capabilities** The following product capabilities are **non-negotiable** within our platform and must be supported in your Pay At The Table integration. These features are crucial to the Thanx user experience. ### **Reward Redemption** Users must be able to look up their available rewards (via the [Get Account](/loyalty/get-account) endpoint). They must also be able to redeem these rewards (via the [Create or Update Basket](/loyalty/create-update-basket) endpoint). ### **Points Product Exchange** Users must be able to view the products they are eligible to exchange based on their points balance (via the [Get Account](/loyalty/get-account) endpoint). They must also be able to submit those products as part of their basket to complete the exchange (via the [Create or Update Basket](/loyalty/create-update-basket) endpoint). ### **Automated Location Mapping** To ensure accurate tracking of purchases per location and proper filtering of location-specific rewards, baskets must be submitted with the correct **Thanx Location ID** in the `location_uid` attribute as specified [here](/loyalty/create-update-basket#param-location-uid). To simplify this process, you can automate the mapping of your own location IDs to Thanx Location IDs by using the [Get Locations](/consumer/locations/get-locations) endpoint from the Consumer API. This allows your system to asynchronously communicate with the Thanx API, keeping location data up to date and ensuring seamless internal mapping between your locations and Thanx locations. ## Product Guide # Additional Endpoints to Enhance the Experience | Endpoints | Purpose | | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Get User, Update User, Delete User** | Manage the user account. | | **Get Purchase, Get Purchases** | Display a user’s past purchases. | | **Get Points Balance, Get Rewards** | Show the user’s current points and available rewards. | | **Get Points Products, Exchange Points Product** | Display available points products and allow users to redeem them. | | **Get Communication Settings, Update Communication Settings** | Manage the user’s communication preferences. | | **Create Card, Get Cards, Delete Card** | Create or manage a user’s linked payment cards. Once a card is registered, the user can pay with that card to accrue points without logging in, for merchants that use the Card-link loyalty type. The user will accrue points only if the transaction is processed directly through the card network. Payments made through Stripe or other payment service providers (aggregators) will not trigger accrual because the transaction is processed under the provider’s merchant ID rather than the merchant’s own. | | **Get Tags, Update Tags, Delete Tag** | Fetch and update user tags to enable targeted campaigns. | # POS / Kiosk Source: https://docs.thanx.com/overview/guides/pos-kiosk # Overview This integration connects the POS or kiosk system with the Thanx loyalty platform so that customers can seamlessly identify themselves during checkout, view and redeem available rewards or points-products, and automatically apply discounts to their order. By embedding the loyalty experience directly into the checkout flow, whether assisted by a cashier or on a self-service kiosk, this integration removes friction, increases reward usage, and drives repeat visits. Every step of the purchase (including reward redemption, points accrual, cancellations, or refunds) is tracked to ensure accurate loyalty data and better customer insights. The goal is to deliver a consistent, seamless, and engaging loyalty experience at the point of purchase, ultimately boosting customer satisfaction, loyalty participation, and revenue. # Credentials You Will Need For this kind of integration, you will be provided the following credentials: * Client ID * Client Secret * Merchant ID * Merchant Key * Partner Token (only to be used against [Create Access Token](/partner/auth/create-token)) # Endpoints We Will Be Using In order to achieve the full POS integration, these are the endpoints your integration should interact with: * [Create Access Token](/partner/auth/create-token) * [Get Account](/loyalty/get-account) * [Create or Update Basket](/loyalty/create-update-basket) Note that these are the minimum required endpoint interactions in order to build a successful and reliable Thanx integration. If more user data is needed, you can always ask which endpoints to consume to get the desired user data. # Postman API Collection Here you will find the **POS - Kiosk Integration API Postman Collection** to import directly within your API testing tool. This collection is already completed and includes sample values for the credentials. Please replace them with the ones provided by your Thanx representative in order to achieve successful API calls. Download Postman Collection ## API Interaction Workflow ```mermaid theme={null} flowchart LR A["Create Access Token"] --> B["Get Account"] B["Get Account"] --> D["Create Or Update Basket"] classDef default fill:transparent,stroke:#13c1bf,stroke-width:1px; ``` # POS Integration Flow ### 1 - **User Authentication at POS** The user arrives at the POS and either: * Scans their QR code (if QR check-in is enabled), or * Provides their phone number or email to log in. * **Reward QR Code case:** Once scanned, the QR code will return a value in the format `{user_id}|{reward_id}`. * Use the `user_id` with the [Create Access Token](/partner/auth/create-token) endpoint to generate an access token and make API calls on behalf of the user. * Use the `reward_id` to directly apply the discount to the order via the [Create or Update Basket](/loyalty/create-update-basket) endpoint. The POS uses this information to request an access token via the [Create Access Token](/partner/auth/create-token) endpoint using the user ID, email, or phone. With the acquired token, the POS calls the Get Account endpoint to retrieve user details and available rewards. ### 2 - **Reward Selection** * If it’s a cashier-assisted experience, the user is asked which reward they wish to redeem. * If it’s a kiosk, the user selects the reward directly from the list displayed. ### 3 - **Basket Management** During the purchase decision phase, the POS sends the current basket with `"checkout"` state to the Create or Update Basket endpoint. This call should be made any time the user updates their basket or reward selection, to ensure discounts are recalculated if necessary. ### 4 - **Order Placement & Locking** When the order is submitted, the POS updates the basket with the `"placed"` state to lock the reward. * Once a reward is specified at this stage, it becomes locked to the order. * If a points product is used, the corresponding points are deducted from the user’s balance. ### 5 - **Billing & Completion** When the user decides to pay, the POS calls the same endpoint with the `"billed"` state. * This indicates that the order has been transmitted to the POS and the user’s credit card has been charged. * Rewards are marked as used, and points or loyalty progress are accrued. (Recommended) After billing, the POS calls the endpoint with the `"completed"` state to indicate that the order has been handed to the customer. ### 6 - **Order Cancelation or Refunds** * (Recommended) If an order is canceled after being placed but before being billed, the POS should call the endpoint with the `"voided"` state. * Locked rewards are returned to the user. * Points spent on points products are not refunded, but the product reward remains available for future use. * If an order is refunded or canceled after billing, the POS should use the `"refunded"` state. * As with voided orders, locked rewards are returned, but spent points are not refunded. * The points product remains redeemable in future purchases. ### 7 - **Lifecycle Tracking** (Optional but Recommended) For full lifecycle tracking, the POS should consistently report state transitions for every order using the Create or Update Basket endpoint. This ensures loyalty data remains accurate and recoverable in case of disputes or technical issues. # Certification Once your integration has been built and developed against the sandbox environment, please reach out to [developer.support@thanx.com](mailto:developer.support@thanx.com) to go through a lightweight but mandatory certification process. **Before submitting for certification**, download and complete the self-check checklist to verify your integration meets all requirements. This reduces back-and-forth during certification and helps ensure a first-attempt pass. Download POS / Kiosk Pre-Certification Self-Check For basic integration use-cases, certification is quick and normally takes no more than a few days depending on the scope of integration. This process is mainly designed to ensure the integration is working as intended without risking any negative impact on live customers (merchant or consumer). Each net new integration use-case should be re-certified as new use-cases will very likely require different scoping. Launching new merchants on certified integration use-cases does not require re-certification. The certification process will start with a video call with members of our developer support team. On the call, your team will demo the integration and all the supported use-cases. After the demo of all support use-cases, our team will validate the following: ## **Interactions** 1. authentication 2. loyalty lookup, such as reward and points product 3. order submission with or without loyalty redemption 4. walk through examples of all supported loyalty types: * reward redemption workflow: * amount off rewards * item-based rewards * points redemption workflow: * amount off points products * item-based points products 5. error message handling ## **API** 1. requests must include all [required headers](/loyalty/headers) 2. requests must not be unnecessarily duplicated 3. error messages should be handled gracefully for users 4. requests should only be issued on a reasonable frequency and in response to end-user interactions (e.g. Don't rapidly poll the API for changes) ## **Product Capabilities** The following product capabilities are **non-negotiable** within our platform and must be supported in your POS–Kiosk integration. These features are crucial to the Thanx user experience. ### **Reward Redemption** Users must be able to look up their available rewards (via the [Get Account](/loyalty/get-account) endpoint). They must also be able to redeem these rewards (via the [Create or Update Basket](/loyalty/create-update-basket) endpoint). ### **Points Product Exchange** Users must be able to view the products they are eligible to exchange based on their points balance (via the [Get Account](/loyalty/get-account) endpoint). They must also be able to submit those products as part of their basket to complete the exchange (via the [Create or Update Basket](/loyalty/create-update-basket) endpoint). ### **Refunds** Users must be able to request refunds for their transactions if needed. (via the [Create or Update Basket](/loyalty/create-update-basket) endpoint). Refunds should be handled at the POS, ensuring that: * Any redeemed rewards are restored. * Any exchanged point products are reverted, and the corresponding points are credited back to the user. ### **Automated Location Mapping** To ensure accurate tracking of purchases per location and proper filtering of location-specific rewards, baskets must be submitted with the correct **Thanx Location ID** in the `location_uid` attribute as specified [here](/loyalty/create-update-basket#param-location-uid). To simplify this process, you can automate the mapping of your own location IDs to Thanx Location IDs by using the [Get Locations](/partner/metadata/get-locations) endpoint from the Partner API. This allows your system to asynchronously communicate with the Thanx API, keeping location data up to date and ensuring seamless internal mapping between your locations and Thanx locations. ## Product Guide # Additional Endpoints to Enhance the Experience | Endpoints | Purpose | | --------------------- | --------------------------------------------------------------------------------------- | | **Get User** | Retrieve additional user information to enhance the user experience | | **Get Tier Statuses** | Retrieve the current user's tier status to display on the POS or customer-facing screen | # Subscriber Ingestion Source: https://docs.thanx.com/overview/guides/subscriber-ingestion # Overview This guide explains how to integrate **subscriber ingestion** using the Thanx Partner API. This integration allows partners and merchants to programmatically opt email addresses into a merchant's Thanx loyalty marketing. Common use cases include syncing newsletter signups, importing CRM contacts, connecting email marketing platforms, and ingesting subscribers from website signup forms. The integration is entirely **server-to-server**. Partners submit subscriber information on behalf of merchants, and Thanx handles targeted loyalty outreach to encourage full loyalty program enrollment. This is one of the simplest Thanx API integrations — it requires a single endpoint and minimal configuration. *** ## Credentials You Will Need For this kind of integration, you will be provided the following credentials: * **Client ID** — used in the `X-ClientId` header * **Access Token** — used in the `Authorization` header These credentials grant access to all merchants that have explicitly opted into the specified integration. All merchants accessible to these credentials can be listed via the [Get Merchants](/partner/metadata/get-merchants) endpoint. Each API credential is configured with an agreed upon scope — granting access to a subset of the API endpoints available. The subscriber ingestion endpoint requires the `subscribers.write` scope. Use the [Get Scopes](/partner/metadata/get-scopes) endpoint to verify which scopes your credentials have access to. All API requests must include the required headers documented in the [Partner API Overview](/partner/overview#headers) — including `Authorization`, `X-ClientId`, `Accept-Version`, `Content-Type`, and `User-Agent`. *** ## Endpoints We Will Be Using The following endpoints are required for this integration: 1. [Get Merchants](/partner/metadata/get-merchants) — Retrieve your merchant ID 2. [Create Subscriber](/partner/subscribers/create-subscriber) — Opt an email address into a merchant's loyalty marketing *** ## Postman API Collection Here you will find the **Partner API Postman Collection** to import directly within your API testing tool. This collection includes sample values for credentials. Replace them with those provided by your Thanx representative to ensure successful API calls. [Partner API Postman Collection](/overview/api_collections) *** ## API Interaction Workflow ```mermaid theme={null} flowchart LR A["Get Merchants"] --> B["Get merchant_id"] B --> C["Create Subscriber"] C -->|"201 Created"| D["Success"] C -->|"400 Bad Request"| E["Invalid Email"] C -->|"429 Too Many Requests"| F["Backoff & Retry"] F --> C classDef default fill:transparent,stroke:#13c1bf,stroke-width:1px; ``` *** ## Integration Flow ### 1 — Setup & Discovery Before creating subscribers, the partner must retrieve the merchant ID for the merchant whose loyalty marketing subscribers will be opted into. Call the [Get Merchants](/partner/metadata/get-merchants) endpoint to retrieve the list of merchants that have opted into the integration. Each merchant in the response includes an `id` that is required when creating subscribers. For single-merchant integrations, this only needs to be done once. The merchant ID can then be stored and reused for all subsequent subscriber creation requests. **Endpoints used in this step:** 1. [Get Merchants](/partner/metadata/get-merchants) Lists all merchants accessible to the integration partner. 2. [Get Scopes](/partner/metadata/get-scopes) *(Optional)* Verifies which API scopes your credentials have access to. Useful for confirming `subscribers.write` is available. *** ### 2 — Creating Subscribers This is the core action. When a user signs up for a newsletter, submits a form, or is otherwise identified as a marketing prospect, the partner calls the [Create Subscriber](/partner/subscribers/create-subscriber) endpoint to opt them into the merchant's Thanx loyalty marketing. The request requires: * `merchant_id` — The merchant to subscribe the user to * `email` — The subscriber's email address Optional fields that enrich the subscriber profile: * `first_name` — Subscriber's first name * `last_name` — Subscriber's last name * `birth_date` — Subscriber's birth date as a nested object: `{ "month": 8, "day": 14 }` * `zip_code` — Subscriber's zip code Note that all subscriber fields must be wrapped inside a `subscriber` key in the request body. See the [Create Subscriber](/partner/subscribers/create-subscriber) endpoint reference for the exact payload structure. **Important behavior notes:** * The endpoint responds with `201 Created` for **any valid email address**, even if the email already exists in the system. This is by design — it prevents unintentional PII exposure for existing records. * The response only contains the accepted email address. * The only time the endpoint returns `400 Bad Request` is when the input email address is invalid. * All subscriber information submitted via API **must** have explicit user consent to participate in the merchant's marketing. **Endpoints used in this step:** 1. [Create Subscriber](/partner/subscribers/create-subscriber) Opts an email address into the specified merchant's loyalty marketing. *** ## Subscriber vs. User It is important to understand the distinction between a **subscriber** and a **user** in the Thanx platform: | | Subscriber | User | | --------------------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | | **Created via** | `POST /partner/subscribers` (Partner API) | `POST /users` (Consumer API) | | **What they receive** | Targeted marketing from the merchant to encourage loyalty enrollment | Full loyalty program access: rewards, points, tiers, cards | | **Requirements** | Email address + marketing consent | Full enrollment flow with legal requirements (card linkage, ToS acceptance) | | **Complexity** | Low — single endpoint | High — requires Consumer API integration with SSO, card enrollment, legal compliance | If your integration requires creating full loyalty program users (not just marketing subscribers), please reach out to [developer.support@thanx.com](mailto:developer.support@thanx.com) to discuss a [Consumer API](/consumer/overview) integration instead. *** ## Rate Limits Integration partners should not exceed a rate of **5 requests per second** and **2,000 requests per 15 minutes**. These are hard limits and the API will return `429 Too Many Requests` once exceeded. Rate-limited requests can and should be retried. One such strategy is through an **exponential backoff** approach. Should your specific integration use-case require higher API throughput, please reach out to [developer.support@thanx.com](mailto:developer.support@thanx.com) to request an increase. *** ## Certification **Before submitting for certification**, download and complete the self-check checklist to verify your integration meets all requirements. This reduces back-and-forth during certification and helps ensure a first-attempt pass. Download Subscriber Ingestion Pre-Certification Self-Check Before receiving production credentials, all integrations must go through Thanx's [certification process](/partner/overview#certification). For subscriber ingestion, the certification team will validate the following: ### Interactions 1. Subscriber creation with valid email addresses 2. Handling of optional subscriber fields (name, birth date, zip code) 3. Bulk ingestion workflow (if applicable) 4. Ongoing sync mechanism (if applicable) ### API 1. Requests include all [required headers](/partner/overview#headers) 2. Requests are not unnecessarily duplicated 3. Error messages are handled gracefully 4. Requests are issued at a reasonable frequency (e.g., not rapidly submitting the same email) ### Consent 1. All subscriber data submitted to Thanx has explicit user consent for the merchant's marketing 2. Partners do not submit email addresses obtained without proper opt-in ### Product Guide *** ## Additional Endpoints to Enhance the Experience | Endpoint | Purpose | | ---------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | | **[Get Merchants](/partner/metadata/get-merchants)** | Retrieve the list of merchants accessible to the integration. Use this to populate merchant selection in your platform. | | **[Get Locations](/partner/metadata/get-locations)** | Retrieve locations for accessible merchants. Useful if your platform operates at the location level rather than the merchant level. | | **[Get Scopes](/partner/metadata/get-scopes)** | Verify which API scopes your credentials have access to. Useful for onboarding diagnostics. | # Integrating with Thanx Source: https://docs.thanx.com/overview/integrating **Welcome!** This guide is designed to help you work **with Thanx** from initial onboarding to a successful launch. We believe in a collaborative, partner-centric approach where *your* success is *our* success. We strive to provide proactive support, clear documentation, and a smooth integration process. Below you’ll find an overview of team roles, key integration paths, resources, and processes we’ll navigate **together**. Note: This site is your go-to for detailed API specs, step-by-step guides, and best practices. ## Roles & Responsibilities ### Partnerships Team Think of the Partnerships team as your project concierge and primary point of contact. In practice, this means they: * Coordinate kickoff meetings and integration scoping. * Ensure requirements are understood and captured. * Facilitate alignment across internal teams. * Escalate questions or needs to the right specialists. * Keep you informed about progress and milestones. * Partner with you on GTM and co-marketing opportunities. They ensure you always know who to contact and keep the engagement on track. For general partnership questions or to start an integration with us, reach out to [**partnerships@thanx.com**](mailto:partnerships@thanx.com) ### Developer Support Team The Developer Support team is your technical guide and engineers. They provide: * **Technical documentation** and implementation support. * **Sandbox credentials** and environment setup. * **Certification reviews** to ensure your integration meets Thanx standards. Dev Support is your go-to contact for: * API questions and examples. * Integration troubleshooting. * Technical updates or feature clarifications. You can reach them at [**developer.support@thanx.com**](mailto:developer.support@thanx.com) ## Key Integration Paths Thanx supports multiple integration paths to fit your product and customers. Our platform is designed to be flexible – whether you’re integrating at the POS, kiosk, in a custom app, or via a pay-at-table experience. ### POS Integrations Integrate Thanx loyalty directly into your Point-of-Sale system for in-store transactions. Using our **Loyalty API**, a POS can: * Look up a guest’s loyalty account. * Retrieve available rewards. * Apply discounts. * Record loyalty accrual in real time. This creates a seamless cashier experience where rewards are integrated into checkout. Refer to the [POS / Kiosk Integration Guide](/overview/guides/pos-kiosk) for details. ### Kiosk Integrations Extend loyalty to self-service kiosks. The kiosk software allows guests to: * Identify themselves (e.g., by phone number or QR code). * View and redeem rewards. * Apply rewards before payment. This ensures a frictionless loyalty experience even in self-service environments. Kiosks follow the same integration path for POS, refer to the [POS / Kiosk Integration Guide](/overview/guides/pos-kiosk) for details. ### Consumer UX (Mobile & Web) Integrations Build loyalty features into your **custom mobile or web app**. You can: * Display loyalty balances and rewards. * Enroll users in programs. * Handle redemptions and reward events in real-time. Thanx provides OAuth tokens, sandbox environments, and webhooks for real-time updates. This path allows you to deliver a fully branded loyalty experience while Thanx operates behind the scenes. Refer to the [Consumer UX Integration Guide](/overview/guides/consumer-ux) for more information. ### Pay-at-Table Integrations Enable guests to pay directly from their mobile device by scanning a QR code at their table. Using our Pay-at-Table APIs, you can: * Allow guests to sign up or sign in to their loyalty account. * Display order details and apply available rewards. * Complete payment and automatically accrue loyalty points. This integration connects on-premise ordering and payment systems with the Thanx loyalty platform, creating a seamless, contactless dining experience. Refer to the [Pay-at-Table Integration Guide](/overview/guides/pay-at-table) for more information ### Subscriber Ingestion Sync newsletter signups, CRM contacts, or email marketing lists into Thanx loyalty marketing via the Partner API. Using our **Partner API**, you can: * Opt email addresses into a merchant’s loyalty marketing. * Enrich subscriber profiles with names, birth dates, and zip codes. * Perform bulk imports or real-time syncs as users sign up. Thanx handles targeted outreach to encourage full loyalty program enrollment. Refer to the [Subscriber Ingestion Guide](/overview/guides/subscriber-ingestion) for details. Don’t see your integration path? Reach out to [partnerships@thanx.com](mailto:partnerships@thanx.com) for more information. ## Integration Process & Certification Here’s an overview of the typical process and how we’ll support you at each stage: ### 1. Discovery & Scoping * The Partnerships team defines the integration **scope and requirements** with you. * Partnerships team and Developer Support identify your goals, data needs, and technical constraints. * Once aligned, you’ll receive a clear plan for development, timelines, and handoffs. ### 2. Development & Sandbox Testing * Thanx provides **sandbox credentials** and access for testing. * The Developer Support team walks you through relevant endpoints and examples. * You test against sandbox accounts to validate flows (e.g., reward lookups, redemptions, accruals). * Check-ins and Q\&A sessions are available throughout this phase. ### 3. Certification (Quality Check) * After sandbox testing, Thanx conducts a **certification review** before go-live. * You demo your integration via video call, walking through key use cases. * You should also provide a link or test environment where we can independently test your experience. * We verify authentication, redemption logic, error handling, and data consistency. * You must submit a **product guide** (screenshots of each step plus a screen recording demonstrating how the integration works) covering all use cases submitted for certification, shared with the Thanx team via email. * Once complete, Thanx provides **production API keys**. ### 4. Launch & Ongoing Support * The Partnerships team coordinates the **launch** and any co-marketing opportunities. * Dev Support remains available for post-launch help and optimization. * Once certified, you can onboard additional merchants using the same integration without going over all the initial certification steps. We provide smoother checks to help you launch new customers. ## Next Steps & Feedback We’d love your feedback! Are there additional integration types or use-cases you think we should support? Share your ideas — they directly shape our roadmap and help us improve our partner experience. Your insights are invaluable, and we look forward to building even stronger integrations together. **Thank you** for partnering with Thanx — we’re excited to collaborate with you to create amazing experiences for merchants and customers alike! # Introduction Source: https://docs.thanx.com/overview/intro Thanx provides a number of ways to integrate — via API, webhooks, and data exports. Outlined in these docs are guides on how to integrate with the Thanx platform, best practice recommendations, API / webhook specs, and data export documentation. Integrate Thanx into a custom consumer experience Privileged APIs supporting custom integration use-cases Support integrations with digital ordering and kiosk providers Responding in real-time to events within Thanx Accessing Thanx data in the destination of your choice Use AI to search docs and interact with APIs # Loyalty Models Source: https://docs.thanx.com/overview/loyalty-models Thanx supports two types of loyalty programs: **Card-Linked Loyalty** and **Check-In Loyalty**. Each merchant can use **only one type**, so it's important to understand how they work before building an integration. **Card-linked loyalty** automatically tracks in-store and digital purchases when guests pay with a linked payment card. It offers a seamless, staff-free experience, maximizes passive enrollment, and captures rich transaction data. Due to card network agreements, it is currently **available only in the United States**. **Check-in loyalty** identifies guests at the register using a phone number, email, or QR code. It follows a more traditional loyalty flow and is supported on integrated POS platforms. It is ideal for brands that prefer in-store interaction or **plan to operate internationally**. In short: * **Card-linked = automation + full data capture** * **Check-in = interactive in-store flow + geographic flexibility** ## Card-Linked Loyalty Card-linked loyalty links a guest's payment card to their loyalty account so that future purchases are tracked automatically. ### How It Works 1. During a digital checkout, Thanx securely tokenizes the guest's payment card. 2. When the guest uses the same card in-store, the transaction is matched to their loyalty account. 3. Thanx awards points and applies rewards without any action from the guest or staff. ### Key Characteristics * **No manual guest identification:** no phone number, QR code, or staff prompt required. * **Automatic enrollment:** guests who complete digital purchases are enrolled in loyalty. * **Wide POS compatibility:** works across most integrated POS systems for earn and redemption. * **Unified customer data:** combines online and in-store activity for accurate profiles and reporting. * **Availability:** limited to the United States due to card network rules. ## Check-In Loyalty Check-in loyalty relies on guest identification at the POS to track purchases and award points. ### How It Works 1. At checkout, the guest enters a phone number or email, or scans a QR code. 2. The POS identifies the guest and sends the transaction details to Thanx. 3. Thanx records the purchase, awards points, and enables in-store reward redemption. ### Key Characteristics * **Traditional in-store flow:** aligns with common loyalty experiences. * **Supported on select POS:** requires a POS integration. * **Guest or staff interaction:** relies on prompts or displays at checkout. * **International support:** not restricted by card network agreements. ## Comparison Table | | Card-linked | Check-in | | ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Earning points for digital purchases** | Yes | Yes | | **Earning points for in-store purchases** | Using an enrolled card or uploading a receipt | Checking-in at the POS with staff or via a guest-facing display | | **Redeeming rewards online** | Yes | Yes | | **Redeeming rewards in-store** | - Manager comp
- Staff sees available rewards for *identified* customers and applies them via the integration
- If available via POS, guests can see their rewards on buyer facing screens | - Manager comp
- Staff sees available rewards for *every* customer and applies them via the integration
- If available via POS, guests can see their rewards on buyer facing screens | | **Main benefits** | - Customers can earn points by just checking out as they regularly would
- Less likelihood to issue rewards to “win-back” repeat customers | - Widespread. No additional training required.
- Unified communication: the only way to earn points is via check-in. | | **Means to drive capture rate up** | Encourage digital orders | Focus on staff training to bring up check-in at *every* transaction | | **Receipts** | Necessary to support cash purchases | Check-in will work regardless of how you pay | ## Consumer Experience by Model
### Card-Linked Card Linked experience

Customer can see the cards they are earning points with and are prompted to add more.

Card Linked zero state

When they have no cards at all, they see a 0 state encouraging them to add more cards.

### Check-In Check-in with QR

Check-in example for a merchant who has QR code scanners.

Check-in without QR

Example without QR codes. When any information is missing, customers can provide it right on the check-in screen.

## Technical Integration by Model ### Card-Linked Loyalty When building integrations for card-linked loyalty, merchant location MIDs must be onboarded within Thanx to guarantee points accrual when a purchase is made at a merchant location. If the integration is for ordering (mobile or web), you should also integrate card management endpoints. This allows users to: * [Create Card](/consumer/cards/create-card) * [Get Cards](/consumer/cards/get-cards) * [Delete Card](/consumer/cards/delete-card) ### Check-In Loyalty When building integrations for check-in loyalty, mobile ordering integrations should include the Get Check-In Code endpoint. This allows users to display their QR code at in-store systems like kiosks or POS terminals to check in at merchant locations. * [Get Check In Code](/consumer/users/check-in-code) ### Basket API Regardless of which loyalty type is implemented, submitting a basket via our Loyalty API and our basket creation endpoint will always trigger points accrual for the user. * [Create or Update Basket](/loyalty/create-update-basket) # Sandbox Gotchas & FAQ Source: https://docs.thanx.com/overview/sandbox-faq **Purpose:** A single reference for the sandbox-specific behaviors every new partner hits in their first week of integration. If something "isn't working" in sandbox, start here before opening a ticket. This guide supplements the [POS/Kiosk](/overview/guides/pos-kiosk), [Consumer UX](/overview/guides/consumer-ux), and [Basket Lifecycle](/overview/guides/basket-lifecycle) guides with behaviors that are specific to the sandbox environment. **Who this is for:** * Partners actively integrating against `thanxsandbox.com` hosts * Anyone troubleshooting unexpected sandbox responses before escalating to Dev Support ## 1. Sandbox purchase processing has a noticeable delay Sandbox purchase processing runs on a lower-priority worker pool, so a successful `billed` basket or a sandbox `POST /purchases` request will not show up immediately. | Environment | Typical latency | | ----------- | -------------------------------------- | | Production | Near real-time | | Sandbox | 15 minutes, commonly up to 30+ minutes | Before reporting "points not accruing" or "purchase missing," wait \~30 minutes and re-check `GET /account` or `GET /purchases`. The majority of these sandbox tickets resolve themselves in this window. ## 2. Array query parameters require bracket notation When a Thanx endpoint accepts an array filter (e.g., filtering rewards by state), the query parameter name must include `[]` — dropping the brackets causes the server to interpret the value as a single string instead of an array element. **Wrong:** ``` GET /rewards?states=available,active ``` **Right:** ``` GET /rewards?states[]=available&states[]=active ``` The [Get Rewards](/consumer/rewards/get-rewards) endpoint documents this directly. The same convention applies to any array-valued filter across the Consumer, Partner, and Loyalty APIs. ## 3. Granting rewards in sandbox — `POST /rewards/grant` You don't need to trigger campaigns or wait for earn conditions to test rewards in sandbox. Use [`POST /rewards/grant`](/consumer/rewards/grant-reward) to issue any configured campaign's reward directly to a user. **Availability:** Sandbox only. The endpoint is disabled in production. **Required parameters:** * `campaign_id` — the **hashid** form of the program's `external_uid`, not the numeric program ID * `user_id` — the user to grant the reward to **Finding the `campaign_id`:** Ask Dev Support for the hashids of the campaigns set up on your sandbox merchant, or look them up in the merchant's admin. Using the numeric program ID will not resolve — the endpoint only accepts the hashid-encoded external UID. ```bash theme={null} curl https://api.thanxsandbox.com/rewards/grant \ -X POST \ -H "Content-Type: application/json" \ -H "Accept: application/json" \ -H "Accept-Version: v4.0" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" \ -d '{ "campaign_id": "YOUR_CAMPAIGN_HASHID", "user_id": "YOUR_USER_ID" }' ``` ## 4. Simulating a purchase in sandbox — `POST /purchases` To test points accrual, tier progression, or campaign triggers that depend on a completed purchase, use [`POST /purchases`](/consumer/purchases/create-purchase). This is the only way to create a sandbox purchase without going through a live POS or payment processor. **Availability:** Sandbox only. **Behavior:** * Processed asynchronously — the endpoint returns no JSON body * The purchase takes the usual 15–30+ minutes to land (see §1) * Poll `GET /purchases` to confirm ingestion — see guidance below ```bash theme={null} curl https://api.thanxsandbox.com/purchases \ -X POST \ -H "Content-Type: application/json" \ -H "Accept: application/json" \ -H "Accept-Version: v4.0" \ -H "Authorization: Bearer ${token}" \ -H "X-ClientId: ${client_id}" \ -d '{ "purchase": { "merchant_id": "YOUR_MERCHANT_ID", "location_id": "YOUR_LOCATION_ID", "user_id": "YOUR_USER_ID", "amount": 13.45, "purchased_at": "2020-09-15T00:52:10.655+00:00" } }' ``` **Polling guidance for sandbox verification:** * Wait at least 60 seconds before the first poll * Use exponential backoff — start at 60s, double up to a 5-minute cap * Stop polling as soon as the purchase appears, or after \~45 minutes total * This is a sandbox-only pattern for verifying test setup. Production integrations should not poll — sandbox latency is a sandbox artifact and does not reflect production behavior. Loyalty API integrations use [`POST /baskets`](/loyalty/create-update-basket) with state `billed` instead of `POST /purchases`. `POST /purchases` is specifically for Consumer API sandbox testing. ## 5. Test cards trigger fraud detection on protected rewards Commonly-used shared test card numbers (e.g., the standard Visa/MC test PANs) are flagged as high-risk by Thanx's fraud engine. **When this causes problems:** * Fraud-protected reward types include intro, birthday, winback, and signup rewards * Using a shared test card on a user registered to one of these rewards will silently fail to earn/activate * You'll see no error — just no reward **How to work around:** * For fraud-protected reward flows, register **a unique card number per test user** (only the first 6 and last 4 digits need to be valid; the middle digits can be random but consistent) * For non-protected reward types (points products, free-item rewards), shared test cards are fine ## Need sandbox credentials? Sandbox credentials (client ID, client secret, merchant key, partner token, and test user) are provided by Thanx Developer Support during onboarding. If you haven't received them or need a reset, email [developer.support@thanx.com](mailto:developer.support@thanx.com). ## Related Pages * [Integrating with Thanx](/overview/integrating) * [Basket Lifecycle & Troubleshooting](/overview/guides/basket-lifecycle) * [POS/Kiosk Integration Guide](/overview/guides/pos-kiosk) * [Consumer UX Integration Guide](/overview/guides/consumer-ux) * [Grant Reward (sandbox only)](/consumer/rewards/grant-reward) * [Create Purchase (sandbox only)](/consumer/purchases/create-purchase) # Create Access Token Source: https://docs.thanx.com/partner/auth/create-token POST /partner/oauth/token Scope required: `auth.create` This endpoint allows for the programmatic generation of an API access token for a given user. This access token can then be used with the [Consumer API](/consumer/overview) or the [Loyalty API](/loyalty/overview). Programmatic generation of access tokens on behalf of users is designed to support integration partners using custom authentication mechanisms. This allows for generation of access tokens that can be used with either the [consumer](/consumer/overview) or [loyalty](/loyalty/overview) APIs depending on the integration use-case. This enables integration partners to have complete flexibility in their management of user authentication - using [Thanx Auth](/consumer/sso/overview), a self-hosted authentication implementation, or a third-party authentication provider. ### Parameters Merchant ID Thanx User ID. One of `user_id`, `email`, or `phone` must be specified. Email address. One of `user_id`, `email`, or `phone` must be specified. Phone number in [E.164 format](https://www.twilio.com/docs/glossary/what-e164) (e.g. `+14155551212`). One of `user_id`, `email`, or `phone` must be specified. The number of seconds after which this access token will expire. Defaults to no expiration for integrations that require long-lived access tokens. If your integration does not require long-lived access tokens, we highly recommend this value to be specified. The allowed values are between 60s and 3600s (1 hour). Phone numbers must be in E.164 format with the country code prefix (e.g. `+14155551212`). For US numbers and US territories, the prefix is `+1`, including Puerto Rico (787/939), USVI (340), Guam (671), Northern Mariana Islands (670), and American Samoa (684). Numbers without the country code prefix may be parsed as international and return `Unknown user`. Besides phone formatting (above), `Unknown user` is also returned when the user does not exist on Thanx, or exists but is **not an enrolled loyalty member at this merchant** (a marketing subscriber is not sufficient). Enroll the user with [`POST /users`](/consumer/users/create-user) first, then retry. ### Response The user's access token, for use in accessing the [Consumer API](/consumer/overview) The type of token, "Bearer" The API scopes granted to the access token The number of seconds since the epoch The number of seconds after which this access token will expire ```bash Email theme={null} curl -X POST \ -H 'X-ClientId: ${client_id}' \ -H 'Accept-Version: v4.0' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer ${access_token}' \ https://api.thanxsandbox.com/partner/oauth/token \ -d '{ "merchant_id": "k2lye10h32l5wzo", "email": "example@example.com", "expires_in": 3600 }' ``` ```bash Phone (E.164) theme={null} curl -X POST \ -H 'X-ClientId: ${client_id}' \ -H 'Accept-Version: v4.0' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer ${access_token}' \ https://api.thanxsandbox.com/partner/oauth/token \ -d '{ "merchant_id": "k2lye10h32l5wzo", "phone": "+17875551212", "expires_in": 3600 }' ``` ```json Response Example theme={null} { "access_token": "945148251b603ae34561d90acfe4050e67494d6d1e65d4d3d52798407f03c0bd", "token_type": "Bearer", "scope": "passwordless", "created_at": 1577836800, "expires_in": 3600 } ``` # Create Campaign Source: https://docs.thanx.com/partner/campaigns/create-campaign POST /partner/campaigns Creates a new campaign with variants Scope required: `rewards.issue` This endpoint creates a new partner-initiated campaign for a merchant. A campaign defines the time window, terms, and reward variants for issuing rewards to users. Each campaign must have between 1 and 4 variants. Treatment variants specify a `reward_template_id` that defines the reward to be issued. Control variants (named "Control") do not require a `reward_template_id`. Use the [List Reward Templates](/partner/reward-templates/list-reward-templates) endpoint to discover available reward templates for a merchant. ### Parameters Merchant ID Campaign name Campaign objective Terms and conditions Campaign start date (ISO8601) Campaign end date (ISO8601) Reward redemption start date (ISO8601) Reward redemption end date (ISO8601) Campaign variants (1-4 variants) Variant name Reward template ID. Required for treatment variants, omit for control variants. ### Response Returns 201 Created with the campaign object. ```bash Create Campaign theme={null} curl https://api.thanxsandbox.com/partner/campaigns \ -X POST \ -H 'X-ClientId: {client_id}' \ -H 'Accept-Version: v4.0' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer {access_token}' \ -d '{ "campaign": { "merchant_id": "k2lye10h32l5wzo", "name": "Summer Free Coffee", "objective": "Re-engage lapsed customers", "fine_print": "Limit one per customer", "start_at": "2025-06-01T00:00:00Z", "end_at": "2025-08-31T23:59:59Z", "redeemable_from": "2025-06-01T00:00:00Z", "redeemable_to": "2025-09-30T23:59:59Z", "variants": [ { "name": "Treatment", "reward_template_id": "abc123def456" }, { "name": "Control" } ] } }' ``` ```json 201 theme={null} { "campaign": { "id": "camp_abc123", "name": "Summer Free Coffee", "objective": "Re-engage lapsed customers", "start_at": "2025-06-01T00:00:00Z", "end_at": "2025-08-31T23:59:59Z", "redeemable_from": "2025-06-01T00:00:00Z", "redeemable_to": "2025-09-30T23:59:59Z", "time_zone": "America/Los_Angeles", "fine_print": "Limit one per customer", "variants": [ { "id": "var_treat1", "name": "Treatment", "reward_template_id": "abc123def456" }, { "id": "var_ctrl1", "name": "Control", "reward_template_id": null } ] } } ``` # Get Campaign Source: https://docs.thanx.com/partner/campaigns/get-campaign GET /partner/campaigns/:id Returns a specific campaign Scope required: `rewards.issue` This endpoint returns a specific partner-initiated campaign. ### Parameters Campaign ID ### Response Campaign ID Campaign name Campaign objective Campaign start date (ISO8601) Campaign end date (ISO8601) Reward redemption start date (ISO8601) Reward redemption end date (ISO8601) Campaign time zone Terms and conditions Campaign variants Variant ID Variant name Reward template ID (null for control variants) ```bash Get Campaign theme={null} curl https://api.thanxsandbox.com/partner/campaigns/camp_abc123 \ -X GET \ -H 'X-ClientId: {client_id}' \ -H 'Accept-Version: v4.0' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer {access_token}' ``` ```json Response Example theme={null} { "campaign": { "id": "camp_abc123", "name": "Summer Free Coffee", "objective": "Re-engage lapsed customers", "start_at": "2025-06-01T00:00:00Z", "end_at": "2025-08-31T23:59:59Z", "redeemable_from": "2025-06-01T00:00:00Z", "redeemable_to": "2025-09-30T23:59:59Z", "time_zone": "America/Los_Angeles", "fine_print": "Limit one per customer", "variants": [ { "id": "var_treat1", "name": "Treatment", "reward_template_id": "abc123def456" }, { "id": "var_ctrl1", "name": "Control", "reward_template_id": null } ] } } ``` # Issue Rewards Source: https://docs.thanx.com/partner/campaigns/issue-rewards POST /partner/campaigns/issue Issue rewards to users for a campaign variant Scope required: `rewards.issue` This endpoint initiates an asynchronous reward issuance job. Rewards are issued to the specified users for a given campaign variant. The endpoint returns immediately with a `202 Accepted` response containing the issuance job details. Use the [Get Issuance Job](/partner/issuance-jobs/get-issuance-job) endpoint to poll for completion status. ### Best Practices for Event-Driven Workflows While there is nothing preventing you from issuing rewards one user at a time, we strongly recommend batching identifiers into a single request whenever possible. Sending individual requests per user is significantly less efficient and may result in rate limiting under the [global rate limits](/partner/overview#global-rate-limits). Collect identifiers and submit them in batches of up to 10,000 per request for optimal throughput. ### Idempotency This endpoint supports idempotent requests via the `X-Idempotency-Key` header. When provided, duplicate requests with the same key return the cached response from the original request. If the request body differs from the original, a `422 Unprocessable Entity` error is returned. ### Parameters Campaign ID Merchant ID Variant ID. Must belong to the specified campaign. Array of user identifiers to issue rewards to (max 10,000) Identifier type: `email` or `phone` Identifier value. Phone numbers must be in E.164 format (e.g., `+12025551234`). Optional idempotency key to prevent duplicate issuance jobs. ### Response Returns `202 Accepted` with the issuance job object. Issuance job ID Campaign ID Variant ID Job state: `pending`, `processing`, `completed`, or `failed` Total number of identifiers submitted Number of identifiers processed so far Number of rewards successfully issued Number of failed issuances Completion percentage (0-100) Job creation timestamp (ISO8601) Processing start timestamp (ISO8601), null if not started Processing completion timestamp (ISO8601), null if not completed ```bash Issue Rewards theme={null} curl https://api.thanxsandbox.com/partner/campaigns/issue \ -X POST \ -H 'X-ClientId: {client_id}' \ -H 'Accept-Version: v4.0' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer {access_token}' \ -H 'X-Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000' \ -d '{ "campaign_id": "camp_abc123", "merchant_id": "k2lye10h32l5wzo", "variant_id": "var_treat1", "identifiers": [ { "type": "email", "value": "jane.smith@example.com" }, { "type": "phone", "value": "+14155551234" } ] }' ``` ```json 202 theme={null} { "issuance_job": { "id": "job_xyz789", "campaign_id": "camp_abc123", "variant_id": "var_treat1", "state": "pending", "total_count": 2, "processed_count": 0, "success_count": 0, "failure_count": 0, "progress_percent": 0, "created_at": "2025-06-15T10:30:00Z", "started_at": null, "completed_at": null } } ``` # List Campaigns Source: https://docs.thanx.com/partner/campaigns/list-campaigns GET /partner/campaigns Returns active campaigns for a merchant Scope required: `rewards.issue` This endpoint returns all active partner-initiated campaigns for a given merchant. Only campaigns created through the Partner API are returned. ### Parameters Merchant ID ### Response Campaign ID Campaign name Campaign objective Campaign start date (ISO8601) Campaign end date (ISO8601) Reward redemption start date (ISO8601) Reward redemption end date (ISO8601) Campaign time zone Terms and conditions Campaign variants Variant ID Variant name Reward template ID (null for control variants) ```bash List Campaigns theme={null} curl https://api.thanxsandbox.com/partner/campaigns?merchant_id={merchant_id} \ -X GET \ -H 'X-ClientId: {client_id}' \ -H 'Accept-Version: v4.0' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer {access_token}' ``` ```json Response Example theme={null} { "campaigns": [ { "id": "camp_abc123", "name": "Summer Free Coffee", "objective": "Re-engage lapsed customers", "start_at": "2025-06-01T00:00:00Z", "end_at": "2025-08-31T23:59:59Z", "redeemable_from": "2025-06-01T00:00:00Z", "redeemable_to": "2025-09-30T23:59:59Z", "time_zone": "America/Los_Angeles", "fine_print": "Limit one per customer", "variants": [ { "id": "var_treat1", "name": "Treatment", "reward_template_id": "abc123def456" }, { "id": "var_ctrl1", "name": "Control", "reward_template_id": null } ] } ], "pagination": { "current_page": 1, "per_page": 10, "total_pages": 1 } } ``` # Respond to Feedback Source: https://docs.thanx.com/partner/feedbacks/feedback-response POST /partner/feedbacks/:id/respond This endpoint allows a merchant or partner to programmatically respond to a customer's feedback with a text-based response. This will trigger a message to the Thanx customer on behalf of the merchant. Only a single merchant response is allowed for a given feedback record. Scope required: `feedbacks.write` ### Parameters Feedback ID ### Parameters Merchant's response to the user's feedback ### Response ```bash theme={null} curl https://api.thanxsandbox.com/feedbacks/590485d6f0/response \ -X POST \ -H 'X-ClientId: {client_id}' \ -H 'Accept-Version: v4.0' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer {access_token}' \ -d '{ "feedback": { "response": "Merchant's written response to the customer's review." } }' ``` ```json theme={null} { "feedback": { "id": "590485d6f0", "user_id": "weorifsdf", "merchant_id": "9a1f0772c", "location_id": "fgr2349gh", "state": "reviewed", "purchased_at": "2020-01-05T20:00:00Z", "viewed_at": "2020-01-06T20:00:00Z", "rated_at": "2020-01-06T20:02:00Z", "reviewed_at": "2020-01-06T20:03:00Z", "responded_at": null, "expires_at": "2020-01-07T20:00:00Z", "rating": 10, "review": "Customer's written review for their latest purchase.", "response": "Merchant's written response to the customer's review.", "purchase": { "id": "wourhfiwer", "purchased_at": "2020-01-01T20:00:00Z", "amount": 9.99, "order": { "id": "aepo3cme2p", "provider": "Toast" } } } } ``` # Get Feedback Records Source: https://docs.thanx.com/partner/feedbacks/get-feedbacks GET /partner/feedbacks This endpoint will return all the feedback records of the specified merchant. Scope required: `feedbacks.read` ### Parameters Filter by Merchant ID Filter by User ID Filter by Location ID Filter by state (`unviewed`, `viewed`, `expired`, `rated`, `reviewed`, `responded`). The default is to return all feedback records regardless of state. Filter by the timestamp the feedback record was last updated (`ISO8601`-format) ### Response ```bash Get Feedbacks theme={null} curl https://api.thanxsandbox.com/partner/feedbacks \ -X GET \ -H 'X-ClientId: {client_id}' \ -H 'Accept-Version: v4.0' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer {access_token}' \ ``` ```json Response Example theme={null} { "feedbacks": [ { "id": "590485d6f0", "user_id": "fsjlk", "merchant_id": "woeri34", "location_id": "fgr2349gh", "state": "responded", "expires_at": "2020-01-07T20:00:00Z", "rating": 10, "review": "Customer's written review for their latest purchase.", "response": "Merchant's written response to the customer's review.", "purchase": { "id": "916895d48a", "purchased_at": "2020-01-01T20:00:00Z", "amount": 16.0, "order": { "id": "aepo3cme2p", "provider": "Toast" } } } ], "pagination": { "current_page": 1, "per_page": 10, "total_pages": 1 } } ``` # Get Issuance Job Source: https://docs.thanx.com/partner/issuance-jobs/get-issuance-job GET /partner/issuance_jobs/:id Returns the status of a reward issuance job Scope required: `rewards.issue` This endpoint returns the current status of a reward issuance job. Use this to poll for completion after initiating an issuance via [Issue Rewards](/partner/campaigns/issue-rewards). When the job reaches the `completed` state, a `summary` field is included with success and failure counts. If any issuances failed, the `summary` includes a `failures` array with details about each failure. ### Parameters Issuance job ID Merchant ID ### Response Issuance job ID Campaign ID Variant ID Job state: `pending`, `processing`, `completed`, or `failed` Total number of identifiers submitted Number of identifiers processed so far Number of rewards successfully issued Number of failed issuances Completion percentage (0-100) Job creation timestamp (ISO8601) Processing start timestamp (ISO8601), null if not started Processing completion timestamp (ISO8601), null if not completed Completion summary (only present when state is `completed`) Number of rewards successfully issued Number of failed issuances Failure details Position in the original identifiers array Identifier type (`email` or `phone`) Error message describing the failure ```bash Get Issuance Job theme={null} curl https://api.thanxsandbox.com/partner/issuance_jobs/job_xyz789?merchant_id={merchant_id} \ -X GET \ -H 'X-ClientId: {client_id}' \ -H 'Accept-Version: v4.0' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer {access_token}' ``` ```json Response Example theme={null} { "issuance_job": { "id": "job_xyz789", "campaign_id": "camp_abc123", "variant_id": "var_treat1", "state": "completed", "total_count": 2, "processed_count": 2, "success_count": 1, "failure_count": 1, "progress_percent": 100, "created_at": "2025-06-15T10:30:00Z", "started_at": "2025-06-15T10:30:05Z", "completed_at": "2025-06-15T10:30:15Z", "summary": { "success_count": 1, "failure_count": 1, "failures": [ { "identifier_index": 1, "identifier_type": "phone", "error": "User not found" } ] } } } ``` # Revoke Issuance Job Source: https://docs.thanx.com/partner/issuance-jobs/revoke-issuance-job POST /partner/issuance_jobs/:id/revoke Revoke all rewards issued by an issuance job Scope required: `rewards.issue` This endpoint revokes all rewards that were issued by a given issuance job. Revocation is processed asynchronously. The endpoint returns `202 Accepted` and the job transitions to a `revoking` state while rewards are being revoked in the background. Only issuance jobs in a `completed` or `failed` state can be revoked. Jobs that are `pending` or `processing` will return a `422` error. Jobs that are already `revoking` or `revoked` will also return a `422` error. ### Parameters Issuance job ID Merchant ID ### Response Returns `202 Accepted` with the issuance job object. Issuance job ID Campaign ID Variant ID Job state: `revoking` after a successful revocation request Total number of identifiers submitted Number of identifiers processed Number of rewards successfully issued Number of failed issuances Completion percentage (0-100) Job creation timestamp (ISO8601) Processing start timestamp (ISO8601) Processing completion timestamp (ISO8601) ```bash Revoke Issuance Job theme={null} curl https://api.thanxsandbox.com/partner/issuance_jobs/job_xyz789/revoke \ -X POST \ -H 'X-ClientId: {client_id}' \ -H 'Accept-Version: v4.0' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer {access_token}' \ -d '{ "merchant_id": "k2lye10h32l5wzo" }' ``` ```json 202 theme={null} { "issuance_job": { "id": "job_xyz789", "campaign_id": "camp_abc123", "variant_id": "var_treat1", "state": "revoking", "total_count": 2, "processed_count": 2, "success_count": 1, "failure_count": 1, "progress_percent": 100, "created_at": "2025-06-15T10:30:00Z", "started_at": "2025-06-15T10:30:05Z", "completed_at": "2025-06-15T10:30:15Z" } } ``` # Get Locations Source: https://docs.thanx.com/partner/metadata/get-locations GET /partner/locations This endpoint will return all accessible location records This endpoint can be used to fetch the IDs of all locations that are currently accessible to the integration partner. ```bash Get Merchants theme={null} curl https://api.thanxsandbox.com/partner/locations \ -H 'X-ClientId: ${client_id}' \ -H 'Accept-Version: v4.0' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer ${access_token}' \ ``` ### Parameters Filter by Merchant ID ### Response Location ID Merchant ID Location's street address Location's city Location's state Location's zip code The name of the location if it has one The phone number of the location ```json Response Example theme={null} { "locations": [ { "id": "92b7b0dac4", "merchant_id": "9a1f0772c9ac", "street": "123 Pizza Lane", "city": "Smalltown", "state": "CA", "zip": "12345", "name": "Pizza Town Co", "phone": "(415) 555-3728" } ], "pagination": { "current_page": 1, "per_page": 10, "total_pages": 1 } } ``` # Get Merchants Source: https://docs.thanx.com/partner/metadata/get-merchants GET /partner/merchants This endpoint will return all accessible merchants records This endpoint can be used to fetch the IDs of all merchants that are currently accessible to the integration partner. ```bash Get Merchants theme={null} curl https://api.thanxsandbox.com/partner/merchants \ -H 'X-ClientId: ${client_id}' \ -H 'Accept-Version: v4.0' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer ${access_token}' \ ``` ### Response Merchant ID Merchant Handle. This is used as a long-lived unique descriptive identifier for the merchant across the Thanx platform. Merchant Name ```json Response Example theme={null} { "merchants": [ { "id": "k2lye10h32l5wzo", "name": "Pizza Company", "handle": "pizzacompany" } ] } ``` # Get Scopes Source: https://docs.thanx.com/partner/metadata/get-scopes GET /partner/scopes Returns API scopes accessible to the current credentials This endpoint can be used to list out the scopes the API credentials currently has access to. ```bash Get Scopes theme={null} curl https://api.thanxsandbox.com/partner/scopes \ -H 'X-ClientId: ${client_id}' \ -H 'Accept-Version: v4.0' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer ${access_token}' \ ``` ### Response Scope granted to API credential being used ```json Response Example theme={null} { "scopes": [ "subscribers.write" ] } ``` # Overview Source: https://docs.thanx.com/partner/overview These APIs are designed to be leveraged by integrating partners and merchants to fulfill a variety of non-consumer UX integration use-cases. If you are a new partner that is interested in establishing a partnership and building technical integration with the Thanx platform, please reach out to [partnerships@thanx.com](mailto:partnerships@thanx.com). For partners who already have API access, each API credential is configured with an agreed upon scope — granting access to a subset of the API endpoints available. Each partnership API endpoint has a section describing the required scopes. The [GET /scopes](/partner/metadata/get-scopes) endpoint can be used to list the scopes your API credentials have access to. ## Environments All integrations should be developed against the sandbox Thanx API environment. Before production API credentials are issued, integrations should be certified with the Thanx team. The Partner API is served from the following base URLs: | Environment | Base URL | | ----------- | ------------------------------ | | Sandbox | `https://api.thanxsandbox.com` | | Production | `https://api.thanx.com` | Partner API endpoints are served under the `/partner/*` path prefix (for example, `https://api.thanxsandbox.com/partner/locations`). All examples in this reference use the sandbox base URL. Swap in the production URL once your integration has been certified and production credentials have been issued. ## Certification Once your integration has been built and developed against the sandbox environment, please reach out to [developer.support@thanx.com](mailto:developer.support@thanx.com) go through a lightweight but mandatory certification process. For basic integration use-cases, certification is quick and normally takes no more than a few days depending on the scope of integration. This process is mainly designed to ensure the integration is working as intended without risking any negative impact on live customers (merchant or consumer). Each net new integration use-case should be re-certified as new use-cases will very likely require different scoping. Launching new merchants on certified integration use-cases does not require re-certification. ### Product Guide ## Access Upon gaining access to the Thanx APIs, integration partners will be issued the following: * Client ID - used in the required `X-ClientId` header * Access Token - used in the required `Authorization` header These credentials grant access to all merchants that have explicitly opted into the specified integration. All merchants accessible to these credentials can be listed in [GET /merchants](/partner/metadata/get-merchants). ## Headers | HEADER | Value | Description | | ---------------- | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Authorization` | `Bearer {access_token}` | This value should be set to provided access token | | `X-ClientId` | `{client_id}` | This value should be set to the provided client ID | | `Accept-Version` | `v4.0` | This value **must** be specified in API calls. This denotes the current API version that is in use. Any other value specified will cause undefined behavior and may risk API access revokation. | | `Content-Type` | `application/json` | This value specifies the request body format. Only JSON is supported at this time. | | `User-Agent` | `{partner}/1.0.0` | This value should be set to something that indicates the name of the partner. This is useful for debugging purposes. | ## Postman API Collection Here you will find the **Partner API Postman Collection** to import directly within your API testing tool. This collection is already completed and includes sample values for the credentials. Please replace them with the ones provided by your Thanx representative in order to achieve successful API calls. Download Postman Collection ## Global Rate Limits Integration partners should not exceed a rate of 5 requests per second and 2,000 requests per 15 minutes. These default rate limits are hard-limits and APIs will return `429 Too Many Requests` once these limits are crossed. Rate-limited API requests can and should be retried. One such strategy to handle this is through an exponential backoff strategy. Should your specific integration use-case require higher API throughput, please reach out to [developer.support@thanx.com](mailto:developer.support@thanx.com) to request an increase to these default values. # Create Promotion Source: https://docs.thanx.com/partner/promotions/create-promotion POST /partner/promotions Create a new promotion for a merchant Scope required: `promos.write` This endpoint creates a new promotion for the specified merchant. It mirrors the functionality available in the Thanx dashboard: it creates the promotion's underlying program and redeem configuration, and — depending on how codes are requested — its initial code pool. For the full lifecycle — creating a promotion, generating codes, dispensing them to customers, and replenishing — see the [Promotions Overview](/partner/promotions/overview). ### Code Pools How you supply codes at creation determines the pool that is created: * **`static_code`** — creates a `multi_use` pool containing a single shared code that can be redeemed multiple times (a "universal" code). The pool is marked complete immediately. * **`code_count`** — creates a `single_use` pool and enqueues asynchronous generation of that many unique one-time codes. Poll [Get Promotion](/partner/promotions/get-promotion) until `code_generation_status` is `complete`, then fetch the codes with [List Promotion Codes](/partner/promotions/list-codes). Additional single-use codes can later be generated with [Generate Promotion Codes](/partner/promotions/generate-codes). * **Neither** — the promotion is created without any codes. `static_code` and `code_count` are mutually exclusive. ### Parameters Merchant ID Promotion name Type of discount: `amount`, `percent`, or `item` Discount amount. Interpreted according to `discount_type` (for example, a percentage for `percent` or a currency amount for `amount`). Minimum spend required to redeem Maximum discount that can be applied (where supported by the discount type) Terms and conditions Redemption instructions shown to the customer Where the promotion can be redeemed: `all`, `instore`, or `online`. Defaults to `instore`. When the promotion becomes active (ISO8601) When the promotion ends (ISO8601). Must be after `starts_at`. A single shared code to create as a `multi_use` pool. Mutually exclusive with `code_count`. Number of unique one-time codes to generate as a `single_use` pool (1–4,000,000). Generation runs asynchronously. Mutually exclusive with `static_code`. Initial state: `active` or `draft`. Defaults to `active`. Draft promotions are managed in the Thanx dashboard — the read endpoints ([List Promotions](/partner/promotions/list-promotions), [Get Promotion](/partner/promotions/get-promotion)) return only `active` promotions. Optional day-of-week and time-of-day restrictions on when the promotion can be redeemed. Write-only: these are applied at creation and viewed or edited in the Thanx dashboard; they are not returned by the read endpoints. Whether time-based restrictions are enforced Time zone the restriction hours are evaluated in (IANA name, e.g. `America/Los_Angeles`) Hours (0–23) the promotion is redeemable on Monday. Repeat for `tuesday` through `sunday`. Restrict redemption to specific location IDs ### Response Returns `201 Created` with the newly created promotion. The response uses the same shape as [Get Promotion](/partner/promotions/get-promotion). Promotion ID Promotion name Promotion state (`active` or `draft`) Type of discount the promotion applies: `percent`, `item`, or `amount` Discount amount, as a string. Null if not set. Minimum spend required to redeem, as a string. Null if not set. Maximum discount that can be applied, as a string. Null if not set. Terms and conditions Where the promotion can be redeemed Promotion start timestamp (ISO8601). Null if not set. Promotion end timestamp (ISO8601). Null if not set. How the pool's codes are generated: `multi_use` or `single_use`. Null if no pool was created. Number of times codes in the active pool have been redeemed Total number of codes in the active pool Status of asynchronous code generation for the active pool: `none` (no codes requested), `in_progress`, `complete`, or `failed` ```bash Create Promotion (single-use codes) theme={null} curl https://api.thanxsandbox.com/partner/promotions \ -X POST \ -H 'X-ClientId: {client_id}' \ -H 'Accept-Version: v4.0' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer {access_token}' \ -d '{ "merchant_id": "k2lye10h32l5wzo", "name": "Summer 20% Off", "discount_type": "percent", "discount_value": 20, "minimum_spend": 25, "fine_print": "Limit one per customer", "redemption_venue": "online", "starts_at": "2026-06-01T00:00:00Z", "ends_at": "2026-08-31T23:59:59Z", "code_count": 10000 }' ``` ```bash Create Promotion (universal shared code) theme={null} curl https://api.thanxsandbox.com/partner/promotions \ -X POST \ -H 'X-ClientId: {client_id}' \ -H 'Accept-Version: v4.0' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer {access_token}' \ -d '{ "merchant_id": "k2lye10h32l5wzo", "name": "Launch Week", "discount_type": "amount", "discount_value": 5, "redemption_venue": "all", "static_code": "LAUNCH5" }' ``` ```json 201 theme={null} { "promotion": { "id": "promo_abc123", "name": "Summer 20% Off", "state": "active", "discount_type": "percent", "discount_value": "20.0", "minimum_spend": "25.0", "maximum_discount": null, "fine_print": "Limit one per customer", "redemption_venue": "online", "starts_at": "2026-06-01T00:00:00Z", "ends_at": "2026-08-31T23:59:59Z", "generation_type": "single_use", "redemption_count": 0, "total_codes": 0, "code_generation_status": "in_progress" } } ``` ```json 422 theme={null} { "error": { "code": "UNPROCESSABLE_ENTITY", "message": "static_code and code_count are mutually exclusive" } } ``` # Generate Promotion Codes Source: https://docs.thanx.com/partner/promotions/generate-codes POST /partner/promotions/:id/codes Add a batch of single-use codes to an existing promotion Scope required: `promos.write` This endpoint adds a batch of unique single-use codes to an existing promotion — use it to top up (replenish) a promotion whose supply of unredeemed codes is running low. The promotion can be created via [Create Promotion](/partner/promotions/create-promotion) or in the Thanx dashboard. Codes are added to the promotion's active `single_use` pool (one is created if the promotion does not have an active pool yet), so newly generated codes are retrievable through [List Promotion Codes](/partner/promotions/list-codes) alongside the existing ones. By default, codes are 8-character, uppercase, alphanumeric values (the letters `I`, `L`, and `O` are excluded to avoid ambiguity). Use `prefix` and `code_length` to customize their format. Generation runs asynchronously. The endpoint returns immediately with a `202 Accepted` response describing the generation request. Poll [Get Promotion](/partner/promotions/get-promotion) until `code_generation_status` is `complete`, then fetch the new codes with [List Promotion Codes](/partner/promotions/list-codes). ### Per-Request Cap A single request may generate up to `100,000` codes. Requests above this cap return a `422 Unprocessable Entity` error. To add more than 100,000 codes, submit multiple requests. (For a larger initial pool, `code_count` on [Create Promotion](/partner/promotions/create-promotion) accepts up to 4,000,000 in a single call.) ### Idempotency This endpoint supports idempotent requests via the `X-Idempotency-Key` header. When provided, duplicate requests with the same key return the cached response from the original request rather than generating codes again. If the request body differs from the original, a `422 Unprocessable Entity` error is returned. We strongly recommend sending an idempotency key so that a retried request does not silently double-generate codes. ### Parameters Promotion ID Merchant ID Number of codes to generate (1–100,000) Optional prefix prepended to each generated code (e.g., `FIVEGUYS`). Length of the random portion of each code (4–20). Defaults to `8`. Optional idempotency key to prevent duplicate code generation. ### Response Returns `202 Accepted` describing the accepted generation request. Promotion ID the codes are generated for ID of the pool the codes are added to Number of codes requested Generation status: `in_progress`, `complete`, or `failed`. This is the same value exposed as `code_generation_status` on [Get Promotion](/partner/promotions/get-promotion), which you poll until it reaches `complete`. ```bash Generate Promotion Codes theme={null} curl https://api.thanxsandbox.com/partner/promotions/promo_abc123/codes \ -X POST \ -H 'X-ClientId: {client_id}' \ -H 'Accept-Version: v4.0' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer {access_token}' \ -H 'X-Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000' \ -d '{ "merchant_id": "k2lye10h32l5wzo", "count": 10000 }' ``` ```json 202 theme={null} { "code_generation": { "promotion_id": "promo_abc123", "pool_id": "pool_def456", "requested_count": 10000, "status": "in_progress" } } ``` ```json 422 theme={null} { "error": { "code": "UNPROCESSABLE_ENTITY", "message": "count must be an integer between 1 and 100000" } } ``` # Get Promotion Source: https://docs.thanx.com/partner/promotions/get-promotion GET /partner/promotions/:id Returns a single active promotion Scope required: `promos.read` This endpoint returns a single active promotion for the merchant. The promotion must belong to the specified merchant and be in the `active` state, otherwise a `404 Not Found` is returned. The fields of the promotion's active code pool are flattened onto the promotion, including `generation_type`, `redemption_count`, and `total_codes`. ### Parameters Promotion ID Merchant ID ### Response Promotion ID Promotion name Promotion state (always `active`) Type of discount the promotion applies: `percent`, `item`, or `amount` Discount amount, as a string. Null if not set. Minimum spend required to redeem, as a string. Null if not set. Maximum discount that can be applied, as a string. Null if not set. Terms and conditions Where the promotion can be redeemed: `all`, `instore`, or `online` Promotion start timestamp (ISO8601). Null if not set. Promotion end timestamp (ISO8601). Null if not set. How the pool's codes are generated: `multi_use` (a shared code redeemable multiple times) or `single_use` (a batch of one-time codes). Null if the promotion has no code pool. Number of times codes in the active pool have been redeemed Total number of codes in the active pool Status of asynchronous code generation for the active pool: `none`, `in_progress`, `complete`, or `failed`. Poll this field after requesting code generation via [Create Promotion](/partner/promotions/create-promotion) or [Generate Promotion Codes](/partner/promotions/generate-codes). ```bash Get Promotion theme={null} curl https://api.thanxsandbox.com/partner/promotions/promo_abc123?merchant_id={merchant_id} \ -X GET \ -H 'X-ClientId: {client_id}' \ -H 'Accept-Version: v4.0' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer {access_token}' ``` ```json Response Example theme={null} { "promotion": { "id": "promo_abc123", "name": "Summer 20% Off", "state": "active", "discount_type": "percent", "discount_value": "20.0", "minimum_spend": "25.0", "maximum_discount": "10.0", "fine_print": "Limit one per customer", "redemption_venue": "online", "starts_at": "2026-06-01T00:00:00Z", "ends_at": "2026-08-31T23:59:59Z", "generation_type": "single_use", "redemption_count": 142, "total_codes": 10000, "code_generation_status": "complete" } } ``` ```json 404 theme={null} { "error": { "code": "NOT_FOUND", "message": "Promotion not found" } } ``` # List Promotion Codes Source: https://docs.thanx.com/partner/promotions/list-codes GET /partner/promotions/:id/codes Returns the codes for a promotion's active pool Scope required: `promos.read` This endpoint returns the codes belonging to a promotion's active code pool, ordered oldest first. The promotion must belong to the specified merchant and be in the `active` state, otherwise a `404 Not Found` is returned. If the promotion has no active pool, an empty `codes` array is returned with zero total pages. To pull codes to hand out to customers, filter by `status=unredeemed`. Note that a code stays `unredeemed` until the customer redeems it at the point of sale — not when you send it — so you must track which codes you have already dispensed on your side. See [Dispensing codes to customers](/partner/promotions/overview#dispensing-codes-to-customers). ### Parameters Promotion ID Merchant ID Filter by redemption status: `unredeemed` or `redeemed`. Omit to return all codes. The current page of paginated codes. * Default: `1` Number of codes to return per request. * Default: `500` * Minimum: `1` * Maximum: `10000` ### Response The promotion code Redemption status: `redeemed` if the code has been redeemed at least once, otherwise `unredeemed` ```bash List Promotion Codes theme={null} curl 'https://api.thanxsandbox.com/partner/promotions/promo_abc123/codes?merchant_id={merchant_id}&status=unredeemed&per_page=500' \ -X GET \ -H 'X-ClientId: {client_id}' \ -H 'Accept-Version: v4.0' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer {access_token}' ``` ```json Response Example theme={null} { "codes": [ { "code": "A1B2C3D4", "status": "unredeemed" }, { "code": "7QMX9K2P", "status": "redeemed" } ], "pagination": { "current_page": 1, "per_page": 500, "total_pages": 20 } } ``` # List Promotions Source: https://docs.thanx.com/partner/promotions/list-promotions GET /partner/promotions Returns active promotions for a merchant Scope required: `promos.read` This endpoint returns the merchant's active promotions, most recently created first. Only promotions in the `active` state are returned. Each promotion flattens the fields of its active code pool onto the promotion (a promotion has one active pool in practice), including the code `generation_type`, the running `redemption_count`, and `total_codes`. ### Parameters Merchant ID ### Response Promotion ID Promotion name Promotion state (always `active` for listed promotions) Type of discount the promotion applies: `percent`, `item`, or `amount` Discount amount, as a string. Null if not set. Minimum spend required to redeem, as a string. Null if not set. Maximum discount that can be applied, as a string. Null if not set. Terms and conditions Where the promotion can be redeemed: `all`, `instore`, or `online` Promotion start timestamp (ISO8601). Null if not set. Promotion end timestamp (ISO8601). Null if not set. How the pool's codes are generated: `multi_use` (a shared code redeemable multiple times) or `single_use` (a batch of one-time codes). Null if the promotion has no code pool. Number of times codes in the active pool have been redeemed Total number of codes in the active pool Status of asynchronous code generation for the active pool: `none`, `in_progress`, `complete`, or `failed` ```bash List Promotions theme={null} curl https://api.thanxsandbox.com/partner/promotions?merchant_id={merchant_id} \ -X GET \ -H 'X-ClientId: {client_id}' \ -H 'Accept-Version: v4.0' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer {access_token}' ``` ```json Response Example theme={null} { "promotions": [ { "id": "promo_abc123", "name": "Summer 20% Off", "state": "active", "discount_type": "percent", "discount_value": "20.0", "minimum_spend": "25.0", "maximum_discount": "10.0", "fine_print": "Limit one per customer", "redemption_venue": "online", "starts_at": "2026-06-01T00:00:00Z", "ends_at": "2026-08-31T23:59:59Z", "generation_type": "single_use", "redemption_count": 142, "total_codes": 10000, "code_generation_status": "complete" } ], "pagination": { "current_page": 1, "per_page": 10, "total_pages": 1 } } ``` # Promotions Overview Source: https://docs.thanx.com/partner/promotions/overview How to create promotions, generate codes, and dispense them to customers Promotions let a partner (for example, a marketing platform such as Klaviyo) issue discount codes to a merchant's customers. This guide explains the code model and the end-to-end workflow, including how to hand out unique one-time codes and replenish them as they run out. ## Code Models A promotion holds its codes in a **pool**. The pool's `generation_type` determines how codes behave: * **`multi_use`** — a single shared code (a "universal" code) that many customers can redeem. Created by supplying `static_code` at [creation](/partner/promotions/create-promotion). * **`single_use`** — a batch of unique, one-time codes, each intended for a single customer. Created by supplying `code_count` at creation, and topped up later with [Generate Promotion Codes](/partner/promotions/generate-codes). ## End-to-End Workflow Call [Create Promotion](/partner/promotions/create-promotion). For unique one-time codes, pass `code_count`; for a single shared code, pass `static_code`. The response returns the promotion `id`. `single_use` code generation runs asynchronously. Poll [Get Promotion](/partner/promotions/get-promotion) until `code_generation_status` is `complete` (or `failed`). Call [List Promotion Codes](/partner/promotions/list-codes) with `status=unredeemed` to pull codes that have not been redeemed yet — one at a time, or up to 10,000 per page. Assign each fetched code to exactly one recipient before sending it. See [Dispensing codes](#dispensing-codes-to-customers) below for the important caveat about tracking assignment on your side. When your supply of unredeemed codes runs low, call [Generate Promotion Codes](/partner/promotions/generate-codes) to add more to the same promotion. They become available through List Promotion Codes once generation completes. ## Dispensing Codes to Customers A single-use code is intended for one customer, but the API only knows whether a code has been **redeemed** (used at the point of sale) — not whether you have already **handed it out**. A code you emailed to a customer this morning is still `unredeemed` until they actually use it. This means you must track assignment on your side: * Fetch a batch of `unredeemed` codes and record which recipient you assign each one to. * Never send the same code to two customers. Because a just-sent code is still `unredeemed`, the API cannot dedupe this for you. * Use your own record of assigned codes — not the API's `unredeemed` count — to decide when to [replenish](/partner/promotions/generate-codes). This is the standard integration pattern for marketing platforms that manage their own send/replenishment logic. ## Reconciling Redemptions Once a customer redeems a code, it reports `status: redeemed` in [List Promotion Codes](/partner/promotions/list-codes), and the promotion's `redemption_count` and `total_codes` ([Get Promotion](/partner/promotions/get-promotion)) reflect overall usage. # Create Purchase Source: https://docs.thanx.com/partner/purchases/create-purchase POST /purchases This endpoint submits a purchase to Thanx for processing. This allows for issuance of loyalty points to the given user. Scope required: `purchases.write` ### Parameters Merchant ID User ID The purchase amount Time the purchase was made in ISO8601 format Location ID Card ID that the user used, if it is registered in Thanx Optionally specified array of product strings to associate with the purchase ### Response ```bash theme={null} curl https://api.thanxsandbox.com/purchases \ -X POST \ -H 'X-ClientId: {client_id}' \ -H 'Accept-Version: v4.0' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer {access_token}' \ -d '{ "purchase": { "merchant_id": "weoru", "location_id": "hljkfd2345", "user_id": "wgljsdwer23", "card_id": null "amount": 13.45, "purchased_at": "2020-09-15T00:52:10.655+00:00", "products": ["coffee", "pizza"] } }' ``` ```json theme={null} {} ``` # Get Reward Template Source: https://docs.thanx.com/partner/reward-templates/get-reward-template GET /partner/reward_templates/:id Returns a specific published reward template Scope required: `rewards.issue` This endpoint returns a specific published reward template for a given merchant. ### Parameters Reward template ID Merchant ID ### Response Reward template ID Template name Reward type Reward subtype Short description of the reward Terms and conditions Discount details Where the reward can be redeemed Image URLs for the reward template ```bash Get Reward Template theme={null} curl https://api.thanxsandbox.com/partner/reward_templates/abc123def456?merchant_id={merchant_id} \ -X GET \ -H 'X-ClientId: {client_id}' \ -H 'Accept-Version: v4.0' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer {access_token}' ``` ```json Response Example theme={null} { "reward_template": { "id": "abc123def456", "name": "Free Coffee", "type": "discount", "subtype": "free_item", "description": "One free coffee, any size", "fine_print": "Valid at participating locations", "discount": { "type": "free_item", "value": null }, "redemption_venue": "in_store", "images": { "small": "https://images.thanx.com/reward_template_small.png", "large": "https://images.thanx.com/reward_template_large.png" } } } ``` # List Reward Templates Source: https://docs.thanx.com/partner/reward-templates/list-reward-templates GET /partner/reward_templates Returns published reward templates for a merchant Scope required: `rewards.issue` This endpoint returns all published reward templates for a given merchant. Reward templates define the type of reward that can be issued through a campaign. Use these templates when creating campaigns to specify what reward each variant will offer. ### Parameters Merchant ID ### Response Reward template ID Template name Reward type Reward subtype Short description of the reward Terms and conditions Discount details Where the reward can be redeemed Image URLs for the reward template ```bash List Reward Templates theme={null} curl https://api.thanxsandbox.com/partner/reward_templates?merchant_id={merchant_id} \ -X GET \ -H 'X-ClientId: {client_id}' \ -H 'Accept-Version: v4.0' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer {access_token}' ``` ```json Response Example theme={null} { "reward_templates": [ { "id": "abc123def456", "name": "Free Coffee", "type": "discount", "subtype": "free_item", "description": "One free coffee, any size", "fine_print": "Valid at participating locations", "discount": { "type": "free_item", "value": null }, "redemption_venue": "in_store", "images": { "default": "https://images.thanx.com/reward_template.png" } } ], "pagination": { "current_page": 1, "per_page": 10, "total_pages": 1 } } ``` # Create Subscriber Source: https://docs.thanx.com/partner/subscribers/create-subscriber POST /partner/subscribers Scope required: `subscribers.write` This endpoint opts an email address into the specified merchant's loyalty marketing. This will enable merchants to send targeted marketing to these subscribers in order to encourage loyalty opt-in. It is expected that all user information provided to Thanx via API must have gotten explicit user consent to participate in the merchant's marketing. For integrations intending to sign up a user directly for a merchant's loyalty program should be integrating with the [Consumer APIs](/consumer/overview). This integration is more intensive, as it requires strict compliance with the [legal requirements for user creation](/consumer/usage/legal) and must include a complete enrollment flow (prompt users for card linkage, display introductory incentives). Please reach out to our team at [developer.support@thanx.com](mailto:developer.support@thanx.com) if you are interested in this type of integration instead. This endpoint only requires `merchant_id` and `email` to be specified, but accepts additional subscriber information. This endpoint responds with a `201` for any valid email address that is sent, even if the email address is already captured in the system. To avoid unintentional PII exposure for existing records in the system, this API responds only with accepted email address. The only time this endpoint `400`s is when the input email address is invalid. ### Body Filter by Merchant ID The subscriber's email The subscriber's first name The subscriber's last name The subscriber's birthday information The subscriber's birth year The subscriber's birth month The subscriber's birth day The subscriber's zip code ```bash Create a new subscriber theme={null} curl https://api.thanxsandbox.com/partner/subscribers/ \ -X POST \ -H 'X-ClientId: {client_id}' \ -H 'Accept-Version: v4.0' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer {access_token}' \ -d '{ "merchant_id": "owierywtwt", "subscriber": { "email": "jane.smith@example.com", "first_name": "Jane", "last_name": "Smith", "birth_date": { "month": 8, "day": 14 }, "zip_code": "12345" } }' ``` ### Response The newly created subscriber The subscriber's email ```json 201 theme={null} { "subscriber": { "email": "jane.smith@example.com" } } ``` ```json 400 theme={null} { "error": { "code": "BAD_REQUEST", "message": "Email does not appear to be valid" } } ``` # Delete Tags Source: https://docs.thanx.com/partner/tags/delete-tags DELETE /partner/tags Scope required: `tags.write` This endpoint allows for bulk deletion of tags ### Parameters Merchant ID User IDs (500 max per request) `user_ids` must be each user's Thanx identifier — the value returned as `id` by [Get Users](/partner/users/get-users). An ID copied from a dashboard URL or a customer-data/SFTP export is a **different encoding** and will not match: the request returns `200` with **zero tags deleted** and no error. Confirm one test user matches before running a bulk delete. Tag Key ### Response ```bash theme={null} curl https://api.thanxsandbox.com/partner/tags \ -X DELETE \ -H 'X-ClientId: {client_id}' \ -H 'Accept-Version: v4.0' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer {access_token}' \ -d '{ "merchant_id": "weroifs", "user_ids": [ "wroeiu2304hfwf", "73bf1f46769dwr" ], "key": "allergens" }' ``` ```json 200 theme={null} {} ``` # Get Tags Source: https://docs.thanx.com/partner/tags/get-tags GET /partner/tags Scope required: `tags.read` This endpoint returns paginated tags for the specified users. ### Parameters Filter tags by Merchant ID Filter tags by User IDs Optionally filter tags by key ### Response ```bash Get Tags theme={null} curl https://api.thanxsandbox.com/partner/tags \ -X GET \ -H 'X-ClientId: {client_id}' \ -H 'Accept-Version: v4.0' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer {access_token}' \ ``` ```json theme={null} { "tags": [ { "id": "92b7b0dac4", "user_id": "wroeiu2304hfwf", "merchant_id": "weroif", "key": "allergens", "values": ["gluten", "soy", "dairy"] } ], "pagination": { "current_page": 1, "per_page": 10, "total_pages": 1 } } ``` # Upsert Tags Source: https://docs.thanx.com/partner/tags/upsert-tags PUT /partner/tags Scope required: `tags.write` This endpoint allows for bulk upserting of tag values for specified users. If a tag with the specified key does not exist for the user / merchant pair, a new tag record is created with the specified values. If a tag with the specified key already exists, the tag values are updated. A maximum of 500 `user_ids` can be specified per API request. Currently, tags are merchant/user-scoped. This means that they are accessible to be managed by all integration partners a given merchant enables. Given this, for tags that are integration-specific and not general purpose user profile attributes, we recommend integration partners prefix tag keys with the name of your organization to avoid key usage conflicts between integrations enabled for a given merchant. eg: * `thanx-custom-tag`, rather than `custom-tag`, would be preferred for tags that are integration specific * `allergens` should still be used, if it's expected that the tag be leveraged as a general-purpose user profile attribute Tag keys are case-insensitive — `Employee` and `employee` are treated as the same key (writing one overwrites the other's values), so use a consistent lowercase-with-hyphens convention. ### Parameters Merchant ID User IDs (500 max per request) `user_ids` must be each user's Thanx identifier — the value returned as `id` by [Get Users](/partner/users/get-users). An ID copied from a dashboard URL or a customer-data/SFTP export is a **different encoding** and will not match: the request returns `201` with **zero tags written** and no error. Confirm one test user lands before running a bulk write. Tag key Array of tag values (50 max) ### Response ```bash theme={null} curl https://api.thanxsandbox.com/partner/tags \ -X PUT \ -H 'X-ClientId: {client_id}' \ -H 'Accept-Version: v4.0' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer {access_token}' \ -d '{ "merchant_id": "weroifs", "user_ids": [ "wroeiu2304hfwf", "73bf1f46769dwr" ], "key": "allergens", "values": [ "gluten", "soy", "dairy", "honey" ] }' ``` ```json 201 theme={null} {} ``` # Get User's Communication Settings Source: https://docs.thanx.com/partner/users/communication-settings/get GET /partner/users/:id/communication_settings This endpoint returns a user's communication settings for the specified merchant. The notification key reflects a user's settings for receiving push notifications in their app or via text if they don't have an app installed. The email key reflects a user's settings for receiving emails. Scopes: `users.read`, `communication_settings.read` ### Parameters User ID Merchant ID ### Response ```bash Get Communication Settings theme={null} curl https://api.thanxsandbox.com/partner/users/:id/communication_settings \ -X GET \ -H 'X-ClientId: {client_id}' \ -H 'Accept-Version: v4.0' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer {access_token}' \ ``` ```json theme={null} { "communication_setting": { "id": "weori234098", "merchant_id": "owierywtwt", "merchant_handle": "example-merchant", "user_id": "woeruijsfwer", "reward_progress": { "email": true }, "reward_offer": { "notification": true, "email": true }, "marketing_general": { "email": true, "sms":false } } } ``` # Update User's Communication Settings Source: https://docs.thanx.com/partner/users/communication-settings/update PATCH /partner/users/:id/communication_settings This endpoint allows the update of a user's notification / email settings for the specified merchant. Scopes: `users.write`, `communication_settings.write` ### Parameters User ID Merchant ID Settings for when a user earns loyalty progress email setting Settings for when a merchant sends an offer app notification setting email setting Settings for when a merchant sends general marketing email setting ### Response ```bash theme={null} curl https://api.thanxsandbox.com/partner/users/:id/communication_settings?merchant_id=owierywtwt \ -X PATCH \ -H 'X-ClientId: {client_id}' \ -H 'Accept-Version: v4.0' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer {access_token}' \ -d '{ "communication_setting": { "reward_progress": { "email": false }, "reward_offer": { "notification": false, "email": false }, "marketing_general": { "email": false } } }' ``` ```json theme={null} { "communication_setting": { "id": "weoruoisdhf", "merchant_id": "owierywtwt", "merchant_handle": "example-merchant", "user_id": "woerushfwe", "reward_progress": { "email": true }, "reward_offer": { "notification": true, "email": true }, "marketing_general": { "email": true } } } ``` # Get User Source: https://docs.thanx.com/partner/users/get-user GET /partner/users/:id This endpoint will return one particular user of the specified merchant. Scope required: `users.read` The user's phone number is not gathered by Thanx with the permission to use it for marketing. ### Parameters User ID Merchant ID ### Response ```bash Get User theme={null} curl https://api.thanxsandbox.com/partner/users/:id \ -X GET \ -H 'X-ClientId: {client_id}' \ -H 'Accept-Version: v4.0' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer {access_token}' \ ``` ```json Response Example theme={null} { "user": { "id": "wroeiu2304hfwf", "email": "john.smith@example.com", "phone": "+14158672345", "first_name": "Jane", "last_name": "Smith", "birth_date": { "year": 1987, "month": 8, "day": 14 }, "zip_code": "12345", "updated_at": "2025-02-01T19:00:00Z", "loyalty": { "tier": "silver", "points_balance": 120.50, "user_joined_at": "2023-12-01T19:00:00Z" }, "communication_settings": { "marketing_general_email": true } } } ``` # Get Users Source: https://docs.thanx.com/partner/users/get-users GET /partner/users This endpoint will return all the users of the specified merchant. Scope required: `users.read` The user's phone number is not gathered by Thanx with the permission to use it for marketing. The Partner API exposes users **read-only**. To create or enroll a user, use the Consumer API [`POST /users`](/consumer/users/create-user). ### Parameters Filter by Merchant ID Optionally filter by email. If there is a match, a single user record will be returned. Optionally filter by phone. If there is a match, a single user record will be returned. This value is expected to be in [E.164 format](https://www.twilio.com/docs/glossary/what-e164). Phone numbers must be in E.164 format with the country code prefix (e.g. `+14155551212`). For US numbers and US territories, the prefix is `+1`, including Puerto Rico (787/939), USVI (340), Guam (671), Northern Mariana Islands (670), and American Samoa (684). Numbers without the country code prefix may be parsed as international and return `Unknown user`. Optionally filter by records updated after specified `updated_after` timestamp. Optionally filter by records updated before specified `updated_before` timestamp. Optionally include loyalty attributes in response. Defaults to `false`. Optionally include communication setting attributes in response. Defaults to `false`. ### Response ```bash Get Users theme={null} curl https://api.thanxsandbox.com/partner/users \ -X GET \ -H 'X-ClientId: {client_id}' \ -H 'Accept-Version: v4.0' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer {access_token}' \ ``` ```json Response Example theme={null} { "users": [ { "id": "wroeiu2304hfwf", "email": "john.smith@example.com", "phone": "+14158672345", "first_name": "Jane", "last_name": "Smith", "birth_date": { "year": 1987, "month": 8, "day": 14 }, "zip_code": "12345", "updated_at": "2025-02-01T19:00:00Z", "loyalty": { "tier": "silver", "points_balance": 120.50, "user_joined_at": "2023-12-01T19:00:00Z" }, "communication_settings": { "marketing_general_email": true } } ], "pagination": { "current_page": 1, "per_page": 10, "total_pages": 1 } } ``` # Communication Settings Source: https://docs.thanx.com/webhooks/communication-settings These webhooks are sent anytime a user's communication settings are updated. ### Payload Description Communication Setting ID Merchant ID User ID Settings for when a user earns loyalty progress email setting Settings for when a merchant sends an offer app notification setting email setting Settings for when a merchant sends general marketing email setting ```json theme={null} { "communication_setting": { "id": "weori234098", "merchant_id": "owierywtwt", "user_id": "woeruijsfwer", "reward_progress": { "email": true }, "reward_offer": { "notification": true, "email": true }, "marketing_general": { "email": true } } } ``` # Overview Source: https://docs.thanx.com/webhooks/overview In addition to standard SFTP data exports, the Thanx platform supports a variety of webhooks. These webhooks allow for integrating platforms to respond in realtime to changes to data resources in the Thanx platform. If you are an existing integration partner, please reach out to our team at [developer.support@thanx.com](mailto:developer.support@thanx.com) to have webhooks enabled. ## Requirements Webhook endpoints must be valid HTTPS URLs. Requests will be sent as `POST` requests and expect the receiving servers to respond to requests within 15 seconds. By default, webhooks are not configured to retry if the receiving server responds with an error. Any missed data can be collected via bulk data transfer mechanisms. ## Delivery Semantics Webhook delivery is **not exactly-once**. The same event can be delivered more than once, and each individual delivery is best-effort — failed deliveries are not retried (see [Requirements](#requirements)), so delivery of any single event is not guaranteed. Duplicates are the common case, and this is most pronounced for [purchase](/webhooks/purchases) webhooks: a single purchase is re-sent as it moves through authorization and settlement, and across payment rails, with every delivery carrying the same purchase `id`. Design your consumer to be idempotent: deduplicate on the payload's stable identifier (for purchases, this is `id`) and treat repeat deliveries as updates rather than new events. Where a field can be refined over a resource's lifecycle (such as a purchase `amount`), prefer the latest delivery. The payload carries no delivery sequence or timestamp, so treat the last delivery you receive for an `id` as the current state; for purchases, authorization and settlement fires are typically days apart, so arrival order tracks lifecycle order. ## Query Parameters When configuring a webhook endpoint, query parameters may be appended to the URL. These parameters will be included with every webhook request. **Example:** [https://example.com/webhook?client\_id=abc123\&env=sandbox](https://example.com/webhook?client_id=abc123\&env=sandbox) In this example, Thanx will send each `POST` request to the exact URL above, including the query parameters. **Notes** * Query parameters are static and defined at the time the webhook URL is registered. * They are not modified or validated by Thanx. * Sensitive values should not be placed in query parameters. When an integration authenticates via a static query parameter (e.g. an `apiKey`), that value is fixed at registration and sent on every delivery. Rotating it requires re-registering the webhook URL with Thanx — a stale credential will cause your endpoint to reject deliveries (e.g. `401`). ## Verification To verify the authenticity of webhook requests, each webhook request includes a `X-Thanx-Signature` header that can be used to verify that the webhook was initiated by the Thanx platform. The `X-Thanx-Signature` is a hex-encoded `HMAC-SHA256` signature of the request payload, using a webhook secret that can be provided by the Thanx team. Example Verification: ```ruby Ruby theme={null} require 'json' require 'openssl' # value of the `X-Thanx-Signature` request header signature = '425bf0e847d0647d6e3449c7c1cddadc2095a98c954a7549da0d01c417b833fd' # webhook secret provided by Thanx secret = 'f19ce124-48e4-45fb-b39b-4f9e3e1d4b1b' # webhook request payload body payload = { "purchase": { "id": "bd4163e4ea5e168431fdc4b8d1ea061f", "amount": "7.76", "purchased_at": "2024-03-26T21:38:36.000Z", "event": "create", "user": { "id": "675c038cfc5f43591718936c18080855", "email": "example@thanx.com", "first_name": "Thanx", "last_name": "Example" }, "merchant": { "id": "a91f75a0dc2cc54a62ad8a1a05b9fa6b", "name": "Thanx Restaurant" }, "location": { }, "order": { }, "products": [ "Latte" ] } }.to_json # the following will return true OpenSSL::HMAC.hexdigest('sha256', secret, payload) == signature ``` ```python Python theme={null} import hashlib import hmac import json # value of the `X-Thanx-Signature` request header signature = '425bf0e847d0647d6e3449c7c1cddadc2095a98c954a7549da0d01c417b833fd' # webhook secret provided by Thanx secret = 'f19ce124-48e4-45fb-b39b-4f9e3e1d4b1b' # webhook request payload body payload = json.dumps({ "purchase": { "id": "bd4163e4ea5e168431fdc4b8d1ea061f", "amount": "7.76", "purchased_at": "2024-03-26T21:38:36.000Z", "event": "create", "user": { "id": "675c038cfc5f43591718936c18080855", "email": "example@thanx.com", "first_name": "Thanx", "last_name": "Example" }, "merchant": { "id": "a91f75a0dc2cc54a62ad8a1a05b9fa6b", "name": "Thanx Restaurant" }, "location": { }, "order": { }, "products": [ "Latte" ] } }, separators=(',', ':')) # the following will return True signature == hmac.new( key=secret.encode('utf-8'), msg=payload.encode('utf-8'), digestmod=hashlib.sha256 ).hexdigest() ``` # Purchases Source: https://docs.thanx.com/webhooks/purchases These webhooks are sent anytime Thanx detects a qualifying user purchase. **Duplicate deliveries are expected.** A single purchase can trigger this webhook multiple times — the same `id` is re-sent as the purchase is processed through authorization and settlement, and across payment rails. Delivery is not exactly-once (best-effort, with duplicates expected). Deduplicate by `id` and treat repeat deliveries for an `id` as updates. Because `amount` and `products` may be refined between deliveries, prefer the values from the last delivery you receive for a given `id`. ### Payload Description The ID of the purchase record in Thanx User information The ID of the user record in Thanx The user's email. This value may not be present. The user's first name. This value may not be present. The user's last name. This value may not be present. Merchant information The ID of the merchant record in Thanx The name of the merchant Location information The location name or category The ID of the location record in Thanx, if permitted The street address of the location, if permitted The location's city, if permitted The location's state, if permitted The location's zip code, if permitted The location's time zone, if permitted The location's latitude, if permitted The location's longitude, if permitted Time the purchase was made in ISO8601-format The purchase amount, represented as a string to prevent precision issues commonly associated with floating point numbers on the receiving side. This value may be refined between the authorization and settlement deliveries for the same purchase `id`; prefer the value from the last delivery you receive. The order information, if this purchase reflects an online order The order ID in the provider's system (`OLO`, `Toast`, `Other`) By default, these webhooks are sent 10 minutes after a purchase record is initially captured by the Thanx platform (usually initially from the credit card networks or ordering providers). Due to the nature of how Thanx collects item-level data, this data may not always be captured by Thanx by the time this webhook is sent out. If the purchase is digital (placed via Thanx-managed ordering experiences), this attribute will be populated. If the purchase is an in-store purchase, this attribute may not be populated depending on how quickly the webhook is configured to send. This data can be collected by working with the Thanx team to adjust the webhook latency, send an additional webhook at the time of item matching, or looked up via other mechanisms. Because of this, later deliveries for the same purchase `id` may include products that earlier deliveries omitted; treat the last delivery you receive as the most complete. The list of products the user bought ```json theme={null} { "purchase": { "id": "92b7b0dac4", "user": { "id": "weori235", "email": "bob@bob.com", "first_name": "Bob", "last_name": "McBob" }, "merchant": { "id": "9a1f0772c9ac", "name": "Pizza Shack" }, "location": { "id": "e7183da044", "name": "Pizza Shack 12", "street": "123 Pizza Lane", "city": "Smalltown", "state": "CA", "zip": "12345", "time_zone": "America/New_York", "latitude": "37.76271750294678", "longitude": "-122.42438230349147" }, "purchased_at": "2020-01-01T20:00:00Z", "amount": "9.99", "order": { "id": "RTF234S", "provider": "OLO" }, "products": ["Snickers", "Twix"] } } ``` ```json Mall-specific Response theme={null} { "purchase": { "id": "92b7b0dac4", "user": { "id": "weori235", "email": "bob@bob.com" }, "merchant": { "id": "9a1f0772c9ac", "name": "The Best Mall Ever" }, "location": { "name": "Food" }, "purchased_at": "2020-01-01T20:00:00Z", "amount": "9.99", "order": {}, "products": [] } } ``` # Reward Batch Completed Source: https://docs.thanx.com/webhooks/reward-batch-completed This webhook is sent once when an entire issuance job finishes processing. It provides a summary of the batch including total counts and any failures. This fires regardless of whether all rewards succeeded or some failed. ### Event `reward_batch.completed` ### Payload Description The event type: `reward_batch.completed` The time the event occurred (ISO8601) Event data The ID of the completed issuance job The ID of the merchant associated with the issuance job Final job state: `completed` or `failed` Total number of identifiers in the batch Number of rewards successfully issued Number of failed issuances Details of any failed issuances The identifier value (email or phone) that failed Error message describing the failure ```json theme={null} { "event": "reward_batch.completed", "timestamp": "2025-06-15T10:30:15Z", "data": { "issuance_job_id": "job_xyz789", "merchant_id": "mer_abc123", "state": "completed", "total_count": 2, "issued_count": 1, "failed_count": 1, "failures": [ { "user_identifier": "+14155551234", "reason": "User not found" } ] } } ``` # Reward Issued Source: https://docs.thanx.com/webhooks/reward-issued This webhook is sent each time an individual reward is successfully issued to a user during a partner issuance job. If a batch contains 100 identifiers, up to 100 individual `reward.issued` webhooks may be sent (one per successful issuance). ### Event `reward.issued` ### Payload Description The event type: `reward.issued` The time the event occurred (ISO8601) Event data The ID of the issuance job that triggered this reward The ID of the merchant associated with the issuance job The ID of the issued reward The identifier used to issue the reward Identifier type: `email` or `phone` Position in the original identifiers array The ID of the user who received the reward, if found The reward state (e.g., `active`, `pending`, `delivered`) The reward expiration date (ISO8601), if applicable Campaign information Campaign ID Campaign name Campaign objective Campaign start date (ISO8601) Campaign end date (ISO8601) Reward redemption start date (ISO8601) Reward redemption end date (ISO8601) Campaign time zone Terms and conditions The variant used for issuance Variant ID Variant name Reward template ID ```json theme={null} { "event": "reward.issued", "timestamp": "2025-06-15T10:30:10Z", "data": { "issuance_job_id": "job_xyz789", "merchant_id": "mer_abc123", "reward_id": "rwd_abc123", "identifier": { "type": "email", "index": 0 }, "user_id": "usr_def456", "state": "active", "expires_at": "2025-09-30T23:59:59Z", "campaign": { "id": "camp_abc123", "name": "Summer Free Coffee", "objective": "Re-engage lapsed customers", "start_at": "2025-06-01T00:00:00Z", "end_at": "2025-08-31T23:59:59Z", "redeemable_from": "2025-06-01T00:00:00Z", "redeemable_to": "2025-09-30T23:59:59Z", "time_zone": "America/Los_Angeles", "fine_print": "Limit one per customer", "variant": { "id": "var_treat1", "name": "Treatment", "reward_template_id": "abc123def456" } } } } ``` # SMS Subscriptions Source: https://docs.thanx.com/webhooks/sms-subscriptions These webhooks are sent when a user opts into SMS marketing. Thanx does not synchronize downstream SMS marketing opt-in status and users are only prompted to enter a phone number for SMS marketing once. SMS marketing partners are expected to manage confirmation of SMS marketing consent. ### Payload Description User ID Merchant ID The user's phone number, in E.164 format (eg. `+14157582345`) The user's email address ```json theme={null} { "sms_subscription": { "user_id": "woeruijsfwer", "merchant_id": "owierywtwt", "phone": "+14157582345", "email": "example@thanx.com" } } ```