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

  1. You register a URL endpoint with mCards
  2. When an event occurs, mCards sends an HTTP POST to your URL
  3. Your endpoint processes the event and returns a 2xx status code
  4. 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

EventTrigger
transaction.authorizedA transaction is authorized
transaction.settledA transaction is settled
transaction.refundedA transaction is refunded
transaction.declinedA transaction is declined
transaction.reversedAn authorization is reversed

Card Events

EventTrigger
card.createdA new card is issued
card.activatedA card is activated
card.deactivatedA card is deactivated
card.suspendedA card is suspended

Cardholder Events

EventTrigger
cardholder.createdA new cardholder is created
cardholder.updatedCardholder details are updated
cardholder.kyc_completedKYC 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

HeaderDescription
Content-Typeapplication/json
X-Mcards-SignatureHMAC-SHA256 signature of the payload
X-Mcards-EventEvent type
X-Mcards-DeliveryUnique delivery ID
X-Mcards-TimestampUnix 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}), 200

Retry Policy

AttemptDelay
1Immediate
21 minute
35 minutes
430 minutes
52 hours
612 hours

After 6 failed attempts, the webhook is marked as failed.

Best Practices

  1. Return 200 quickly — process events asynchronously
  2. Handle duplicates — use X-Mcards-Delivery as an idempotency key
  3. Verify signatures — always validate X-Mcards-Signature
  4. Use HTTPS — webhook URLs must use HTTPS in production
  5. Monitor delivery logs — check for failed deliveries regularly
  6. Test in sandbox first — verify your handler before going live