Webhooks

Webhooks avoid continuously polling resource state. Each delivery sends JSON to an HTTPS URL.

Create an endpoint

POST /webhook-endpoints · scope webhooks:write · idempotent · response 201

BASH
curl -X POST https://api.subdomain.to/v1/webhook-endpoints \
  -H "Authorization: Bearer $SUBDOMAIN_TO_API_KEY" \
  -H "Idempotency-Key: webhook-production" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/webhooks/subdomainto","events":["hostname.created","hostname.deleting"]}'

events defaults to ['*']. The secret field is returned only by this creation response; store it immediately.

Delivery format

JSON
{"id":"01J00000000000000000000004","event":"hostname.created","created_at":"2026-07-15T10:30:00+00:00","data":{"id":"01J...","hostname":"portal.customer.com"}}

Verify the signature

The header is SubdomainTo-Signature: t=timestamp,v1=signature. The signature is the HMAC-SHA256 of timestamp + "." + raw_body using the endpoint secret.

JAVASCRIPT
import { verifyWebhook } from '@subdomainto/node';

const event = verifyWebhook(rawBody, signatureHeader, endpointSecret);

Always use the untouched raw body, compare signatures in constant time, and reject stale timestamps. Official SDKs implement these checks with a default tolerance of 300 seconds.