Webhooks

Webhooks let UserSound notify your server when a respondent finishes a survey. Use them to unlock a discount, update CRM status, issue a reward, or trigger any follow-up in your product when interview_status becomes complete.

Enable webhooks

  1. Open your project in the UserSound dashboard
  2. Click Setup
  3. Open the Webhooks section (below Widget settings)
  4. Turn on Enable completion webhook
  5. Enter your HTTPS endpoint URL
  6. Click Save

Saving generates a signing secret automatically. Copy it from the dashboard — your server needs it to verify requests. Use Rotate secret if you need a new one.

Click Send test event to POST a sample webhook.test payload to your endpoint.

Identify respondents

For unlock or reward flows, pass an identity when the survey opens so the webhook can tell you which user finished. Use either:

  • external_user_id (preferred) — your stable account / customer ID
  • email — if that is already how you identify users

Your app should inject these from the authenticated session. Do not let end users edit them in the URL.

Survey link

URL


https://usersound.com/survey/YOUR_PROJECT_UUID/?external_user_id=YOUR_USER_ID
URL


https://usersound.com/survey/YOUR_PROJECT_UUID/[email protected]

Embed / widget

Pass identity in the SDK context object. See Identifying users for the full embed pattern (user_id maps to the same identified respondent as external_user_id).

Events

Event type When it fires
interview.completed Once, when a response transitions to complete.
webhook.test When you click Send test event in Setup.

Delivery happens as soon as the interview is marked complete — it does not wait for summary generation. Each completed response produces at most one interview.completed delivery.

Payload

Example interview.completed body:

JSON


{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "type": "interview.completed",
  "created_at": "2026-07-22T18:00:00.123456+00:00",
  "data": {
    "project_uuid": "05de077e-5f64-4b61-bc8b-4fc54ede38cc",
    "response_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "interview_status": "complete",
    "external_user_id": "customer-123",
    "respondent": {
      "email": "[email protected]",
      "user_name": "Alex Example",
      "first_name": "Alex"
    },
    "completed_at": "2026-07-22T18:00:00.120000+00:00"
  }
}
Field Description
id Unique event / delivery ID. Use for idempotency on your side.
type Event name, e.g. interview.completed.
data.project_uuid The UserSound project UUID.
data.response_id The interview response UUID.
data.external_user_id Your user ID if one was passed; otherwise null.
data.respondent Optional profile fields stored on the identified respondent.

Request headers

Header Description
Content-Type application/json
User-Sound-Event Same as the payload type (e.g. interview.completed).
User-Sound-Delivery-Id Same as payload id.
User-Sound-Signature t=<unix_timestamp>,v1=<hmac_sha256_hex>. HMAC-SHA256 of {timestamp}.{raw_body} using your signing secret — verify this before trusting the payload.

Completion status API

If the user returns to your app before the webhook arrives, poll this endpoint from your backend. Authenticate with the same signing secret as a Bearer token.

HTTP


GET https://usersound.com/api/v1/survey/YOUR_PROJECT_UUID/completion-status/?external_user_id=YOUR_USER_ID
Authorization: Bearer YOUR_WEBHOOK_SECRET
JSON


{
  "external_user_id": "customer-123",
  "email": null,
  "completed": true,
  "response_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "completed_at": "2026-07-22T18:00:00.120000+00:00"
}
  • Provide exactly one of external_user_id or email.
  • Call this from your server, not a public mobile/browser client that exposes the secret.
  • If the user already completed and no new webhook fires, this endpoint still returns completed: true.

Retries

  • If your endpoint is down or returns an error, UserSound retries a few times with short delays.
  • Return a successful HTTP response (status code 200–299) once you have handled the event.
  • The same completion may be delivered more than once — store the event id (or response_id) and ignore duplicates so you do not unlock a reward twice.

Production webhook URLs must use https:// and resolve to public addresses. Private / localhost URLs are rejected in production.

Testing locally

  1. Point the webhook URL at a local HTTP receiver, or use a tunnel like ngrok for HTTPS.
  2. Save, copy the signing secret, then click Send test event.
  3. To test a real completion, open the survey with ?external_user_id=... and finish the interview.