# TapResearch Publisher Documentation — Hosted Link # Source: https://supply-docs.tapresearch.com · generated at build time, do not edit by hand. # Each section below is one documentation page. # Hosted Link Source: https://supply-docs.tapresearch.com/docs/3.x/hosted-link/overview # Hosted Link The Hosted Link is the fastest, **low-code** way to connect your users to TapResearch surveys. You add a call-to-action in your app that opens a single URL, and TapResearch handles eligibility, survey selection, and presentation on our side. There's no SDK to install and no API to call. :::tip Creating your app In the [Supplier Dashboard](https://www.tapresearch.com/supplier_dashboard/overview), create a new app and select **Hosted Link**. See the [Setup checklist](../setup) for the full flow. ::: ## How it works You embed one hosted link in your app or web experience. The link contains a few **placeholder tokens** that you swap out per user before sending the user to it — most importantly, a unique identifier for the user. 1. **Build the link per user.** Take the hosted link from your dashboard and substitute the placeholder tokens (such as the user identifier) with that user's real values. 2. **Send the user to the link.** When they tap your call-to-action, open the built link. 3. **TapResearch handles the rest.** Eligibility, targeting, and survey matching all happen on TapResearch's side — there is no eligibility call for you to make. 4. **Rewards arrive via callback.** When a user earns a reward, TapResearch notifies your backend with a server-to-server postback. ## When to use it The Hosted Link trades control for speed — it's the fastest launch, with eligibility and presentation handled for you. Reach for a different path if you need: * **To keep users inside your app** — use the **SDK** path. The Hosted Link opens in the device's browser (see the warning below). * **Native survey tiles or in-app placements** — use the **SDK** path. * **An eligibility check before you send a user** — use the **Eligibility API** path. * **A survey feed you render yourself, or profile / impanel support** — use the **Survey Feed API** path. :::warning Open in a browser, not an in-app WebView The Hosted Link is designed to open in the device's browser. Loading it inside an in-app WebView is **not recommended** — the survey flow has nuances (notably how the close and abandon buttons need to behave) that are difficult to get right in a custom WebView. If you want to keep users inside your app, use the **SDK** instead — it handles the in-app survey experience automatically. ::: ## What you need * The **hosted link** for your placement, from the Publisher Dashboard. * A unique **user identifier** to substitute into the link for each user. No API token or eligibility request is required. The integration is light: add a call-to-action that opens the link, template the `uid` per user, and set up the reward [callback](callbacks.mdx) on your backend. ## Next steps * **[Implementation](setup.md)** — the URL format, the placeholder tokens to substitute per user, and the redirect behavior. * **[Callbacks](callbacks.mdx)** — receive reward notifications on your backend with the server-to-server postback. --- # Integrate with AI Source: https://supply-docs.tapresearch.com/docs/3.x/hosted-link/integrate-with-ai # Integrate Hosted Link with AI Copy the prompt below into your AI assistant — Claude, ChatGPT, Cursor, Codex, or whatever you use. It points the agent at our full, always-current Hosted Link reference, so it works from the real documentation instead of guessing. Hosted Link is the low-code path, so there's not much to build — mostly templating the link per user and handling the reward callback. Your agent can walk you through both. Review what it writes, and reach for the rest of these docs whenever you want the details yourself. ## After you integrate: verify it's working Hosted Link is low-code, so verification is quick. Complete your dashboard **Account Setup** first (currency, a placement with content, and a test device), then check the flow end-to-end on a **test device**. **Your AI agent can help** run and debug these steps, but it can't see your account — so your callback endpoint receiving the completion is what confirms the flow works. :::tip Use a real test session Open the link on a real test device — a test postback on its own won't exercise the flow. Add a test device first (**More → Test devices**). ::: 1. **Link opens the survey wall** — Open your templated Hosted Link on a test device; it should load the survey wall. 2. **Reward callback configured** — Set your server-to-server postback URL in your app settings. 3. **Survey complete recorded** — Complete a test survey through the link. 4. **Callback received & verified** — Confirm your endpoint receives a signed `GET` (validate the HMAC `sig`) and redeems the reward. (The dashboard's **Integration** tab shows only Account Setup for Hosted Link — there's no implementation checklist to watch, which is why the callback is your signal.) For deeper guidance, see [Testing & QA](/docs/3.x/testing-and-qa). --- # Implementation Source: https://supply-docs.tapresearch.com/docs/3.x/hosted-link/setup # Implementation This page covers how to use your hosted link: the URL format, the value you substitute per user, and what happens when a user opens the link. You need a TapResearch account and a **Hosted Link** app before you begin. Don't have an account yet? [Sign up](https://www.tapresearch.com/suppliers/sign_up), then grab your hosted link from the [Publisher Dashboard](https://tapresearch.com/supplier_dashboard/overview). ## The hosted link format Your dashboard generates the hosted link for you. It points at one of your placements — identified by your **app title identifier** and the **placement tag** in the path — and carries the user you're sending in the `uid` query parameter: ``` https://www.tapresearch.com/supply_api/v4/app_titles//placements//redirect?uid= ``` There is **no API token** in the link — the Hosted Link requires no authentication. The dashboard fills in the path for you; you only substitute the per-user identifier. ## Values to substitute The `` and `` are already filled in by the dashboard and are fixed per placement. Before you send a user to the link, fill in the user value: | Value | Location | Required | Description | |-------|----------|----------|-------------| | `` | `uid` query param | Yes | A persistent, unique identifier for the user. Swap this per user so rewards are attributed to the right account. Reuse the same value for a given user across sessions. | | `did` | Query param | No | An optional identifier for the user's device. | :::info One link, swapped per user The hosted link is the same for every user except for the per-user `uid`. Template the link once, then substitute the current user's value at the moment you hand them the link. ::: **Requirements:** * Use a stable `uid` for each user — the same value should map to the same user every time. * URL-encode any values that contain special characters. ## What happens when a user opens the link Opening the hosted link hands the user off to the TapResearch-hosted experience — you don't select, render, or redirect to anything yourself: 1. **We check what's available for the user.** Eligibility and targeting are handled entirely on TapResearch's side — there's no eligibility call for you to make. 2. **The user enters the survey experience.** First-time users go through a short profiling flow, then land on the TapResearch **survey wall**, where they browse and take their available surveys. 3. **Otherwise, they see a "no surveys available" message.** If the user isn't currently eligible for anything, they get a friendly, localized message instead. No reward is issued in this case. After a user completes a survey, TapResearch notifies your backend asynchronously — see [Callbacks](callbacks.mdx). ## Next steps * **[Callbacks](callbacks.mdx)** — set up the server-to-server postback so you're notified when a user earns a reward. --- # Callbacks Source: https://supply-docs.tapresearch.com/docs/3.x/hosted-link/callbacks ## Callbacks With the Hosted Link path, rewards are delivered to your backend with a **server-to-server postback**. TapResearch sends a request to your callback URL immediately after a user earns a reward, and you verify and credit it on your side. In-app callbacks do not apply to the Hosted Link path — there is no SDK to deliver them — so only the server-to-server postback is documented below. ## In-App Callbacks In-app callbacks report rewards to your app through the SDK, as a single `RewardCollection` callback. **Example:** If a user completes three surveys, the SDK fires one callback containing all three rewards. **Key features:** * TapResearch notifies users of their rewards * Default callback method (fires unless server-to-server is configured) **When callbacks fire:** * When the user closes TapResearch * After successful SDK initialization :::info In-app callbacks are the default. To receive rewards on your backend instead, configure the server-to-server postback described below. ::: ## Server-to-Server Postback The server-to-server postback is a `GET` request that TapResearch sends to your callback URL immediately after a user earns a reward. The reward details are passed as query parameters, and an HMAC-MD5 signature (`sig`) lets you verify the request originated from TapResearch. **Important:** With server-to-server callbacks your app is responsible for notifying users of the rewards they receive — TapResearch does not notify users with this method. ### Update Callback URL Set or update your callback URL in the **"Edit App"** section of the [Publisher Dashboard](https://tapresearch.com/supplier_dashboard/overview). **URL requirements:** * No spaces or special characters * Must return a 2xx response code to be considered valid ### Sample Request ``` https://your-callback-url.example.com/postback?uid=developers%40tapresearch.com&tid=777ca23551a4a9173920c22e1ed7f4f3&cpid=tap_37939e4ede350f3a8d5149d2fcaa025e&payout_amount=191&payout_currency=gold&revenue=0.5&payout_type=3&sig=42cbd66af5b670bed293d9b01c06d3c4 ``` ### Query Parameters | Parameter | Type | Description | |-----------|------|-------------| | uid | String | Persistent unique identifier for this user. | | tid | String | Transaction ID or click ID. This value will not be unique if the user completed multiple surveys in a single session. Use `cpid` for deduping purposes. | | cpid | String | Unique survey complete identifier. We recommend that you store and check against this value to ensure you reward the user only once per survey complete. | | payout_amount | Integer | Amount of currency earned by this user. | | payout_currency | String | The type of currency the user earned. | | revenue | Decimal | Amount you will be paid for this survey complete, in USD. | | payout_type | Integer | The action that the user was rewarded for. 0 - Profile Complete, 3 - Survey Rewarded, 9 - Quick Question Completed. | | sig | String | The URL signature: an HMAC-MD5 generated from the query string minus the `sig` parameter. See [Signature Validation](#signature-validation) below. | :::note The parameters above aren't the complete set The callback may include additional parameters beyond those listed here, and more may be added over time. This is expected — the signature always covers the **entire** query string, so validate against whatever you actually receive rather than a fixed list of fields (see [Signature Validation](#signature-validation)). ::: ### Callback Testing Use the **Test Callback** button in the dashboard to generate a test completion that fires a callback to your specified URL. **Best practice:** Test callbacks before deploying to production. :::note Test callbacks use fixed currency values. Commercial survey values will vary. ::: ### Signature Validation For security, every callback request includes an HMAC-MD5 signature (`sig`) generated from the query string. Validate it on every request before you reward a user. **Sign the entire query string exactly as you receive it, minus `sig` — don't rebuild it from a fixed list of parameters.** The signature covers every parameter present, so hashing whatever arrives (as the steps and code below do) stays correct even as parameters are added. Grab your API secret from your main dashboard. Example: `26dcc0fc7b6208fdfeffaf19f627cb4a` 1. Start with the incoming callback request, for example: `https://your-callback-url.example.com/postback?uid=developers%40tapresearch.com&tid=777ca23551a4a9173920c22e1ed7f4f3&cpid=tap_37939e4ede350f3a8d5149d2fcaa025e&payout_amount=191&payout_currency=gold&revenue=0.5&payout_type=3&sig=42cbd66af5b670bed293d9b01c06d3c4` 2. Isolate the query string, leaving out the question mark. 3. Strip out the `sig` parameter, including the leading ampersand (`&`). 4. URL-decode the remaining query string. 5. Run your API secret and the decoded query string through an HMAC-MD5 generator. 6. Compare your generated HMAC against the `sig` parameter value. If they match, record the complete and reward the user. ```ruby # Sample request URL url = "https://your-callback-url.example.com/postback?uid=developers%40tapresearch.com&tid=777ca23551a4a9173920c22e1ed7f4f3&cpid=tap_37939e4ede350f3a8d5149d2fcaa025e&payout_amount=191&payout_currency=gold&revenue=0.5&payout_type=3&sig=42cbd66af5b670bed293d9b01c06d3c4" # Isolate query string query_string = url.gsub(/^(.*?)\?/, "") # Strip out the sig parameter stripped_query_string = query_string.gsub(/&sig.*/, "") # Decode URL decoded = URI.decode_www_form_component(stripped_query_string) # Generate HMAC-MD5 api_secret = "26dcc0fc7b6208fdfeffaf19f627cb4a" digest = OpenSSL::Digest.new("md5") md5 = OpenSSL::HMAC.hexdigest(digest, api_secret, decoded) puts md5 # 42cbd66af5b670bed293d9b01c06d3c4 ``` ```php ``` ```java private static final String API_SECRET = "26dcc0fc7b6208fdfeffaf19f627cb4a"; private static final String ALGO = "HmacMD5"; try { // URL String urlString = "https://your-callback-url.example.com/postback?uid=developers%40tapresearch.com&tid=777ca23551a4a9173920c22e1ed7f4f3&cpid=tap_37939e4ede350f3a8d5149d2fcaa025e&payout_amount=191&payout_currency=gold&revenue=0.5&payout_type=3&sig=42cbd66af5b670bed293d9b01c06d3c4"; // Generate HMAC-MD5 Mac mac = Mac.getInstance(ALGO); SecretKeySpec key = new SecretKeySpec(API_SECRET.getBytes(StandardCharsets.UTF_8), ALGO); mac.init(key); // Isolate query string and remove sig parameter String queryString = urlString.substring(urlString.indexOf("?") + 1); queryString = queryString.substring(0, queryString.indexOf("&sig=")) + queryString.substring(queryString.indexOf("&sig=") + 37); // Decode URL String decode = URLDecoder.decode(queryString, StandardCharsets.UTF_8); byte[] bytes = mac.doFinal(decode.getBytes(StandardCharsets.UTF_8)); String md5 = DatatypeConverter.printHexBinary(bytes).toLowerCase(); System.out.println(md5); // 42cbd66af5b670bed293d9b01c06d3c4 } catch (Exception e) { e.printStackTrace(); } ``` ### Whitelisted IP Addresses To further harden your endpoint, restrict incoming callback requests to the following TapResearch source IP addresses: | IP Address | |------------| | 34.198.225.203 | | 3.88.121.21 | | 3.89.214.250 | | 3.92.129.242 | ### Retries If a callback fails, our system continues retrying to send the reward for 48 hours OR until a `2xx` response code is returned. ---