Agent API and MCP

Usercall API

An agent can talk to customers and learn why. These operations are the Agent API. MCP tools call the same paths.

Talk to customers and learn why

An agent can ask a research question, hear it from a participant, and read back themes, quotes, and risks. The Agent API and the hosted MCP server are the same operations.

When to call it

Start here, then authenticate, then follow the workflow once before calling individual operations.

Authentication

Machine clients send a personal-account API key. Claude, ChatGPT, and Cursor use the hosted connector and OAuth instead of a key.

When to call it

Send the key on every Agent API call. Use the connector when a person is connecting an assistant.

Parameters

NameTypeRequiredDescription
AuthorizationheaderAPIBearer token from Home → Developer. Shown once at creation. Scope is the personal account only.
ConnectorURLMCPhttps://mcp.usercall.co. OAuth signs the person in. No API key for the hosted connector.

Response

401 { "error": "unauthorized", "message": "Unauthorized" }
Token revoked, expired, or not valid for the personal account uses the same error with a specific message.
500 { "error": "auth_lookup_failed", "message": "Failed to validate API token" }
Rate limit is 60 requests per minute per token:
429 { "error": "rate_limited", "message": "Rate limit exceeded", "limit": 60, "remaining": 0, "reset_at": "..." }

Example

curl -s "$BASE_URL/api/v1/agent/studies" \
  -H "Authorization: Bearer $USERCALL_API_KEY"

One workflow

Go from a product problem to evidence: create the study, simulate or review the guide, share the participant link or leave a trigger paused, then read results.

When to call it

Follow this order. Do not treat an in-progress result as a finding.

Example

1. You already know what happened in the product, not why.
2. POST /api/v1/agent/studies with key_research_goal only.
3. POST .../simulations, then POST .../reviews.
4. PATCH workflow_questions from a recommendation when you want to change the guide.
5. Send interview_link, or POST /api/v1/agent/triggers. The trigger stays paused until a human opens activation_url.
6. GET the study until status is complete.
7. GET .../results. Use format=full only when you need transcripts.
POST

Create a study

/api/v1/agent/studies

Creates a study from the research question and returns the participant link.

When to call it

Call this first. The next step is simulate_interview, before anyone real sees the link.

Parameters

NameTypeRequiredDescription
key_research_goalstringYesResearch question. Trimmed, 5–2000 characters.
business_contextstringNoProduct context, 5–2000 characters when present. Shorter than 5 is 400. It is not copied from the goal.
additional_context_promptstringNoExtra interviewer guidance, max 1000 characters.
target_interviewsnumberNo1–200. Default 1. Reserves 10 credits per interview.
duration_minutesnumberNo5–65. Default 12.
interview_modestringNovoice (default), text, or voice_and_text.
languagesstring[]NoOne locale runs the interview in that language and leaves the picker off. Two or more let the participant choose. Empty, unknown, or duplicate values are 400. Omit it for English voice and questions spoken as written. Locales: en-US, en-GB, en-AU, en-IN, hi-IN, ta-IN, mr-IN, kn-IN, ur-IN, pt-BR, es-ES, es-419, fr-FR, de-DE, zh-CN, ja-JP, it-IT, th-TH, ms-MY, vi-VN, id-ID, ar-SA, ko-KR, sv-SE, ru-RU.
voice_genderstringNofemale (default on create) or male. The server picks the voice. Do not send a voice id.
enable_link_contextbooleanNoDefault false. Query params on the interview link are ignored until this is true.
custom_link_variablesarrayNoUp to 10 declared custom keys: { key, label?, default_value? }. key is snake_case, max 32, not reserved.
metadataobjectNoYour own key-value pairs.
study_mediaobjectNo{ type: image | prototype, url, description? }. Shown with questions for web participants.

Response

