Webhooks
Webhooks let your application receive real-time HTTP POST callbacks when events happen in your MTG Rack account. Instead of polling the API repeatedly to check for changes, you register a URL and MTG Rack pushes event data to you as it happens — cards added, decks updated, binders modified, and more.
Setting Up a Webhook
You can create webhook subscriptions via the Developer Portal UI or programmatically via the API. In either case, you provide three things:
- URL — an HTTPS endpoint on your server that will receive POST requests. The URL must be publicly accessible and respond within 10 seconds. In production, HTTPS is required — HTTP URLs are only accepted for
localhostduring development. - Events — the event types you want to subscribe to. You can subscribe to all events or pick specific ones.
- Secret (optional) — a signing secret used to verify that payloads are genuinely from MTG Rack. If you omit this, a secret is auto-generated for you and displayed once in the portal.

To create a webhook via the API:
curl -X POST https://mtgrack.com/api/v1/webhooks \
-H "Authorization: Bearer mtr_k_your_key" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/webhooks/mtgrack",
"events": ["collection.entry.created", "deck.updated"],
"secret": "whsec_your_secret_here"
}'Available Events
Subscribe to any combination of the following 11 event types:
collection.entry.created— a card was added to the user's collectioncollection.entry.updated— a collection entry was modified (quantity, condition, foil status, binder assignment, etc.)collection.entry.deleted— a card was removed from the collectiondeck.created— a new deck was createddeck.updated— a deck's contents (cards added/removed) or metadata (name, format, visibility) changeddeck.deleted— a deck was deletedbinder.created— a new binder was createdbinder.updated— a binder was renamed, reordered, or had its description modifiedbinder.deleted— a binder was deletedprice.alert.triggered— a price alert threshold was crossed for a card in the collectionexport.completed— a bulk export finished processing and is ready for download
Event Batching
To reduce noise and avoid flooding your endpoint with dozens of requests during bulk operations, MTG Rack batches events that occur within a 5-second window into a single delivery. For example, if a user imports 50 cards in quick succession, you receive one POST containing an array of 50 collection.entry.created events rather than 50 separate HTTP requests. Each event in the batch includes its own id, type, timestamp, and data payload.
HMAC Signature Verification
Every webhook delivery includes an X-Webhook-Signature header containing an HMAC-SHA256 signature of the raw request body, computed using your webhook secret. Always verify this signature before processing the payload to ensure it was genuinely sent by MTG Rack and has not been tampered with in transit.
import crypto from "crypto";
function verifyWebhookSignature(
rawBody: string,
signature: string,
secret: string
): boolean {
const expected = crypto
.createHmac("sha256", secret)
.update(rawBody, "utf8")
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// In your Express/Next.js handler:
export async function POST(req: Request) {
const rawBody = await req.text();
const signature = req.headers.get("x-webhook-signature") ?? "";
if (!verifyWebhookSignature(rawBody, signature, process.env.WEBHOOK_SECRET!)) {
return new Response("Invalid signature", { status: 401 });
}
const events = JSON.parse(rawBody);
for (const event of events) {
// Process each event based on event.type
console.log(event.type, event.data);
}
return new Response("OK", { status: 200 });
}Never Skip Verification
X-Webhook-Signature header before acting on a payload.Retry Schedule
MTG Rack expects your endpoint to return a 2xx status within 10 seconds. If the initial delivery fails (timeout, network error, or non-2xx response), the system retries with exponential backoff across 5 attempts:
- Retry 1 — 30 seconds after the initial failure
- Retry 2 — 5 minutes after retry 1
- Retry 3 — 30 minutes after retry 2
- Retry 4 — 2 hours after retry 3
- Retry 5 — 12 hours after retry 4
After all 5 retries are exhausted, the delivery is marked as permanently failed. Each retry includes the same payload and the same X-Webhook-Signature, so your verification logic works identically on retries.
Auto-Disable on Repeated Failures
If a webhook endpoint fails to respond successfully for 10 consecutive event deliveries (across any event type), the subscription is automatically disabled to prevent wasted resources. You will receive an email notification when this happens. To re-enable, fix the issue with your endpoint, then visit the Developer Portal and click Re-enable on the affected webhook. The portal also shows a delivery log with timestamps, HTTP status codes, and response bodies for the last 30 days so you can diagnose failures.
Daily Delivery Cap
Each webhook subscription has a daily delivery cap of 1,000 deliveries per day, resetting at midnight UTC. A single batched delivery counts as one delivery regardless of how many events it contains. If you exceed the cap, additional events are silently dropped until the next day. For most users this limit is more than sufficient, but if you regularly perform very large bulk operations, consider using the API to poll for changes instead of relying solely on webhooks. See the Rate Limits page for more details on quotas.
Testing Webhooks
The Developer Portal includes a Send Test button on each webhook endpoint. Clicking it sends a synthetic event of each subscribed type to your URL with realistic sample data so you can verify your handler works correctly without making real changes to your account. Test deliveries include an X-Webhook-Test: true header so your handler can distinguish them from real events if needed.
HTTPS Required in Production
localhost or 127.0.0.1, which is useful for local development with tools like ngrok or localtunnel. Before deploying your integration, make sure your endpoint has a valid TLS certificate.