TestUtopia
SolutionsPricingAboutContact
Help Center
  • Getting started

Assessments

  • Creating assessments
  • Inviting candidates
  • Proctoring
  • Reviewing results

Questions

  • Question types
  • Multiple-choice questions
  • Essay questions
  • Code questions
  • Test case format

Library

  • The Library
  • Importing and publishing

Interviews

  • Managing interviews
  • Live interviews
  • Interview questions
  • Scorecards
  • Interview templates

AI Assessments

  • AI Assessments
  • Templates
  • The question pool
  • Reading the report

Streams

  • Streams
  • Enrolling students
  • Stream tests
  • Stream results

Training

  • Training & Certification
  • Participants
  • Training tasks
  • Certificates and evidence

Account & billing

  • Team and roles
  • Plans and billing
  • Account and security

For candidates

  • Before you start
  • What is recorded
  • Coding questions
  • If something goes wrong
  • After you submit
  • Your data

Developers

  • REST API
  • Webhooks
  • Greenhouse
  • SSO and SCIM

Cannot find what you need?

Contact support
  1. Help Center
  2. /
  3. Developers

Webhooks

Rather than polling, register an HTTPS endpoint and we will POST to it when something happens. Available on Professional and above, under Integrations → Webhooks.

Events

EventFires when
test.invitation.createdAn invitation is sent
test.invitation.openedA candidate opens their link
test.invitation.expiredAn invitation passes its expiry
test.attempt.startedA candidate begins an assessment
test.attempt.submittedA candidate submits
test.attempt.evaluatedScoring finished, including any manual marking
test.attempt.flagged_for_reviewAn attempt was flagged for a human to look at
interview.scheduledAn interview is created
interview.startedAn interview room opens
interview.completedAn interview ends
interview.status_changedAn interview's status changes
subscription.tier_changedYour own plan changes

Subscribe an endpoint to only the events you handle. This list is part of the API contract: new events may be added, but existing ones are not renamed or removed without a deprecation period.

If you want a candidate's final score, test.attempt.evaluated is the one to use — submitted fires before marking is complete.

Verifying the signature

Every request carries a Tu-Signature header:

Tu-Signature: t=1755590400,v1=5257a869e7...

v1 is an HMAC-SHA256, keyed with your endpoint's signing secret, over the string <timestamp>.<raw request body>. To verify:

  1. Parse t and v1 out of the header.
  2. Reject the request if t is more than 5 minutes from your clock, in either direction.
  3. Compute HMAC-SHA256(secret, "<t>.<body>") over the raw body — the exact bytes received.
  4. Compare in constant time against v1.

GOTCHA: sign the raw bytes, not a re-serialized object. Parsing the JSON and re-encoding it changes whitespace and key order, and the signature will never match. Capture the raw body before your framework parses it.

Reject anything that fails. An unverified webhook endpoint is an unauthenticated write API into your systems, and its URL is not a secret.

Rotating the signing secret

Rotation issues a second secret while the old one stays valid for a grace period, and both are accepted during it. Deploy the new secret, confirm deliveries still verify, then finish the rotation.

Retries

A delivery is retried on any network error, timeout, or 5xx response, on this schedule:

1 minute → 5 minutes → 30 minutes → 2 hours → 6 hours → 24 hours

That is six attempts across more than three days, so a receiver that is down overnight recovers without anyone intervening. After the last one the delivery is dead-lettered and not retried again.

A 4xx other than 429 is treated as permanent — you are rejecting the request and retrying will not help.

After 20 consecutive failures the endpoint is disabled automatically and must be re-enabled by hand once the receiver is fixed. This stops a decommissioned URL absorbing deliveries indefinitely.

Building a receiver that behaves

  • Respond fast, then work. Acknowledge with a 2xx as soon as you have verified and stored the event; do the processing afterwards. A slow receiver times out and gets retried, which turns one event into several.
  • Deduplicate on event_id. Delivery is at-least-once. A retry after a timeout can arrive for an event you already handled successfully.
  • Do not assume order. Retries mean a later event can arrive before an earlier one.

Your endpoint must be publicly reachable

We block requests to private and loopback address ranges, so localhost and internal IPs cannot be registered — that restriction protects both of us from server-side request forgery.

For local development, use a tunnelling service to expose your machine on a public HTTPS URL.

Was this helpful?
PreviousREST APINextGreenhouse
TestUtopia

Advanced technical assessment engine designed for high-precision engineering teams. Curating talent through rigorous data-driven evaluation.

Solutions

  • Solutions
  • Pricing
  • Features

Company

  • About

Support

  • Help Center
  • Contact support

Legal

  • Privacy Policy
  • Terms of Service
  • Cookie Policy
  • Security
  • Trust Center
Test Utopia Ltd · Razsadnika-Konyiovitsa, Bl. 22, fl. 6, ap. 38, Sofia, 1330, Bulgaria
Reg. No.: 207409973|VAT: BG207409973
[email protected]|+359 886 363 248

© 2026 Test Utopia Ltd. All rights reserved.