Scout SelectDeveloper Documentation
Certifications

Webhooks

Get a signed callback instead of polling for results.

Rather than poll Results, supply a callbackUrl when creating an invite. Scout Select will POST a signed event to that URL whenever the invite's state changes.

Events

  • certification.completed - the candidate finished the timed challenge.
  • certification.pending_review - the attempt was flagged and is awaiting manual review.
  • certification.result_released - the result is final and safe to show the candidate. Treat this as authoritative.
  • certificate.issued - a public certificate was issued.
  • certification.follow_up_claimed - the candidate claimed a one-time retake or level-up offer. This arrives immediately with the new invite ID, before the candidate starts the new exam.

Payload shape

{
  "eventId": "8f14e45f-...",
  "eventType": "certification.result_released",
  "occurredAt": "2026-07-20T09:41:03.120Z",
  "inviteId": "clv2x...",
  "externalReference": "seemesol-user-12345",
  "followUp": {
    "originalInviteId": "clv1w...",
    "option": "RETAKE_SAME"
  },
  "result": {
    "inviteId": "clv2x...",
    "isFollowUp": true,
    "originalInviteId": "clv1w...",
    "status": "COMPLETED",
    "skillName": "React",
    "level": "Intermediate",
    "completedAt": "2026-07-20T09:41:00.000Z",
    "resultBand": "GOOD",
    "score": 78,
    "proctoringStatus": "CLEARED",
    "resultReleaseStatus": "RELEASED",
    "certificateUrl": "https://select.getscout.ai/certificates/abc123",
    "verificationStatus": "ISSUED",
    "feedbackAreas": ["Error handling", "Debugging"],
    "reportUrl": "https://select.getscout.ai/reports/9f3a1c...",
    "skillWiseScores": [
      { "label": "React", "score": 7.5, "concepts": [{ "label": "Hooks", "score": 8 }] }
    ],
    "communicationScores": [
      { "label": "Communication", "score": 7 }
    ],
    "badgeImageUrl": "https://scout-interview.sgp1.cdn.digitaloceanspaces.com/certifications/public/intermediate-badge.png",
    "badgeEarned": true,
    "badgeExpiresAt": "2027-07-20T09:41:00.000Z"
  }
}

The result object has the exact same shape as developerCertificationResult. For an initial invite, followUp is null. For a candidate's retake or level-up attempt, it identifies the source invite and the selected option.

Follow-up attempts

When a candidate claims a one-time follow-up offer, Scout Select creates a separate invite and assessment session. If the original invite was created with an API-key callbackUrl, the follow-up invite inherits its callback URL, signing API key, and externalReference.

The inherited endpoint receives certification.follow_up_claimed first, then receives the normal lifecycle events for the new invite, including the authoritative certification.result_released event. Use the new top-level inviteId for the retake itself and followUp.originalInviteId to associate it with the original attempt. The original invite's own result is not re-sent.

Verifying the signature

Every callback carries an x-scout-signature header of the form sha256=<hex-hmac>, computed as HMAC-SHA256(rawRequestBody, yourWebhookSigningSecret) - the secret returned once when the API key used to create the invite was generated (see Authentication).

import { createHmac, timingSafeEqual } from "node:crypto";

function verifyScoutSignature(rawBody, signatureHeader, webhookSigningSecret) {
  const expected = "sha256=" + createHmac("sha256", webhookSigningSecret).update(rawBody).digest("hex");
  return (
    signatureHeader.length === expected.length &&
    timingSafeEqual(Buffer.from(signatureHeader), Buffer.from(expected))
  );
}

Compute the HMAC over the raw, unparsed request body - re-serializing parsed JSON can change byte ordering and break the comparison.

Delivery notes

  • Requests time out after 10 seconds on Scout Select's side. Failed deliveries are retried: up to 5 attempts with exponential backoff (roughly 1 min, 5 min, 30 min, 2 hr, then 12 hr after each failure) before being marked permanently failed. Keep polling Results as a fallback for critical flows regardless.
  • Deduplicate on eventId - a retried delivery reuses the same eventId as its original attempt.
  • Treat certification.result_released as the authoritative "done" signal; certification.completed can fire before review finishes for flagged attempts.
  • If your organization has configured an allowed webhook domains list, callbackUrl must match one of the allowed hostnames or the invite/assign mutation is rejected upfront.

On this page