> ## Documentation Index
> Fetch the complete documentation index at: https://docs.repdata.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Basic Integration

> Look up a respondent's threat potential and duplicate status from the browser using the Research Defender Search API.

## Overview

This guide shows how to call the Research Defender respondent search endpoint from client-side JavaScript. You can use either a `GET` or a `POST` request. Both return the same result.

After the request completes, you can read:

| Field | Description |
| - | - |
| `Respondent.threat_potential` | The threat potential assessed for the respondent. |
| `Surveys[0].flag` | The duplicate flag for the survey. |
| `Surveys[0].survey_number` | The survey number the result applies to. |

## Prerequisites

* A Research Defender **publishable key**
* Your **survey number** (`sy_nr`)
* The respondent's **session ID** (`sn_ud`)

<Warning>
  Only use your **publishable** key in client-side code. Never expose a secret key in a browser.
</Warning>

## Endpoint

```text theme={null}
https://{environment}.rtymgt.com/api/v4/respondents/search/{publishable_key}
```

<ParamField path="environment" type="string" required>
  The Research Defender environment, for example `prod`.
</ParamField>

<ParamField path="publishable_key" type="string" required>
  Your Research Defender publishable key.
</ParamField>

### Request parameters

<ParamField body="sy_nr" type="string" required>
  The survey number.
</ParamField>

<ParamField body="sn_ud" type="string" required>
  The respondent's session ID.
</ParamField>

<Note>
  Requests must be sent with credentials (`credentials: "include"`) so Research Defender cookies are included.
</Note>

## Examples

