Webhooks
Webhooks allow you to receive real-time notifications about transaction events and signing operations. When configured, rrelayer will send HTTP POST requests to your specified endpoints whenever certain events occur.
Overview
rrelayer supports webhooks for the following events:
Transaction Events
transaction_queued
- Transaction was added to the queuetransaction_sent
- Transaction was sent to the blockchaintransaction_mined
- Transaction was mined (included in a block)transaction_confirmed
- Transaction reached required confirmationstransaction_failed
- Transaction failedtransaction_expired
- Transaction expiredtransaction_cancelled
- Transaction was cancelledtransaction_replaced
- Transaction was replaced
Signing Events
text_signed
- Text message was signedtyped_data_signed
- Typed data (EIP-712) was signed
Balance Alert Events
low_balance
- Relayer balance fell below minimum threshold
Configuration
Basic Configuration
name: first-rrelayer
description: "my first rrelayer"
api_config:
port: 3000
authentication_username: "${RRELAYER_AUTH_USERNAME}"
authentication_password: "${RRELAYER_AUTH_PASSWORD}"
signing_provider:
aws_kms:
region: "eu-west-1"
networks:
- name: "sepolia_ethereum"
chain_id: 11155111
provider_urls:
- "https://sepolia.gateway.tenderly.co"
block_explorer_url: "https://sepolia.etherscan.io"
max_gas_price_multiplier: 4
gas_bump_blocks_every:
slow: 10
medium: 5
fast: 4
super_fast: 2
webhooks:
- endpoint: "https://api.yourapp.com/webhooks/rrelayer"
shared_secret: "${WEBHOOK_SECRET}"
networks: "*"
max_retries: 3
alert_on_low_balances: true
Multiple Webhooks
You can configure multiple webhook endpoints for different purposes:
webhooks:
- endpoint: "https://api.yourapp.com/webhooks/transactions"
shared_secret: "${TRANSACTION_WEBHOOK_SECRET}"
networks: ["sepolia_ethereum", "polygon_mainnet"]
max_retries: 5
- endpoint: "https://monitoring.yourapp.com/webhooks/alerts"
shared_secret: "${ALERT_WEBHOOK_SECRET}"
networks: "*"
max_retries: 3
alert_on_low_balances: true
Network Filtering
Control which networks trigger webhooks:
webhooks:
# Send webhooks for all networks (using string)
- endpoint: "https://api.yourapp.com/webhooks/all"
shared_secret: "${WEBHOOK_SECRET}"
networks: "*"
# Send webhooks for all networks (using array)
- endpoint: "https://api.yourapp.com/webhooks/all-array"
shared_secret: "${WEBHOOK_SECRET}"
networks: ["*"]
# Send webhooks only for specific networks
- endpoint: "https://api.yourapp.com/webhooks/ethereum"
shared_secret: "${WEBHOOK_SECRET}"
networks: ["sepolia_ethereum", "ethereum_mainnet"]
# Send webhooks for no networks (webhook disabled)
- endpoint: "https://api.yourapp.com/webhooks/disabled"
shared_secret: "${WEBHOOK_SECRET}"
networks: []
Configuration Options
Required Fields
endpoint
: The URL where webhook requests will be sentshared_secret
: Secret used for webhook authentication and payload verificationnetworks
: Network filter - can be "*" for all networks, or an array of network names
Optional Fields
max_retries
: Maximum number of retry attempts for failed webhooks (default: 3)alert_on_low_balances
: Enable low balance alerts for relayers (default: false)
Webhook Payload Structure
Transaction Webhooks
All transaction webhooks send a JSON payload with this structure:
{
"eventType": "transaction_sent",
"apiVersion": "1.0",
"timestamp": "2025-09-26T10:30:00Z",
"transaction": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"relayerId": "550e8400-e29b-41d4-a716-446655440001",
"to": "0x1234567890abcdef1234567890abcdef12345678",
"from": "0x742d35cc6466c4b0de3e3e8c7b8e8f9e8a8d8c8b",
"value": "1000000000000000000",
"data": "0xa9059cbb000000000000000000000000...",
"chainId": 11155111,
"status": "INMEMPOOL",
"txHash": "0xabcdef123456789abcdef123456789abcdef123456789abcdef123456789abcdef",
"queuedAt": "2025-09-26T10:29:30Z",
"sentAt": "2025-09-26T10:30:00Z",
"expiresAt": "2025-09-26T11:30:00Z",
"externalId": "order_12345",
"nonce": 42,
"maxPriorityFee": "2.0",
"maxFee": "15.5",
"isNoop": false
}
}
Enhanced Payloads
Some events include additional data:
Transaction Mined/Confirmed with Receipt
{
"eventType": "transaction_mined",
"apiVersion": "1.0",
"timestamp": "2025-09-26T10:32:00Z",
"transaction": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"relayerId": "550e8400-e29b-41d4-a716-446655440001",
"to": "0x1234567890abcdef1234567890abcdef12345678",
"from": "0x742d35cc6466c4b0de3e3e8c7b8e8f9e8a8d8c8b",
"value": "1000000000000000000",
"data": "0xa9059cbb000000000000000000000000...",
"chainId": 11155111,
"status": "MINED",
"txHash": "0xabcdef123456789abcdef123456789abcdef123456789abcdef123456789abcdef",
"queuedAt": "2025-09-26T10:29:30Z",
"sentAt": "2025-09-26T10:30:00Z",
"confirmedAt": "2025-09-26T10:32:00Z",
"expiresAt": "2025-09-26T11:30:00Z",
"externalId": "order_12345",
"nonce": 42,
"minedAt": "2025-09-26T10:32:00Z",
"minedAtBlockNumber": 1193046,
"maxPriorityFee": "2.0",
"maxFee": "15.5",
"isNoop": false
},
"receipt": {
"transactionHash": "0xabcdef123456789abcdef123456789abcdef123456789abcdef123456789abcdef",
"blockNumber": "0x123456",
"blockHash": "0xfedcba987654321fedcba987654321fedcba987654321fedcba987654321fedcba",
"gasUsed": "0x5208",
"status": "0x1",
"logs": []
}
}
Transaction Replaced
{
"eventType": "transaction_replaced",
"apiVersion": "1.0",
"timestamp": "2025-09-26T10:35:00Z",
"transaction": {
"id": "550e8400-e29b-41d4-a716-446655440002",
"relayerId": "550e8400-e29b-41d4-a716-446655440001",
"to": "0x1234567890abcdef1234567890abcdef12345678",
"from": "0x742d35cc6466c4b0de3e3e8c7b8e8f9e8a8d8c8b",
"value": "1000000000000000000",
"data": "0xa9059cbb000000000000000000000000...",
"chainId": 11155111,
"status": "PENDING",
"txHash": "0xdef456ghi789def456ghi789def456ghi789def456ghi789def456ghi789def456",
"queuedAt": "2025-09-26T10:35:00Z",
"sentAt": null,
"confirmedAt": null,
"expiresAt": "2025-09-26T11:35:00Z"
},
"originalTransaction": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"relayerId": "550e8400-e29b-41d4-a716-446655440001",
"to": "0x1234567890abcdef1234567890abcdef12345678",
"from": "0x742d35cc6466c4b0de3e3e8c7b8e8f9e8a8d8c8b",
"value": "1000000000000000000",
"data": "0xa9059cbb000000000000000000000000...",
"chainId": 11155111,
"status": "EXPIRED",
"txHash": "0xabcdef123456789abcdef123456789abcdef123456789abcdef123456789abcdef",
"queuedAt": "2025-09-26T10:29:30Z",
"sentAt": "2025-09-26T10:30:00Z",
"confirmedAt": null,
"expiresAt": "2025-09-26T11:30:00Z"
}
}
Signing Webhooks
Signing webhooks have a different payload structure:
Text Signing
{
"eventType": "text_signed",
"apiVersion": "1.0",
"timestamp": "2025-09-26T10:30:00Z",
"signing": {
"relayerId": "550e8400-e29b-41d4-a716-446655440001",
"chainId": 11155111,
"signature": {
"r": "0x1234567890abcdef...",
"s": "0xfedcba0987654321...",
"v": 27
},
"signedAt": "2025-09-26T10:30:00Z",
"message": "Hello, World!"
}
}
Typed Data Signing (EIP-712)
{
"eventType": "typed_data_signed",
"apiVersion": "1.0",
"timestamp": "2025-09-26T10:30:00Z",
"signing": {
"relayerId": "550e8400-e29b-41d4-a716-446655440001",
"chainId": 11155111,
"signature": {
"r": "0x1234567890abcdef...",
"s": "0xfedcba0987654321...",
"v": 27
},
"signedAt": "2025-09-26T10:30:00Z",
"domainData": {
"name": "MyApp",
"version": "1",
"chainId": 11155111,
"verifyingContract": "0x..."
},
"messageData": {
"user": "0x...",
"amount": "1000"
},
"primaryType": "Transfer"
}
}
Balance Alert Webhooks
Balance alert webhooks are sent when a relayer's balance falls below the minimum threshold for its network:
{
"eventType": "low_balance",
"apiVersion": "1.0",
"timestamp": "2025-09-27T14:30:00Z",
"balanceAlert": {
"relayerId": "550e8400-e29b-41d4-a716-446655440001",
"address": "0x742d35cc6466c4b0de3e3e8c7b8e8f9e8a8d8c8b",
"chainId": 1,
"currentBalance": "3500000000000000000",
"minimumBalance": "5000000000000000000",
"currentBalanceFormatted": "3.5",
"minimumBalanceFormatted": "5.0",
"detectedAt": "2025-09-27T14:30:00Z"
}
}
Balance Monitoring Thresholds
rrelayer automatically monitors relayer balances and sends alerts based on network-specific thresholds:
- Ethereum Mainnet: 0.005 ETH minimum (higher due to gas costs)
- Layer 2 Networks (Polygon, Arbitrum, Optimism, Base, etc.): 0.001 ETH minimum
- Testnets (Sepolia, Mumbai, etc.): 0.0005 ETH minimum
Balance checks run every 10 minutes and both log warnings and send webhooks when enabled.
Webhook Authentication
Webhook authentication is configured through the shared_secret
field in your webhook configuration. This secret is used for webhook authentication and payload verification.
Security Configuration
Each webhook endpoint requires a shared secret for authentication:
webhooks:
- endpoint: 'https://api.yourapp.com/webhooks/rrelayer'
shared_secret: '${WEBHOOK_SECRET}' # Strong secret for authentication
networks: '*'
Best Practices
- Use strong secrets - Generate cryptographically secure random strings
- Keep secrets secure - Store in environment variables, not in configuration files
- Rotate secrets regularly - Update webhook secrets periodically
- Use HTTPS endpoints - Always use encrypted connections for webhook delivery
Delivery and Retry Logic
Delivery Behavior
- Webhooks are sent as HTTP POST requests with JSON payloads
- rrelayer considers a webhook successful if it receives a 2xx HTTP response
- Failed webhooks are automatically retried with exponential backoff
Retry Configuration
- Default max retries: 3 attempts
- Initial retry delay: 1 second
- Maximum retry delay: 2 minutes
- Exponential backoff multiplier: 2.0
- Request timeout: 30 seconds
Retry Schedule Example
- Initial attempt: Immediate
- First retry: After 1 second
- Second retry: After 2 seconds
- Third retry: After 4 seconds
- Final failure: After 3 failed attempts
Low Balance Alerts
Enable Balance Monitoring
To receive alerts when relayer balances fall below safe thresholds, enable the alert_on_low_balances
option:
webhooks:
- endpoint: 'https://monitoring.yourapp.com/webhooks/alerts'
shared_secret: '${MONITORING_WEBHOOK_SECRET}'
networks: '*'
alert_on_low_balances: true # Enable balance alerts
Dedicated Alert Endpoint
For better monitoring, consider using a separate webhook endpoint specifically for alerts:
webhooks:
# Transaction notifications
- endpoint: 'https://api.yourapp.com/webhooks/transactions'
shared_secret: '${TRANSACTION_WEBHOOK_SECRET}'
networks: '*'
max_retries: 3
# Balance and system alerts
- endpoint: 'https://monitoring.yourapp.com/webhooks/alerts'
shared_secret: '${ALERT_WEBHOOK_SECRET}'
networks: '*'
max_retries: 5
alert_on_low_balances: true
Monitoring Integration
Low balance webhooks integrate well with monitoring systems:
// Example webhook handler for balance alerts
app.post('/webhooks/alerts', (req, res) => {
const { event_type, balance_alert } = req.body;
if (event_type === 'low_balance') {
const {
relayerId,
chainId,
currentBalanceFormatted,
minimumBalanceFormatted,
} = balanceAlert;
// Send alert to monitoring system
monitoring.alert({
level: 'warning',
message: `Low balance: Relayer ${relayerId} on chain ${chainId}`,
details: {
current: `${currentBalanceFormatted} ETH`,
minimum: `${minimumBalanceFormatted} ETH`,
chain: chainId,
},
});
// Optionally trigger automatic top-up process
if (shouldAutoTopUp(chainId, currentBalanceFormatted)) {
triggerTopUp(relayerId, chainId);
}
}
res.status(200).json({ received: true });
});
Best Practices
Endpoint Implementation
- Return 2xx status codes for successful processing
- Implement idempotency - Handle duplicate webhooks gracefully
- Process quickly - Respond within 30 seconds to avoid timeouts
- Verify signatures - Always validate the
X-rrelayer-Signature
header
Error Handling
-
Use appropriate HTTP status codes:
200-299
: Success - webhook processed400-499
: Client error - rrelayer will not retry500-599
: Server error - rrelayer will retry
-
Log webhook failures for debugging
-
Implement monitoring for webhook endpoint health
Security
- Use HTTPS endpoints for production
- Validate webhook signatures to prevent spoofing
- Keep shared secrets secure and rotate them regularly
- Implement rate limiting on your webhook endpoints
Monitoring Webhooks
rrelayer provides internal monitoring of webhook delivery:
- Failed webhooks are logged with error details
- Retry attempts are tracked and logged
- Webhook statistics are available for monitoring
Monitor your webhook endpoints for:
- Response times
- Error rates
- Processing failures
- Queue depth (if applicable)