Overview
Webhooks enable real-time event notifications between Royalti.io and your systems. This guide covers two distinct webhook systems:- Outbound Webhooks - Royalti sends event notifications TO your endpoints when events occur
- Inbound Webhooks - Your systems send status updates TO Royalti endpoints
Why Use Webhooks?
- Real-time Updates: Get notified instantly when events occur instead of polling APIs
- Automation: Trigger workflows in your systems based on Royalti events
- Efficiency: Reduce API calls and server load
- Integration: Connect Royalti with external tools (CRMs, analytics, notifications)
Outbound Webhooks (Royalti Sends to You)
Outbound webhooks allow you to receive real-time notifications when events occur in your Royalti workspace.Quick Start
Configure Webhook URL
Enable Webhooks
Subscribe to Events
enabledEvents and the payload’s event field are matched on this exact string. enabledEvents must be a JSON array (or the literal string "all") — a comma-separated string is silently accepted but never matches anything.Implement Endpoint
Event Catalog
Royalti.io emits 40 event types across the categories below.Financial Events (Require Signature Validation)
These events involve sensitive financial data and automatically enforce HMAC signature validation:Catalog Events (Default Enabled)
Roster Events (Default Enabled)
Royalty Events (Require Explicit Opt-in)
High-volume events that require explicit opt-in to prevent overwhelming webhooks:Split Events (Require Signature Validation)
Release Lifecycle Events (Default Enabled)
Emitted after a release transitions status through the Release API (submit, approve/reject review — single or bulk, manual status revert) or via the release auto-creation queue worker on success.resource.type is release, resource.id is the release ID, resource.url is /api/v1/releases/{id}, and resource.displayName is the release title.
DDEX Provider Delivery Events (Default Enabled)
Emitted by the provider-agnostic DDEX delivery manager, so queue-driven deliveries fire these events as well as interactively-triggered ones.resource.type is providerDelivery and resource.id is the delivery ID (falls back to the message ID when no delivery ID has been assigned yet).
Webhook Payload Structure
All outbound webhooks follow this standardized structure:Field Descriptions
Webhook Configuration
Configure your webhook behavior through Tenant Settings —PUT /tenant/settings/{name} (requires the admin role or higher).
Available Settings
webhook-metrics.lastDeliveryAttempt, totalDeliveries, healthScore, etc.) are computed and written by the delivery pipeline itself — they’re read-only and appear in the webhook object of any settings-update response, not something you PUT.Example: Complete Webhook Configuration
Webhook Monitoring & Analytics
Track your webhook performance using the Webhook Deliveries API:Get Delivery History
Get Delivery Summary
Get Detailed Analytics
Retry Failed Delivery
Security Best Practices
HMAC Signature Verification
When signature validation is enabled, Royalti signs all webhook payloads using HMAC-SHA256.Headers Sent by Royalti
Verification Implementation
URL Validation
Royalti enforces strict URL validation for webhook endpoints: ✅ Allowed:- HTTPS URLs (required by default)
- Ports: 80, 443, 8080, 8443
- Public IP addresses and domains
-
HTTP URLs (unless
webhook-config.requireHttpsis false) - Private network ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)
- Localhost (127.0.0.0/8)
- URLs longer than 2048 characters
Rate Limiting
Webhooks are subject to per-tenant rate limits:- Default: 100 deliveries per minute per webhook
- Auto-disable: Webhooks are automatically disabled after 50 consecutive failures
- Re-enable: Contact support or manually re-enable via settings
Error Handling & Retry Logic
HTTP Status Codes
Your webhook endpoint should return appropriate HTTP status codes:Retry Strategy
Royalti automatically retries failed webhook deliveries:- Initial Attempt: Delivered immediately when event occurs
- Retry 1: After 2 seconds (if initial failed)
- Retry 2: After 4 seconds (exponential backoff)
- Retry 3: After 8 seconds (exponential backoff)
- Final: Marked as failed after max attempts exhausted
-
webhook-config.retryAttempts: Set max retry attempts (default: 3, range: 0–10) - Exponential backoff with 2-second initial delay
- Each retry doubles the delay
Error Categories
Royalti categorizes webhook errors for easier debugging:Manual Retry
You can manually retry failed deliveries via API:finalAttempt: false.Testing & Development
Local Testing with ngrok
To test webhooks locally, use ngrok to expose your local server:Start your local server
Start ngrok tunnel
https://abc123.ngrok.io)Configure webhook URL
Trigger test events
Test Payload Examples
Payment Completed Event
Asset Created Event
Inbound Webhooks (You Send to Royalti)
Inbound webhooks allow external systems to send status updates TO Royalti when events occur in your systems.Royalty File Status Update
Notify Royalti when royalty file processing completes in your external system. Endpoint:POST /webhook/royalty/file-update/webhook
Authentication: royalti-x-hash header with HMAC signature
Payload:
Download Status Update
Notify Royalti when a download file is ready. Endpoint:POST /webhook/download/status-update/webhook
Authentication: royalti-x-hash header with HMAC signature
Payload:
Third-Party Webhooks (System Integration)
Royalti integrates with third-party services that send webhooks to the platform.Stripe Billing Events
Royalti receives Stripe webhooks for subscription and billing events. Supported Events:- Subscription lifecycle (created, updated, deleted)
- Invoice events (payment succeeded, payment failed)
- Checkout session completed
- Customer created/updated
- Billing meter events
Cloudflare Domain & SSL Status
For custom domains configured through Cloudflare SaaS, Royalti receives:- Custom hostname events (created, deleted)
- SSL validation events (completed, failed)
- SSL renewal events (renewed, renewal failed)
Complete Code Examples
Express.js Webhook Server
Idempotency Implementation
Troubleshooting
Common Issues
Webhooks Not Received
✅ Checklist:-
Is
webhook-config.isActiveset totrue? -
Is
webhook-config.urlcorrectly configured with HTTPS? -
Are you subscribed to the event type (
webhook-config.enabledEvents, as a JSON array — notwebhook-enabledEvents, which is silently never read)? - Check webhook delivery logs for error details
- Verify your endpoint is publicly accessible
- Check firewall/security group rules
Signature Verification Failures
✅ Checklist:- Are you using the raw request body (not parsed JSON)?
- Is your secret token correct?
- Are you using the same algorithm (HMAC-SHA256)?
- Check for character encoding issues
- Verify timing-safe comparison is used
Timeout Errors
✅ Solutions:- Optimize your webhook handler (should respond in <5 seconds)
- Process events asynchronously (queue for background processing)
-
Increase
webhook-config.timeoutMsif legitimately needed - Return 200 immediately, then process in background
High Failure Rate
✅ Investigation Steps:- Check delivery logs for error codes
- Monitor your endpoint’s error logs
- Verify endpoint uptime/availability
- Check for rate limiting on your server
- Review error distribution by event type
Best Practices
✅ Production Deployment- Always enable signature validation in production
- Use HTTPS for webhook endpoints (enforced by default)
- Respond quickly (<5 seconds) to prevent timeouts
- Process async - queue events for background processing
- Implement idempotency to handle duplicate events safely
- Log everything - delivery ID, event type, processing time
- Monitor delivery success rates via analytics API
- Set up alerts for high failure rates (>5%)
- Test thoroughly using ngrok in development
- Handle all event types gracefully (even unknown ones)
- Never log webhook payloads containing sensitive data
- Validate all webhook data before processing
- Use environment variables for secrets
- Implement rate limiting on your webhook endpoint
- Monitor for abnormal patterns (sudden spikes, unusual sources)
- Rotate secrets regularly (quarterly recommended)
- Use timing-safe comparison for signature verification
- Sanitize data before database insertion
- Implement IP whitelisting if possible
- Keep dependencies updated for security patches
Support & Resources
API Documentation:- API Reference - Complete API documentation for webhook endpoints
- Webhook Deliveries API - Monitor and manage webhook deliveries
- Support Portal - Get help from our support team
- Status Page - Check system status and uptime
FAQ
Can I receive webhooks for events that occurred before I configured my webhook?
Can I receive webhooks for events that occurred before I configured my webhook?
How long does Royalti retry failed webhook deliveries?
How long does Royalti retry failed webhook deliveries?
webhook-config.retryAttempts configuration (default: 3 attempts) with exponential backoff starting at 2 seconds. After exhausting all retries, the delivery is marked as failed and can be manually retried via API.Can I configure different webhook URLs for different event types?
Can I configure different webhook URLs for different event types?
event field.What happens if my webhook endpoint is down?
What happens if my webhook endpoint is down?
How do I test webhooks in development?
How do I test webhooks in development?
Are webhooks sent in order?
Are webhooks sent in order?
Can I disable webhooks temporarily?
Can I disable webhooks temporarily?
webhook-config.isActive to false via the Tenant Settings API. Events that occur while webhooks are disabled will NOT be queued - they are lost permanently.How do I rotate my webhook secret token?
How do I rotate my webhook secret token?
webhook-config.secretToken setting with a new secure random value via the Tenant Settings API. Update your webhook endpoint code with the new secret before rotating to prevent signature verification failures.Last Updated: January 2025 Version: 1.0