{
  "study_id": "uuid",
  "interview_link": "https://usercall.co/interview/shortid",
  "target_interviews": 1,
  "interview_mode": "voice",
  "credits_reserved": 10,
  "status": "running",
  "study_media": null,
  "link_context_enabled": false,
  "custom_link_variable_keys": [],
  "languages": [],
  "voice_gender": "female",
  "next_step": { "action": "simulate_interview", "reason": "..." },
  "generated_guide": {
    "ai_agent_intro_message": "...",
    "key_learning_goals": "...",
    "workflow_end_message": "...",
    "workflow_questions": [
      { "id": "question_1", "text": "...", "order": 0, "follow_up_depth": "adaptive" }
    ]
  }
}

Example

curl -s -X POST "$BASE_URL/api/v1/agent/studies" \
  -H "Authorization: Bearer $USERCALL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "key_research_goal": "Why do people drop out of onboarding after the first project?"
  }'
GET

List studies

/api/v1/agent/studies

Lists studies on the personal account, each with the same interview link create returned.

When to call it

Call this to reuse a study for a research trigger, or to find a link again.

Response

{
  "studies": [
    {
      "study_id": "uuid",
      "title": "Why do people drop out of onboarding?",
      "created_at": "2026-09-30T00:00:00.000Z",
      "is_agent_api_study": true,
      "archived": false,
      "link_disabled": false,
      "interview_link": "https://usercall.co/interview/shortid",
      "link_context_enabled": false,
      "trigger_eligible": true,
      "interview_mode": "voice"
    }
  ]
}

Example

curl -s "$BASE_URL/api/v1/agent/studies" \
  -H "Authorization: Bearer $USERCALL_API_KEY"
GET

Get study status

/api/v1/agent/studies/{study_id}

Returns progress, the interview link, and the next step.

When to call it

Call this before sharing, and poll it after interviews exist until status is complete.

Parameters

NameTypeRequiredDescription
study_iduuidYesPath id from create.

Response

{
  "status": "running",
  "completed_interviews": 0,
  "target_interviews": 1,
  "last_updated": "2026-09-30T00:00:00.000Z",
  "interview_link": "https://usercall.co/interview/shortid",
  "link_disabled": false,
  "link_context_enabled": false,
  "next_step": { "action": "simulate_interview", "reason": "..." }
}

Example

curl -s "$BASE_URL/api/v1/agent/studies/$STUDY_ID" \
  -H "Authorization: Bearer $USERCALL_API_KEY"
PATCH

Update a study

/api/v1/agent/studies/{study_id}

Changes targets, the guide, interview mode, languages, or link context. The research question cannot be changed.

When to call it

Call this to apply a review suggestion, re-enable a link, or turn link context on. Send at least one field.

Parameters

NameTypeRequiredDescription
target_interviewsnumberNo1–200. Increasing reserves 10 credits per added interview. Decreasing releases unused reserved credits.
is_link_disabledbooleanNoSet false before sending the link, unless the study already hit its target.
interview_modestringNovoice, text, or voice_and_text.
ai_agent_intro_messagestringNo1–5000 characters.
key_learning_goalsstringNo1–5000 characters. Required before a guide review.
workflow_end_messagestringNo1–5000 characters.
workflow_questionsarrayNoReplaces the question list. Adaptive probing is isAdaptive true and followUpCount 3. followUpCount 3 without isAdaptive is rejected.
study_mediaobject | nullNoReplaces media on every question. null removes it.
languagesstring[]NoSame rules as create. One locale turns the picker off. Two or more turn it on.
voice_genderstringNofemale or male. Omit it to leave the stored voice gender.
enable_link_contextbooleanNoOmit it to leave the column unchanged.
custom_link_variablesarrayNoReplaces the declared list. [] clears declarations.

Response

{
  "study_id": "uuid",
  "target_interviews": 1,
  "is_link_disabled": false,
  "interview_mode": "voice",
  "updated_at": "2026-09-30T00:00:00.000Z",
  "languages": ["ko-KR"],
  "voice_gender": "female",
  "link_context_enabled": true,
  "custom_link_variable_keys": ["company"]
}

