Webhooks Guide
Webhooks let your application receive real-time notifications when events occur in your mCards integration — transaction authorizations, card status changes, settlement completions, and more.
How Webhooks Work
- You register a URL endpoint with mCards
- When an event occurs, mCards sends an HTTP POST to your URL
- Your endpoint processes the event and returns a 2xx status code
- If delivery fails, mCards retries with exponential backoff
Registering a Webhook
typescript
import { McardsSdk } from '@mcards/sdk';
const client = new McardsSdk({
apiKey: process.env.MCARDS_API_KEY,
apiSecret: process.env.MCARDS_API_SECRET,
});
const { data: webhook } = await client.webhooks.create({
url: 'https://your-app.com/webhooks/mcards',
events: [
'transaction.authorized',
'transaction.settled',
'transaction.refunded',
'card.activated',
'card.deactivated',
],
});
console.log(webhook.uuid);
console.log(webhook.signing_secret); // Save this!Event Types
Transaction Events
| Event | Trigger |
|---|---|
transaction.authorized | A transaction is authorized |
transaction.settled | A transaction is settled |
transaction.refunded | A transaction is refunded |
transaction.declined | A transaction is declined |
transaction.reversed | An authorization is reversed |
Card Events
| Event | Trigger |
|---|---|
card.created | A new card is issued |
card.activated | A card is activated |
card.deactivated | A card is deactivated |
card.suspended | A card is suspended |
Cardholder Events
| Event | Trigger |
|---|---|
cardholder.created | A new cardholder is created |
cardholder.updated | Cardholder details are updated |
cardholder.kyc_completed | KYC verification is completed |
Webhook Payload
json
{
"id": "evt_abc123",
"type": "transaction.authorized",
"created_at": "2026-03-12T10:30:00Z",
"data": {
"transaction_id": "txn_xyz789",
"amount": 42.50,
"currency": "USD",
"merchant_name": "Coffee Shop",
"card_last4": "4242",
"status": "authorized"
}
}Headers
| Header | Description |
|---|---|
Content-Type | application/json |
X-Mcards-Signature | HMAC-SHA256 signature of the payload |
X-Mcards-Event | Event type |
X-Mcards-Delivery | Unique delivery ID |
X-Mcards-Timestamp | Unix timestamp of the event |
Verifying Webhook Signatures
Always verify the X-Mcards-Signature header to ensure the webhook is from mCards.
Node.js
javascript
const crypto = require('crypto');
function verifyWebhook(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
app.post('/webhooks/mcards', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-mcards-signature'];
const isValid = verifyWebhook(req.body, signature, WEBHOOK_SECRET);
if (!isValid) {
return res.status(401).json({ error: 'Invalid signature' });
}
const event = JSON.parse(req.body);
switch (event.type) {
case 'transaction.authorized':
handleAuthorization(event.data);
break;
case 'transaction.settled':
handleSettlement(event.data);
break;
}
res.status(200).json({ received: true });
});Python (Flask)
python
import hmac
import hashlib
from flask import Flask, request, jsonify
def verify_webhook(payload, signature, secret):
expected = hmac.new(
secret.encode(),
payload,
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(signature, expected)
@app.route("/webhooks/mcards", methods=["POST"])
def handle_webhook():
signature = request.headers.get("X-Mcards-Signature", "")
if not verify_webhook(request.data, signature, WEBHOOK_SECRET):
return jsonify({"error": "Invalid signature"}), 401
event = request.json
if event["type"] == "transaction.authorized":
handle_authorization(event["data"])
return jsonify({"received": True}), 200Retry Policy
| 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.
Best Practices
- Return 200 quickly — process events asynchronously
- Handle duplicates — use
X-Mcards-Deliveryas an idempotency key - Verify signatures — always validate
X-Mcards-Signature - Use HTTPS — webhook URLs must use HTTPS in production
- Monitor delivery logs — check for failed deliveries regularly
- Test in sandbox first — verify your handler before going live