Webhooks Overview
Webhooks allow your application to receive real-time notifications when events occur in your Matchr account.
Webhooks push data to your server instantly when events occur, eliminating the
need to poll our API.
Available Events
| Event | Description |
|---|
order.created | A new order was submitted |
order.filled | An order was completely filled |
order.partially_filled | An order was partially filled |
order.cancelled | An order was cancelled |
position.opened | A new position was opened |
position.closed | A position was closed |
position.resolved | A position’s market was resolved |
market.matched | A cross-platform market match was found |
price.alert | A price alert was triggered |
deposit.completed | Funds were deposited |
withdrawal.completed | Funds were withdrawn |
Setting Up Webhooks
1. Register Your Endpoint
Navigate to Settings → Webhooks or use the API:
curl -X POST "https://api.matchr.xyz/v1/webhooks" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.com/webhooks/matchr",
"events": ["order.filled", "position.resolved"],
"secret": "your_webhook_secret"
}'
Response
{
"success": true,
"data": {
"id": "whk_abc123",
"url": "https://your-app.com/webhooks/matchr",
"events": ["order.filled", "position.resolved"],
"status": "active",
"created_at": "2025-10-15T10:00:00Z"
}
}
Webhook Payload
All webhooks are sent as POST requests with a JSON body.
| Header | Description |
|---|
Content-Type | application/json |
X-Matchr-Signature | HMAC signature for verification |
X-Matchr-Timestamp | Unix timestamp of the request |
X-Matchr-Event | Event type (e.g., order.filled) |
X-Matchr-Delivery-Id | Unique delivery ID for deduplication |
Payload Structure
{
"id": "evt_delivery_123",
"type": "order.filled",
"timestamp": "2025-10-15T14:30:00Z",
"data": {
// Event-specific data
}
}
Event Payloads
order.filled
{
"id": "evt_delivery_123",
"type": "order.filled",
"timestamp": "2025-10-15T14:30:00Z",
"data": {
"order_id": "ord_abc123",
"market_id": "mkt_yes123",
"platform": "polymarket",
"side": "buy",
"type": "limit",
"amount": 100,
"price": 0.52,
"filled_amount": 100,
"average_fill_price": 0.518,
"fees": 0.52,
"position_id": "pos_xyz789"
}
}
position.resolved
{
"id": "evt_delivery_456",
"type": "position.resolved",
"timestamp": "2025-10-15T16:00:00Z",
"data": {
"position_id": "pos_xyz789",
"market_id": "mkt_yes123",
"event_title": "Will Trump win the 2025 election?",
"outcome": "Yes",
"resolution": "Yes",
"won": true,
"size": 500,
"cost_basis": 260.0,
"payout": 500.0,
"realized_pnl": 240.0,
"redeemable": true
}
}
market.matched
{
"id": "evt_delivery_789",
"type": "market.matched",
"timestamp": "2025-10-15T12:00:00Z",
"data": {
"match_id": "match_abc123",
"confidence": 0.95,
"platforms": {
"polymarket": {
"event_id": "evt_poly123",
"title": "Will BTC hit $100K by end of 2025?",
"yes_price": 0.35
},
"kalshi": {
"event_id": "evt_kalshi456",
"title": "Bitcoin price $100,000 or above on December 31",
"yes_price": 0.38
}
},
"spread": 0.03,
"spread_pct": 8.57
}
}
price.alert
{
"id": "evt_delivery_101",
"type": "price.alert",
"timestamp": "2025-10-15T14:45:00Z",
"data": {
"alert_id": "alert_123",
"market_id": "mkt_yes123",
"event_title": "Will Trump win the 2025 election?",
"condition": "price_above",
"threshold": 0.55,
"current_price": 0.56,
"platform": "polymarket"
}
}
Signature Verification
Always verify webhook signatures to ensure requests are from Matchr.
How Signatures Work
- Matchr creates a signature using your webhook secret
- The signature is included in the
X-Matchr-Signature header
- You recreate the signature and compare
Verification Code
import crypto from 'crypto';
function verifyWebhook(
payload: string,
signature: string,
timestamp: string,
secret: string
): boolean {
const signedPayload = `${timestamp}.${payload}`;
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(signedPayload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(`sha256=${expectedSignature}`)
);
}
// Express middleware
app.post('/webhooks/matchr', (req, res) => {
const signature = req.headers['x-matchr-signature'];
const timestamp = req.headers['x-matchr-timestamp'];
const payload = JSON.stringify(req.body);
if (!verifyWebhook(payload, signature, timestamp, WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
// Process webhook
const event = req.body;
console.log('Received event:', event.type);
res.status(200).send('OK');
});
Retry Policy
If your endpoint fails to respond with a 2xx status code, we’ll retry:
| Attempt | Delay |
|---|
| 1 | Immediate |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 30 minutes |
| 5 | 2 hours |
| 6 | 12 hours |
After 6 failed attempts, the webhook is marked as failed and disabled.
Handling Failures
Always return a 200 OK response quickly, even if processing takes time.
Process webhooks asynchronously.
app.post("/webhooks/matchr", async (req, res) => {
// Verify signature first
if (!verifySignature(req)) {
return res.status(401).send("Invalid");
}
// Respond immediately
res.status(200).send("OK");
// Process asynchronously
processWebhookAsync(req.body);
});
Managing Webhooks
List Webhooks
curl -X GET "https://api.matchr.xyz/v1/webhooks" \
-H "Authorization: Bearer YOUR_API_KEY"
Update Webhook
curl -X PATCH "https://api.matchr.xyz/v1/webhooks/whk_abc123" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"events": ["order.filled", "order.cancelled", "position.resolved"]
}'
Delete Webhook
curl -X DELETE "https://api.matchr.xyz/v1/webhooks/whk_abc123" \
-H "Authorization: Bearer YOUR_API_KEY"
Test Webhook
Send a test event to verify your endpoint:
curl -X POST "https://api.matchr.xyz/v1/webhooks/whk_abc123/test" \
-H "Authorization: Bearer YOUR_API_KEY"
Webhook Logs
View recent webhook deliveries:
curl -X GET "https://api.matchr.xyz/v1/webhooks/whk_abc123/deliveries?limit=20" \
-H "Authorization: Bearer YOUR_API_KEY"
Response
{
"success": true,
"data": [
{
"id": "del_123",
"event_type": "order.filled",
"status": "success",
"response_code": 200,
"response_time_ms": 145,
"timestamp": "2025-10-15T14:30:00Z"
},
{
"id": "del_122",
"event_type": "position.resolved",
"status": "failed",
"response_code": 500,
"error": "Connection timeout",
"retry_count": 2,
"timestamp": "2025-10-15T14:25:00Z"
}
]
}
Best Practices
Respond Quickly
Return 200 within 5 seconds. Process data asynchronously.
Verify Signatures
Always verify the X-Matchr-Signature header.
Handle Duplicates
Use X-Matchr-Delivery-Id for idempotency.
Use HTTPS
Only HTTPS endpoints are supported.