stile
HTTP API

Webhook Endpoints

Register, manage, and debug the HTTPS endpoints that receive Stile's signed event notifications.

A webhook endpoint is an HTTPS URL on your server where Stile delivers signed events — session verified, failed, expired, and more. This page covers the management API: creating endpoints, rotating secrets, and inspecting individual deliveries. For signature verification and handler patterns, see the Webhooks guide. You can also manage endpoints in the dashboard.

Examples show cURL, Python, Go, and Node.js. You can also use the Node.js SDK as a typed convenience wrapper.

Live orgs require a webhook endpoint

You cannot create verification sessions until at least one active webhook endpoint exists (the API returns 400 webhook_required). Sandbox organizations are exempt.

The webhook endpoint object

FieldTypeDescription
idstringUnique identifier, prefixed we_.
urlstringThe HTTPS URL events are delivered to.
enabled_eventsstring[]Subscribed event types. ["*"] means all events.
statusstringenabled or disabled. Disabled endpoints receive no deliveries.
descriptionstringHuman-readable label.
metadataobjectKey-value string pairs you attach.
secretstringThe signing secret used to compute Stile-Signature. Returned once — on create and on rotate only.

Create an endpoint

POST/v1/webhook_endpoints

Your endpoint must be a publicly reachable HTTPS URL (plain HTTP is allowed for sandbox/local testing only) and must respond with a 2xx within 30 seconds. Return a 2xx as soon as you've queued the work — process asynchronously.

ParameterTypeDescription
urlrequiredstringThe HTTPS URL to deliver events to.
enabled_eventsrequiredstring[]Event types to subscribe to. Use ["*"] to receive all events.
descriptionstringA human-readable label for this endpoint.
metadataobjectKey-value string pairs to attach to the endpoint.
curl https://api.stile.id/v1/webhook_endpoints \
  -H "Authorization: Bearer stile_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yourapp.com/api/webhooks",
    "enabled_events": ["verification_session.verified", "verification_session.failed"]
  }'
import requests

res = requests.post(
    "https://api.stile.id/v1/webhook_endpoints",
    headers={"Authorization": "Bearer stile_sk_..."},
    json={
        "url": "https://yourapp.com/api/webhooks",
        "enabled_events": [
            "verification_session.verified",
            "verification_session.failed",
        ],
        "description": "Production webhook",
    },
)
endpoint = res.json()

# IMPORTANT: save endpoint["secret"] — it's only shown once!
print("Webhook secret:", endpoint["secret"])
body := strings.NewReader(`{
  "url": "https://yourapp.com/api/webhooks",
  "enabled_events": ["verification_session.verified", "verification_session.failed"],
  "description": "Production webhook"
}`)
req, _ := http.NewRequest("POST", "https://api.stile.id/v1/webhook_endpoints", body)
req.Header.Set("Authorization", "Bearer stile_sk_...")
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
const endpoint = await stile.webhookEndpoints.create({
  url: "https://yourapp.com/api/webhooks",
  enabled_events: [
    "verification_session.verified",
    "verification_session.failed",
    "verification_session.expired",
  ],
  description: "Production webhook",
});

// IMPORTANT: save endpoint.secret — it's only shown once!
console.log("Webhook secret:", endpoint.secret);

Store the secret immediately

The response includes the endpoint's signing secret exactly once. Store it in your secret manager right away — you need it to verify the Stile-Signature header on every delivery. If you lose it, rotate the secret to get a new one.

Retrieve an endpoint

GET/v1/webhook_endpoints/:id
const endpoint = await stile.webhookEndpoints.retrieve("we_abc123");

The secret is not included — it is only returned on create and rotate.

Update an endpoint

POST/v1/webhook_endpoints/:id
ParameterTypeDescription
urlstringNew delivery URL.
enabled_eventsstring[]Replace the subscribed event types.
status"enabled" | "disabled"Pause or resume delivery without deleting the endpoint.
descriptionstringUpdate the label.
metadataobjectReplace all metadata key-value pairs.
// Subscribe to all events
await stile.webhookEndpoints.update("we_abc123", {
  enabled_events: ["*"],
});

// Temporarily pause delivery
await stile.webhookEndpoints.update("we_abc123", {
  status: "disabled",
});

Delete an endpoint

DELETE/v1/webhook_endpoints/:id
await stile.webhookEndpoints.del("we_abc123");

List endpoints

GET/v1/webhook_endpoints
curl https://api.stile.id/v1/webhook_endpoints \
  -H "Authorization: Bearer stile_sk_..."
import requests

res = requests.get(
    "https://api.stile.id/v1/webhook_endpoints",
    headers={"Authorization": "Bearer stile_sk_..."},
)
data = res.json()
req, _ := http.NewRequest("GET", "https://api.stile.id/v1/webhook_endpoints", nil)
req.Header.Set("Authorization", "Bearer stile_sk_...")
res, _ := http.DefaultClient.Do(req)
const { data } = await stile.webhookEndpoints.list();

Rotate the signing secret

POST/v1/webhook_endpoints/:id/rotate-secret

Generates a new signing secret for the endpoint and returns it once.

curl -X POST https://api.stile.id/v1/webhook_endpoints/we_abc123/rotate-secret \
  -H "Authorization: Bearer stile_sk_..."

Rotation takes effect immediately

Update your environment variables as soon as you rotate — deliveries signed with the old secret will stop validating.

List deliveries

GET/v1/webhook_endpoints/:id/deliveries

Returns a paginated list of delivery attempts for a specific endpoint, newest first. Useful for debugging failed deliveries and monitoring webhook health. Each delivery records the event type, the attempt number, and the HTTP status your endpoint returned; the delivery's id is also sent to your endpoint as the Stile-Webhook-Id header.

ParameterTypeDescription
limitnumber= 20Number of deliveries to return.
starting_afterstringDelivery ID cursor for pagination.
const { data } = await stile.webhookEndpoints.listDeliveries("we_abc123", {
  limit: 10,
});

for (const delivery of data) {
  console.log(delivery.event_type, delivery.response_status, delivery.attempt);
}

Retrieve a delivery

GET/v1/webhook_endpoints/:id/deliveries/:deliveryId

Returns the full detail for a single delivery attempt, including the request payload and the response your endpoint returned — useful when debugging a failing handler.

Retry a delivery

POST/v1/webhook_endpoints/:id/deliveries/:deliveryId/retry

Re-queues a failed delivery immediately instead of waiting for the automatic retry schedule (5 min → 30 min → 2 h → 8 h after the initial failure, after which the delivery is marked permanently failed — see the Webhooks guide).

curl -X POST https://api.stile.id/v1/webhook_endpoints/we_abc123/deliveries/whd_xyz789/retry \
  -H "Authorization: Bearer stile_sk_..."

Retries reuse the original event id but get a new delivery id — deduplicate your handler on the event id.

Event types

See the full catalog in the Events API reference — verification session lifecycle (verification_session.*), manual review outcomes (session_review.*), and trust-reuse grants (trust_reuse_grant.*, trust_reuse_consent.*). Use ["*"] in enabled_events to subscribe to everything.

Next steps

On this page