Example

curl -s -X PATCH "$BASE_URL/api/v1/agent/studies/$STUDY_ID" \
  -H "Authorization: Bearer $USERCALL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "workflow_questions": [
      { "text": "What were you trying to finish?", "isAdaptive": true, "followUpCount": 3 }
    ]
  }'
DELETE

Delete a study

/api/v1/agent/studies/{study_id}

Deletes the study, its calls, and releases unused reserved credits.

When to call it

Call this when the study should not run again. This cannot be undone.

Response

{ "study_id": "uuid", "deleted": true, "credits_released": 10 }

Example

curl -s -X DELETE "$BASE_URL/api/v1/agent/studies/$STUDY_ID" \
  -H "Authorization: Bearer $USERCALL_API_KEY"
DELETE

Delete call content

/api/v1/agent/studies/{study_id}/calls/{call_id}

Removes one call’s transcript, recording URLs, and summary.

When to call it

Call this to redact a single interview. Credits are not refunded.

Response

{ "study_id": "uuid", "call_id": "call_id", "deleted": true }

Example

curl -s -X DELETE "$BASE_URL/api/v1/agent/studies/$STUDY_ID/calls/$CALL_ID" \
  -H "Authorization: Bearer $USERCALL_API_KEY"
POST

Start a simulation

/api/v1/agent/studies/{study_id}/simulations

Starts a dry run and returns immediately with status running.

When to call it

Call this before sharing. Do not wait on the call for a transcript. Read it with the simulation id.

Parameters

NameTypeRequiredDescription
persona.namestringWith persona1–80 characters. Both persona fields are required if you send persona.
persona.promptstringWith persona1–4000 characters. Omit persona to use the default participant.

Response

{
  "study_id": "uuid",
  "simulation_id": "uuid",
  "status": "running",
  "next_step": { "action": "simulate_interview", "reason": "..." }
}

Example

curl -s -X POST "$BASE_URL/api/v1/agent/studies/$STUDY_ID/simulations" \
  -H "Authorization: Bearer $USERCALL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
GET

Read a simulation

/api/v1/agent/studies/{study_id}/simulations/{simulation_id}

Returns the simulation status, and the transcript once the run is finished.

When to call it

Call this after start, using the simulation id. A finished pass, fail, or error lets status move on to share.

Response

While running, transcript is omitted:
{ "study_id": "uuid", "simulation_id": "uuid", "status": "running", "next_step": { "action": "simulate_interview", "reason": "..." } }

When finished:
{
  "study_id": "uuid",
  "simulation_id": "uuid",
  "status": "pass",
  "result_explanation": "...",
  "transcript": [],
  "simulated_speech_duration_seconds": 42,
  "simulated_wall_clock_seconds": 90,
  "next_step": { "action": "review_study", "reason": "..." }
}

Example

curl -s "$BASE_URL/api/v1/agent/studies/$STUDY_ID/simulations/$SIMULATION_ID" \
  -H "Authorization: Bearer $USERCALL_API_KEY"
POST

Review the guide

/api/v1/agent/studies/{study_id}/reviews

Runs a guide review and returns findings and up to three suggested edits. It costs 1 credit.

When to call it

Call this before sharing, with an empty body. It does not read transcripts and does not apply edits.

Parameters

NameTypeRequiredDescription
bodyobjectEmptySend {} or omit the body. call_ids and any other field are 400 invalid_request.

Response

{
  "study_id": "uuid",
  "review_id": "uuid",
  "kind": "guide",
  "credits_charged": 1,
  "summary": "...",
  "guide_findings": [],
  "goal_assessments": [],
  "recommendations": [
    { "kind": "guide", "title": "...", "rationale": "...", "label": "...", "suggested_change": {} }
  ],
  "interview_moments": [],
  "study_findings": [],
  "next_step": { "action": "update_study", "reason": "..." }
}
Write suggested_change onto workflow_questions with update study. If recommendations is empty, next_step.action is share.

