Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.scute.io/llms.txt

Use this file to discover all available pages before exploring further.

Webhooks

Receive real-time notifications when events happen in your app. Signed with HMAC-SHA256.

Setup

POST /v1/apps/{app_id}/webhooks
Authorization: Bearer {api_key}
{
  "webhook": {
    "url": "https://your-server.com/webhooks",
    "event_types": ["verification.sms.verified", "verification.sms.expired"],
    "retry_limit": 3
  }
}
ParameterTypeRequiredDescription
urlstringyesHTTPS endpoint
event_typesstring[]noEvents to subscribe to. Default: all
retry_limitintnoRetry attempts (0-10). Default: 3
descriptionstringnoLabel
metadataobjectnoCustom metadata
enabledboolnoDefault: true

Payload

Content-Type: application/json
User-Agent: AppName-Webhooks/1.0
X-Webhook-Signature: t=1713232500,v1=5a3c2b...
{
  "id": "uuid",
  "created_at": "2026-04-16T12:00:00Z",
  "event_type": "verification.sms.verified",
  "app_id": "uuid",
  "data": { ... },
  "api_version": "v1"
}

Signature verification

The X-Webhook-Signature header contains a timestamp and HMAC:
t=1713232500,v1=5a3c2b...
Verify:
const crypto = require("crypto");

function verifyWebhook(payload, header, secret) {
  const [tPart, sigPart] = header.split(",");
  const timestamp = tPart.replace("t=", "");
  const signature = sigPart.replace("v1=", "");

  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${timestamp}.${payload}`)
    .digest("hex");

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

Events

Verification events

Pattern: verification.{channel}.{outcome} — channel is email or sms.
EventWhen
verification.*.requestedVerification sent
verification.*.verifiedContact confirmed (magic link click, OTP code, or consent approval)
verification.*.expiredTimed out. Fires even if the link was never opened
verification.*.failedOTP max attempts exceeded
verification.*.deniedContact denied the action (consent mode)
verification.*.delivery_failedSMS/email failed to send (bad number, provider error)
Verification payloads include:
{
  "data": {
    "verification_id": "uuid",
    "intent": "Password Reset",
    "meta_data": {
      "contact_email": "user@company.com",
      "ticket_id": "12345",
      "delivery_method": "sms"
    },
    "timing": {
      "sent_at": "2026-04-16T01:00:00Z",
      "opened_at": "2026-04-16T01:00:47Z",
      "confirmed_at": "2026-04-16T01:00:52Z",
      "time_to_verify_seconds": 52
    },
    "device": { "os": "iOS", "browser": "Safari" },
    "ip_address": "203.0.113.42"
  }
}
Expiration events add was_opened: true/false. Consent events add consent_decision and denial_reason. Delivery failures add error and channel.

Auth events

EventWhen
auth.login.failedLogin attempt failed
challenge.createdChallenge created (any type)
challenge.completedChallenge verified
challenge.failedChallenge failed

User events

EventWhen
user.createdNew user registered
user.updatedUser profile updated
user.identifier_changedEmail or phone changed

System events

EventWhen
webhook.testTest ping from dashboard

Managing endpoints

ActionMethod
ListGET /v1/apps/{app_id}/webhooks
GetGET /v1/apps/{app_id}/webhooks/{id}
UpdatePATCH /v1/apps/{app_id}/webhooks/{id}
DeleteDELETE /v1/apps/{app_id}/webhooks/{id}
TestPOST /v1/apps/{app_id}/webhooks/{id}/test
DeliveriesGET /v1/apps/{app_id}/webhooks/{id}/deliveries

Delivery status

StatusMeaning
pendingQueued
processingIn flight
delivered2xx response
failedWill retry if retryable

Limits

  • 10-second timeout per delivery
  • Max 10 retries with exponential backoff
  • Respond with 2xx within 5 seconds
  • 4xx = won’t retry. 5xx = will retry.