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.

Payload shape

{
  "eventId": "8f14e45f-...",
  "eventType": "certification.result_released",
  "occurredAt": "2026-07-20T09:41:03.120Z",
  "inviteId": "clv2x...",
  "externalReference": "seemesol-user-12345",
  "result": {
    "inviteId": "clv2x...",
    "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/certifications/verify/abc123",
    "verificationStatus": "ISSUED",
    "feedbackAreas": ["Error handling", "Debugging"],
    "reportUrl": "https://select.getscout.ai/reports/9f3a1c..."
  }
}

The result object has the exact same shape as developerCertificationResult.

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; a failed delivery is not currently retried, so keep polling Results as a fallback for critical flows.
  • Deduplicate on eventId - the same event is never intentionally sent twice, but always code defensively.
  • Treat certification.result_released as the authoritative "done" signal; certification.completed can fire before review finishes for flagged attempts.

On this page