Example

curl -s -X POST "$BASE_URL/api/v1/agent/studies/$STUDY_ID/reviews" \
  -H "Authorization: Bearer $USERCALL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
GET

Get study results

/api/v1/agent/studies/{study_id}/results

Returns themes, quotes, and risks that explain why people behaved this way.

When to call it

Call this after status is complete. Empty themes while the study is running are not a finding.

Parameters

NameTypeRequiredDescription
formatqueryNosummary (default) or full. full adds transcripts and audio_urls.

Response

{
  "status": "complete",
  "completed_interviews": 1,
  "target_interviews": 1,
  "themes": [
    { "name": "Setup friction", "summary": "...", "confidence": 0.4, "quotes": ["..."] }
  ],
  "key_insights": ["..."],
  "risks_or_unknowns": [],
  "next_step": { "action": "done", "reason": "..." }
}
format=full also returns transcripts: [{ "call_id": "...", "transcript": "..." }] and audio_urls. In-progress responses still include empty transcripts and audio_urls. Link context is not on this payload.

Example

curl -s "$BASE_URL/api/v1/agent/studies/$STUDY_ID/results?format=summary" \
  -H "Authorization: Bearer $USERCALL_API_KEY"
GET

Get trigger capabilities

/api/v1/agent/triggers/capabilities

Says which trigger conditions exist and which do not.

When to call it

Call this before inventing a filter. Counts, sequences, absence, and time windows are not supported.

Example

curl -s "$BASE_URL/api/v1/agent/triggers/capabilities" \
  -H "Authorization: Bearer $USERCALL_API_KEY"
GET

List trigger events

/api/v1/agent/triggers/events

Lists events the Usercall SDK has received in the last 30 days.

When to call it

Call this to confirm the product event exists before you create a trigger.

Response

{ "events": [], "setup_required": true, "hint": "No events have been received..." }
When events exist, setup_required is false and each event has event_name, sources, last_seen_at, sample_count, and intercept_capable.

Example

curl -s "$BASE_URL/api/v1/agent/triggers/events" \
  -H "Authorization: Bearer $USERCALL_API_KEY"
GET

Get an event schema

/api/v1/agent/triggers/events/{event_name}/schema

Splits an observed event into properties and traits, with types and sample values.

When to call it

Call this to pick exact filters. An unknown event is 404 event_not_observed.

Example

curl -s "$BASE_URL/api/v1/agent/triggers/events/study_tested/schema" \
  -H "Authorization: Bearer $USERCALL_API_KEY"
GET

Get SDK setup

/api/v1/agent/triggers/setup

Returns the install snippet for the analytics provider and whether events are already arriving.

When to call it

Call this when list events is empty or a needed event has not been observed.

Parameters

NameTypeRequiredDescription
providerqueryNoposthog (default), mixpanel, amplitude, segment, ga4, or custom.
eventsqueryNoComma-separated event names to allow, max 50.

Response

install_snippet, identify_snippet, allowlist_update_snippet, instructions, and status. The secret key is never returned.

Example

curl -s "$BASE_URL/api/v1/agent/triggers/setup?provider=posthog&events=study_tested" \
  -H "Authorization: Bearer $USERCALL_API_KEY"
POST

Create a research trigger

/api/v1/agent/triggers

Creates a paused trigger for people who did something in the product, and returns an activation URL.

When to call it

Call this when you know what happened and need to ask those people why. A human opens activation_url. Agents cannot activate it.

Parameters

NameTypeRequiredDescription
study_iduuidYesStudy that owns the interview. It needs an interview link.
event_namestringYesOne observed event, 1–120 characters.
propertiesobjectNoExact-match event properties. Values are string, number, or boolean.
traitsobjectNoExact-match user traits.
urlobjectNo{ operator: equals | contains | starts_with, value }.
dwell_secondsnumberNo1–600. Page-visit triggers only.
sampling_percentnumberNo1–100.
cooldown_daysnumberNo0–365.
max_invites_per_daynumberNo1–100.
delivery_methodstringNointercept (default) or webhook. webhook requires a public https webhook_url.
invite_link_paramsobjectNostatic, from_traits, and from_properties maps. A non-empty map turns enable_link_context on for the study. {} does not.

