Webhooks
SendPromptly delivers outbound webhooks as HTTP POST requests to customer endpoints. Each webhook is signed, traced, and retried on failure.
Headers included with every webhook
X-SP-Event-Key: event name (e.g.user.signup)X-SP-Message-Id: unique message ULIDX-SP-Timestamp: unix timestamp of sendX-SP-Signature:v1=<hex_hmac_sha256>— HMAC-SHA256 over the string{timestamp}.{body}using the endpoint secret
Signature verification (recommended)
- Extract
X-SP-TimestampandX-SP-Signaturefrom headers. - Reject if the timestamp is older/newer than 5 minutes (prevent replay).
- Recreate
signedContent = "{timestamp}.{raw_body}". - Compute expected HMAC-SHA256 using your webhook secret and hex-encode.
- Use a constant-time comparison (
hash_equals) to compare the expected value with thev1=signature.
Example header: X-SP-Signature: v1=0123ab...
Delivery semantics & retries
- Success is strictly
2xxresponses only; any non-2xx triggers a retry. - Timeout for webhook delivery attempts is 30 seconds.
- Retry schedule (MVP): 5 attempts total at
0s,+1m,+10m,+1h,+6h. - Retries do not increment tenant usage; usage is counted once on first successful delivery per
delivery_run.
Security & SSRF protections
- Webhook endpoints must use HTTPS; non-TLS endpoints are rejected.
- The portal performs DNS/IP checks to prevent SSRF; endpoints are validated at create time and before each send.
Operations
- Rotate signing secret in the Webhook Endpoints screen; the portal stores secrets encrypted.
- Use the portal’s Test Webhook button to exercise an endpoint and view attempts.
- Message details show delivery runs and attempt logs with failure reasons and timestamps.
Example verification pseudo-code
# timestamp = request.headers['X-SP-Timestamp']
# signature = request.headers['X-SP-Signature'] # e.g. "v1=<hex>"
# body = raw_request_body
# signed = f"{timestamp}.{body}"
# expected = HMAC_SHA256(secret, signed) # hex
# if not hash_equals(expected, signature_after_parsing): reject
Link to: API ingestion quickstart and portal Webhook Endpoints UI for setup steps and examples.