<Tabs>
  <Tab title="POST">
    ```javascript post-search.js theme={null}
    const ENVIRONMENT = "prod";
    const PUBLISHABLE_KEY = "YOUR_PUBLISHABLE_KEY";

    const SEARCH_ENDPOINT =
      `https://${ENVIRONMENT}.rtymgt.com/api/v4/respondents/search/${PUBLISHABLE_KEY}`;

    function parseResponse(text) {
      try {
        return JSON.parse(text);
      } catch {
        // Trim a stray trailing character and retry
        return JSON.parse(text.slice(0, -1));
      }
    }

    async function searchRespondent({ surveyNumber, sessionId }) {
      const response = await fetch(SEARCH_ENDPOINT, {
        method: "POST",
        credentials: "include",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ sy_nr: surveyNumber, sn_ud: sessionId }),
      });

      if (!response.ok) {
        throw new Error(`Search request failed with status ${response.status}`);
      }

      return parseResponse(await response.text());
    }

    const result = await searchRespondent({
      surveyNumber: "YOUR_SURVEY_NUMBER",
      sessionId: "YOUR_SESSION_ID",
    });

    console.log("Threat Potential:", result.Respondent?.threat_potential);
    console.log("Duplicate Flag:", result.Surveys?.[0]?.flag);
    console.log("Survey Number:", result.Surveys?.[0]?.survey_number);
    ```
  </Tab>

  <Tab title="GET">
    ```javascript get-search.js theme={null}
    const ENVIRONMENT = "prod";
    const PUBLISHABLE_KEY = "YOUR_PUBLISHABLE_KEY";

    const SEARCH_ENDPOINT =
      `https://${ENVIRONMENT}.rtymgt.com/api/v4/respondents/search/${PUBLISHABLE_KEY}`;

    function parseResponse(text) {
      try {
        return JSON.parse(text);
      } catch {
        // Trim a stray trailing character and retry
        return JSON.parse(text.slice(0, -1));
      }
    }

    async function searchRespondent({ surveyNumber, sessionId }) {
      const params = new URLSearchParams({ sy_nr: surveyNumber, sn_ud: sessionId });

      const response = await fetch(`${SEARCH_ENDPOINT}?${params}`, {
        method: "GET",
        credentials: "include",
      });

      if (!response.ok) {
        throw new Error(`Search request failed with status ${response.status}`);
      }

      return parseResponse(await response.text());
    }

    const result = await searchRespondent({
      surveyNumber: "YOUR_SURVEY_NUMBER",
      sessionId: "YOUR_SESSION_ID",
    });

    console.log("Threat Potential:", result.Respondent?.threat_potential);
    console.log("Duplicate Flag:", result.Surveys?.[0]?.flag);
    console.log("Survey Number:", result.Surveys?.[0]?.survey_number);
    ```
  </Tab>
</Tabs>

## Full HTML pages

If you want a complete page you can open in a browser, use one of the samples below. Replace the placeholder values at the top of the script before running.

<AccordionGroup>
  <Accordion title="Basic POST integration (HTML)">
    ```html basic-post-integration.html theme={null}
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8" />
      <title>Research Defender – Basic POST Integration</title>
    </head>
    <body>
      <pre id="output">Loading…</pre>

      <script>
        const ENVIRONMENT = "prod";
        const PUBLISHABLE_KEY = "YOUR_PUBLISHABLE_KEY";
        const SURVEY_NUMBER = "YOUR_SURVEY_NUMBER";
        const SESSION_ID = "YOUR_SESSION_ID";

        const SEARCH_ENDPOINT =
          `https://${ENVIRONMENT}.rtymgt.com/api/v4/respondents/search/${PUBLISHABLE_KEY}`;

        function parseResponse(text) {
          try {
            return JSON.parse(text);
          } catch {
            return JSON.parse(text.slice(0, -1));
          }
        }

        async function searchRespondent({ surveyNumber, sessionId }) {
          const response = await fetch(SEARCH_ENDPOINT, {
            method: "POST",
            credentials: "include",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({ sy_nr: surveyNumber, sn_ud: sessionId }),
          });

          if (!response.ok) {
            throw new Error(`Search request failed with status ${response.status}`);
          }

          return parseResponse(await response.text());
        }

        window.addEventListener("load", async () => {
          const output = document.getElementById("output");

          try {
            const result = await searchRespondent({
              surveyNumber: SURVEY_NUMBER,
              sessionId: SESSION_ID,
            });

            const survey = result.Surveys?.[0];
            output.textContent = [
              `Threat Potential: ${result.Respondent?.threat_potential}`,
              `Duplicate Flag:   ${survey?.flag}`,
              `Survey Number:    ${survey?.survey_number}`,
              "",
              "Full response:",
              JSON.stringify(result, null, 2),
            ].join("\n");
          } catch (error) {
            output.textContent = `Error: ${error.message}`;
          }
        });
      </script>
    </body>
    </html>
    ```
  </Accordion>

  <Accordion title="Basic GET integration (HTML)">
    ```html basic-get-integration.html theme={null}
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8" />
      <title>Research Defender – Basic GET Integration</title>
    </head>
    <body>
      <pre id="output">Loading…</pre>

      <script>
        const ENVIRONMENT = "prod";
        const PUBLISHABLE_KEY = "YOUR_PUBLISHABLE_KEY";
        const SURVEY_NUMBER = "YOUR_SURVEY_NUMBER";
        const SESSION_ID = "YOUR_SESSION_ID";

        const SEARCH_ENDPOINT =
          `https://${ENVIRONMENT}.rtymgt.com/api/v4/respondents/search/${PUBLISHABLE_KEY}`;

        function parseResponse(text) {
          try {
            return JSON.parse(text);
          } catch {
            return JSON.parse(text.slice(0, -1));
          }
        }

        async function searchRespondent({ surveyNumber, sessionId }) {
          const params = new URLSearchParams({ sy_nr: surveyNumber, sn_ud: sessionId });

          const response = await fetch(`${SEARCH_ENDPOINT}?${params}`, {
            method: "GET",
            credentials: "include",
          });

          if (!response.ok) {
            throw new Error(`Search request failed with status ${response.status}`);
          }

          return parseResponse(await response.text());
        }

        window.addEventListener("load", async () => {
          const output = document.getElementById("output");

          try {
            const result = await searchRespondent({
              surveyNumber: SURVEY_NUMBER,
              sessionId: SESSION_ID,
            });

            const survey = result.Surveys?.[0];
            output.textContent = [
              `Threat Potential: ${result.Respondent?.threat_potential}`,
              `Duplicate Flag:   ${survey?.flag}`,
              `Survey Number:    ${survey?.survey_number}`,
              "",
              "Full response:",
              JSON.stringify(result, null, 2),
            ].join("\n");
          } catch (error) {
            output.textContent = `Error: ${error.message}`;
          }
        });
      </script>
    </body>
    </html>
    ```
  </Accordion>
</AccordionGroup>

## Handling errors

A non-`200` status means the lookup did not succeed. The samples throw an error in that case so you can decide how to handle it, for example by letting the respondent continue or logging the failure.

<Tip>
  Decide in advance what your survey should do when a lookup fails, so a temporary error never blocks legitimate respondents.
</Tip>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.