Response

201 with the trigger, status "paused", activation_url, summary, warnings, and next_step telling you to show the link to a human.
Unknown condition keys are 422 invalid_trigger and nothing is written.

Example

curl -s -X POST "$BASE_URL/api/v1/agent/triggers" \
  -H "Authorization: Bearer $USERCALL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "study_id": "'"$STUDY_ID"'",
    "event_name": "study_tested",
    "traits": { "plan": "free" },
    "sampling_percent": 25,
    "invite_link_params": { "static": { "customer_profile": "pm" } }
  }'
GET

List research triggers

/api/v1/agent/triggers

Lists triggers on the account with status and activation_url.

When to call it

Call this to see what is paused or active. activation_url is null once a human has activated the trigger.

Example

curl -s "$BASE_URL/api/v1/agent/triggers" \
  -H "Authorization: Bearer $USERCALL_API_KEY"
GET

Get a research trigger

/api/v1/agent/triggers/{trigger_id}

Returns one trigger plus invite and interview counts.

When to call it

Call this to read status, activation_url, and stats for a trigger you already created.

Response

The trigger object plus stats: { "invited": 0, "interviews_started": 0, "interviews_completed": 0 }.
webhook_secret is never returned. webhook_secret_set says whether one is stored.

Example

curl -s "$BASE_URL/api/v1/agent/triggers/$TRIGGER_ID" \
  -H "Authorization: Bearer $USERCALL_API_KEY"
PATCH

Update a research trigger

/api/v1/agent/triggers/{trigger_id}

Changes targeting, sampling, copy, or delivery. Changing an active trigger pauses it again.

When to call it

Call this to edit a trigger. Do not send status active. That is 409 and writes nothing.

Parameters

NameTypeRequiredDescription
statusstringNopaused is allowed. active returns 409 activation_required and activation_url.
properties, traits, url, dwell_seconds, sourcevalue or nullNonull clears that filter.

Example

curl -s -X PATCH "$BASE_URL/api/v1/agent/triggers/$TRIGGER_ID" \
  -H "Authorization: Bearer $USERCALL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "sampling_percent": 10 }'
DELETE

Delete a research trigger

/api/v1/agent/triggers/{trigger_id}

Deletes the trigger.

When to call it

Call this when the trigger should stop matching. The study stays.

Response

{ "trigger_id": "uuid", "deleted": true }

Example

curl -s -X DELETE "$BASE_URL/api/v1/agent/triggers/$TRIGGER_ID" \
  -H "Authorization: Bearer $USERCALL_API_KEY"

Verify interview.completed

A human saves an HTTPS URL under Home → Developer. Usercall POSTs interview.completed when a qualified interview has a summary and a transcript.

When to call it

Use this on your server to verify the body. The agent cannot set the URL. This is not the research-trigger webhook, which receives a matched user and an invite link.

Parameters

NameTypeRequiredDescription
x-usercall-signatureheaderYest=<unix>,v1=<hex>. HMAC-SHA256 of `${t}.${rawBody}` with the signing secret. Compare v1 in constant time. No max clock skew is defined.
x-usercall-event-idheaderYesSame value as the idempotency-key header. Treat them as one delivery id.

Response

{
  "event": "interview.completed",
  "event_id": "...",
  "call_id": "...",
  "interview_study_id": "...",
  "interview_study_name": "...",
  "interview_type": "voice",
  "completed_at": "...",
  "duration_seconds": 120,
  "summary": "...",
  "transcript_url": "https://app.usercall.co/api/webhooks/interview-completed/resource?token=..."
}
Optional: recording_url, screen_recording_url, link_context, custom_variables, external_id, email.
interview_type is text, video, or voice. Qualified agent voice interviews are included. Preview calls and failed or too-short calls are not. Retries run up to 3 attempts.

