GET /surveys/{surveyId}/panelists/{panelistId}

Retrieve panelist access information and generate a secure voting URL.

Request

GET /tenant/surveys/{surveyId}/panelists/{panelistId}

Path Parameters

ParameterTypeDescription
surveyIdstringThe survey ID (from your Votito dashboard)
panelistIdstringYour unique identifier for the panelist (e.g., customer ID, email hash)

Headers

HeaderRequiredDescription
X-API-KeyYesYour API key

Response

{
  "panelist": {
    "canRespond": true,
    "sessionCount": 0,
    "activityStartedUnixTs": null,
    "activityMostRecentUnixTs": null,
    "dismissedMostRecentUnixTs": null,
    "publicKey": "abc123:xyz789",
    "hostedResponseUrl": "https://www.votito.com/public/survey/?key=abc123:xyz789"
  },
  "survey": {
    "status": "OPEN",
    "title": "Customer Satisfaction Survey"
  }
}

Response Fields

panelist object

FieldTypeDescription
canRespondbooleanWhether the panelist can currently respond
sessionCountintegerNumber of times the panelist has started a session
activityStartedUnixTsinteger|nullUnix timestamp of first activity, or null if no activity
activityMostRecentUnixTsinteger|nullUnix timestamp of most recent activity
dismissedMostRecentUnixTsinteger|nullUnix timestamp of most recent survey dismissal, or null if never dismissed
publicKeystringCompound token for Panelist API authentication
hostedResponseUrlstringReady-to-use voting URL for the panelist

survey object

FieldTypeDescription
statusstringSurvey status: “DRAFT”, “OPEN”, or “CLOSED”
titlestringSurvey title

Examples

cURL

curl -X GET \
  "https://api.votito.com/tenant/surveys/survey-123/panelists/customer-456" \
  -H "X-API-Key: vtt_your_api_key"

JavaScript

const getSurveyAccess = async (surveyId, panelistId) => {
  const response = await fetch(
    `https://api.votito.com/tenant/surveys/${surveyId}/panelists/${panelistId}`,
    {
      headers: { 'X-API-Key': process.env.VOTITO_API_KEY }
    }
  );

  if (!response.ok) {
    throw new Error(`API error: ${response.status}`);
  }

  return response.json();
};

// Usage
const { panelist, survey } = await getSurveyAccess('survey-123', 'customer-456');
console.log(`Voting URL: ${panelist.hostedResponseUrl}`);

Python

import requests
import os

def get_survey_access(survey_id, panelist_id):
    response = requests.get(
        f"https://api.votito.com/tenant/surveys/{survey_id}/panelists/{panelist_id}",
        headers={"X-API-Key": os.environ["VOTITO_API_KEY"]}
    )
    response.raise_for_status()
    return response.json()

# Usage
data = get_survey_access("survey-123", "customer-456")
print(f"Voting URL: {data['panelist']['hostedResponseUrl']}")

Common Use Cases

Survey Distribution

Generate unique voting URLs for each panelist in your CRM:

const response = await fetch(
  `https://api.votito.com/tenant/surveys/${surveyId}/panelists/${customerId}`,
  { headers: { 'X-API-Key': apiKey } }
);
const { panelist } = await response.json();

// Send panelist.hostedResponseUrl to your customer
sendEmail(customer.email, panelist.hostedResponseUrl);

Survey Fatigue Prevention

Check if a panelist has already responded or recently dismissed before showing surveys:

const { panelist } = await response.json();

if (!panelist.canRespond) {
  // Don't show survey - already responded or survey closed
  return;
}

// Check if panelist dismissed recently (e.g., within 30 days)
if (panelist.dismissedMostRecentUnixTs) {
  const thirtyDaysAgo = Math.floor(Date.now() / 1000) - (30 * 24 * 60 * 60);
  if (panelist.dismissedMostRecentUnixTs > thirtyDaysAgo) {
    // Don't show survey - dismissed less than 30 days ago
    return;
  }
}

if (panelist.sessionCount > 0) {
  // Panelist has already started responding
  // You may want to limit repeated invitations
}

Activity Tracking

Monitor when panelists interact with surveys:

const { panelist } = await response.json();

console.log(`First activity: ${new Date(panelist.activityStartedUnixTs * 1000)}`);
console.log(`Last activity: ${new Date(panelist.activityMostRecentUnixTs * 1000)}`);
console.log(`Sessions: ${panelist.sessionCount}`);

Error Handling

StatusErrorDescription
401UnauthorizedMissing or invalid API key
403ForbiddenAPI key belongs to a different tenant
404survey_not_foundSurvey does not exist or belongs to another tenant

Notes

Panelist ID Best Practices

URL Expiration

The hostedResponseUrl does not expire. The publicKey is valid as long as:

Multiple Responses

If allowMultipleResponses is enabled on the survey, canRespond will be true even after the panelist has responded.