Example

const crypto = require('crypto');
const [tPart, v1Part] = signatureHeader.split(',');
const timestamp = tPart.slice(2);
const v1 = v1Part.slice(3);
const expected = crypto.createHmac('sha256', secret).update(timestamp + '.' + rawBody).digest('hex');
const valid = expected.length === v1.length && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
GET

Download the recording

/api/webhooks/interview-completed/resource?token=...

Downloads the signed recording or transcript from the webhook. No account auth.

When to call it

Call the recording_url within 24 hours. A valid token redirects 302 to storage. Text interviews omit recording_url. Screen recording is the separate screen_recording_url.

Response

recording_url and transcript_url are signed Usercall URLs.
Recording: 302 to storage, or 404 when there is no audio.
Transcript: 200 text/plain.
Missing token is 400. Invalid or expired token is 401.

Example

curl -sL "$RECORDING_URL" -o interview.wav

Error envelope

Failed calls return JSON with error and message. Extra fields depend on the error.

When to call it

Branch on error, not on message text, except where a code below says otherwise.

Response

{ "error": "invalid_request", "message": "...", "details": {} }

400 invalid_json — body was not JSON
400 invalid_request — schema failed, a voice id was sent, or review included call_ids
400 review_not_ready — the study has no key learning goals
401 unauthorized
402 insufficient_credits — required, available, recommended_pack, checkout_url
404 study_not_found, simulation_not_found, call_not_found, trigger_not_found, event_not_observed
409 activation_required — activation_url, status. Nothing was changed
422 invalid_trigger — unknown_keys
429 study_limit_reached — limit 1 active agent study
429 simulation_limit_reached — limit 5 simulations per account per UTC day. Retell is not started
429 rate_limited
500 study_create_failed, guide_generation_failed, simulation_failed, review_failed, and the other *_failed codes

Example

# A voice id is rejected. Send languages and voice_gender instead.
{ "error": "invalid_request", "message": "A voice id cannot be set. Send languages and voice_gender instead." }

# The sixth simulation in a UTC day.
{ "error": "simulation_limit_reached", "message": "You have reached the daily limit of 5 simulations. Please try again tomorrow.", "limit": 5 }
POST

Buy credits

/api/v1/billing/checkout

Creates a checkout URL when create or review returns 402.

When to call it

Open the checkout_url from the 402 body, or call this with the recommended pack. Creating a study does this for you.

Parameters

NameTypeRequiredDescription
pack_idstringYespack_50, pack_100, pack_300, or pack_500.
success_urlstringNoHTTPS URL after purchase.
cancel_urlstringNoHTTPS URL if the person cancels.

Response

{ "checkout_url": "https://usercall.co/agent-checkout?checkout_token=..." }

Example

curl -s -X POST "$BASE_URL/api/v1/billing/checkout" \
  -H "Authorization: Bearer $USERCALL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "pack_id": "pack_50" }'

Hosted connector

Connect an assistant when a person wants it to talk to customers and learn why. The tools below are the same operations as this API. A result is the API JSON plus http_status. Treat http_status of 400 or higher as a failure.

When to call it

Add https://mcp.usercall.co in Claude, ChatGPT, or Cursor and sign in with OAuth. No API key. There is no share tool and no tool that activates a trigger.

Example

https://mcp.usercall.co

create_study

Start an interview from the question you need answered. You get a study and a participant link. You do not share that link yet.

When to call it

Call it when you have the question and no study for it. Do not call it to rewrite a question you already created.

Parameters

NameTypeRequiredDescription
key_research_goalstringYesThe question, in plain language. 5–2000 characters.
business_contextstringNoWhat the product is, only if you have it. At least 5 characters.
languagesstring[]NoOne locale runs the whole interview in that language. Two or more let the participant choose.
voice_genderstringNofemale or male. Do not send a voice id.

Response

interview_link, study_id, and next_step.action simulate_interview. If credits are short, open checkout_url.

Example

create_study({
  "key_research_goal": "Why do people abandon onboarding after they create their first project?"
})

simulate_interview

Hear the interview yourself before a real participant does.

When to call it

Call it after create_study and before you send the link. Leave simulation_id off to start. Call it again with that id to read the transcript. The start returns immediately. A simulation is not a completed interview, and the sixth one in a UTC day is refused.

Parameters

NameTypeRequiredDescription
study_iduuidYesFrom create_study.
simulation_iduuidTo readOmit to start. Pass the id from the start when you want the transcript.
personaobjectNoname and prompt together, only when starting. Omit both to use the default participant.

Response

Start: status running and simulation_id. Later read: pass, fail, or error, plus the transcript when the run is finished.

Example

simulate_interview({
  "study_id": "<study_id from create_study>"
})

simulate_interview({
  "study_id": "<study_id from create_study>",
  "simulation_id": "<simulation_id from the start>"
})

review_study

Check the guide for leading questions and gaps before anyone is invited.

When to call it

Call it before you share. Pass only study_id. It costs 1 credit, does not read transcripts, and does not edit the guide. Write a suggested change with update_study.

Parameters

NameTypeRequiredDescription
study_iduuidYesFrom create_study. Do not send call_ids.

Response

summary, guide_findings, and up to three recommendations. If recommendations is empty, next_step is share. Otherwise next_step is update_study.

Example

review_study({
  "study_id": "<study_id from create_study>"
})

update_study

Change the guide, the language, the number of interviews, or whether the link accepts context.

When to call it

Call it to apply a review suggestion, turn a disabled link back on, or turn link context on. Do not use it to change the research question. Delete the study and create another.

Parameters

NameTypeRequiredDescription
study_iduuidYesThe study to change.
workflow_questionsarrayNoThe new questions. Adaptive probing is isAdaptive true and followUpCount 3.
is_link_disabledbooleanNofalse before you send the link, unless the study already hit its target.
enable_link_contextbooleanNotrue before query params on the link are stored.

Example

update_study({
  "study_id": "<study_id from create_study>",
  "workflow_questions": [
    { "text": "What were you trying to finish when you left?", "isAdaptive": true, "followUpCount": 3 }
  ]
})

get_study_status

Decide the next move for a study that already exists.

When to call it

Call it before you share, and again after interviews start until the study is complete. Do what next_step says. An early result is not a finding.

Parameters

NameTypeRequiredDescription
study_iduuidYesFrom create_study or list_studies.

Response

next_step.action:
simulate_interview — nobody real has been interviewed, and you have not finished a simulation or a guide review
share — send interview_link, or call create_research_trigger
poll_study_status — interviews are in progress
get_study_results — the study is complete
If link_disabled is true, call update_study with is_link_disabled false before you send the link, unless the study already hit its target.

Example

get_study_status({
  "study_id": "<study_id from create_study>"
})

get_study_results

Read why people behaved this way: themes, quotes, and risks.

When to call it

Call it after get_study_status says the study is complete. Ask for format full only when you need the transcripts.

Parameters

NameTypeRequiredDescription
study_iduuidYesThe finished study.
formatstringNosummary (default) or full.

Example

get_study_results({
  "study_id": "<study_id from create_study>",
  "format": "summary"
})

list_studies

Find an interview you already created so you can share its link or attach a trigger.

When to call it

Call it when you do not have the study id. interview_link on each row is the same link create_study returned. trigger_eligible is false when there is no link.

Example

list_studies({})

delete_study

Stop a study for good and release unused credits.

When to call it

Call it when that interview should never run again. This cannot be undone. The calls go with the study.

Parameters

NameTypeRequiredDescription
study_iduuidYesThe study to delete.

Example

delete_study({
  "study_id": "<study_id from create_study>"
})

get_trigger_capabilities

See which ways you can choose who gets invited, and which ways you cannot.

When to call it

Call it before you design a trigger. You can match one event, exact property or trait values, a URL rule, and page dwell. You cannot ask for counts, sequences, "did not do X", or a time window.

Example

get_trigger_capabilities({})

list_trigger_events

See which product events Usercall has actually received, so you only invite people for something real.

When to call it

Call it before create_research_trigger. If nothing is listed, call get_trigger_sdk_setup.

Example

list_trigger_events({})

get_trigger_event_schema

See the real fields on one event so a filter uses a name and a value you have seen.

When to call it

Call it after list_trigger_events, before you set properties or traits. Properties and traits are different lists. Matching is exact.

Parameters

NameTypeRequiredDescription
event_namestringYesAn event from list_trigger_events, such as study_tested.

Example

get_trigger_event_schema({
  "event_name": "study_tested"
})

get_trigger_sdk_setup

Get the snippet that sends your product events into Usercall.

When to call it

Call it when the event you care about has never arrived. If you can edit the app, apply the snippet. Otherwise show it to the user. Then call list_trigger_events again. The snippet never includes a secret key.

Parameters

NameTypeRequiredDescription
providerstringNoposthog, mixpanel, amplitude, segment, ga4, or custom.
eventsstring[]NoEvent names to allow, such as study_tested.

Example

get_trigger_sdk_setup({
  "provider": "posthog",
  "events": ["study_tested"]
})

create_research_trigger

Ask the people who just did something in the product why they did it.

When to call it

Call it when you know the event and which study should interview them. The trigger is created paused. Show activation_url to a human. You cannot turn it on. A non-empty invite_link_params map turns link context on for that study.

Parameters

NameTypeRequiredDescription
study_iduuidYesThe study those people should take.
event_namestringYesAn observed event, such as study_tested.
traitsobjectNoExact user traits, such as { "plan": "free" }.
propertiesobjectNoExact event properties. Do not put traits here.
invite_link_paramsobjectNostatic, from_traits, or from_properties. Empty {} does not change the study.

Response

status paused, summary, and activation_url. Hand that URL to a person.

Example

create_research_trigger({
  "study_id": "<study_id from create_study>",
  "event_name": "study_tested",
  "traits": { "plan": "free" },
  "sampling_percent": 25,
  "invite_link_params": { "static": { "customer_profile": "pm" } }
})

list_research_triggers

See which invites are waiting for a person to approve, and which are already on.

When to call it

Call it to find activation_url for a trigger you did not just create. status and activation_url are on every row. activation_url is empty once a human has activated it.

Example

list_research_triggers({})

get_research_trigger

Check one trigger: whether a person has approved it, and how many interviews it has produced.

When to call it

Call it when you have a trigger id. If it is still paused, hand activation_url to a human. You cannot activate it.

Parameters

NameTypeRequiredDescription
trigger_iduuidYesFrom create_research_trigger or list_research_triggers.

Example

get_research_trigger({
  "trigger_id": "<trigger_id from create_research_trigger>"
})

update_research_trigger

Change who gets invited, how often, or what they see.

When to call it

Call it to edit a trigger you already created. Do not send status active. That returns activation_url and changes nothing. Editing an active trigger pauses it until a human approves it again.

Parameters

NameTypeRequiredDescription
trigger_iduuidYesThe trigger to change.
sampling_percentnumberNo1–100.
statusstringNopaused is allowed. active is refused.

Example

update_research_trigger({
  "trigger_id": "<trigger_id from create_research_trigger>",
  "sampling_percent": 10
})

delete_research_trigger

Stop inviting people for this trigger. Interviews that already finished stay on the study.

When to call it

Call it when that event should no longer ask anyone why. The study itself stays.

Parameters

NameTypeRequiredDescription
trigger_iduuidYesThe trigger to delete.

Example

delete_research_trigger({
  "trigger_id": "<trigger_id from create_research_trigger>"
})