Independent and educational: this site does not process payments, hold funds or offer wallets.Independent and educational. No payment processing, no custody.How we work
    SIMULATIONRuns only in your browser. Testnet or simulated data. No real funds, no custody, never enter private keys or recovery phrases.
    Sandbox · events + HMAC

    Webhook payload explorer

    Payment providers tell your system what happened through webhooks. Explore an illustrative event schema (our teaching example, not any provider’s API), then sign and verify payloads locally with HMAC-SHA256.

    Free · runs in your browserAssumptions reviewed October 30, 2026Methodology

    Mitey the yeti with a testnet flag

    Event

    Signing

    payment.confirmed

    Your confirmation or finality threshold was reached.

    When: After N confirmations / finality. Your handler should: Mark the invoice paid, record the CAD value and rate source, then fulfil.

    Headers

    # HTTP POST to your endpoint Content-Type: application/json X-Sandbox-Signature: … X-Sandbox-Event: payment.confirmed

    Body

    { "id": "evt_sim_7Q2K9X_03", "type": "payment.confirmed", "created_at": "2026-11-02T15:00:45.000Z", "livemode": false, "simulation": true, "idempotency_key": "pr_sim_7Q2K9X:payment.confirmed:3", "data": { "payment_request": { "id": "pr_sim_7Q2K9X", "invoice_id": "INV-2026-0142", "network": "ethereum-sepolia", "asset": "TEST-USD", "amount_requested": "250.00", "confirmations_required": 3 }, "payment": { "tx_hash": "0x68b2776653f6aada41f321dbde672ee1aec56b56c507dbde6f6e064361f0c265", "amount_received": "250.00", "confirmations": 3, "cad_value": "342.50", "rate_source": "sandbox-fixed-rate" } } }
    Verification: …

    Computing… Signature = HMAC-SHA256(secret, "<t>.<raw body>"), compared in constant time, with a five-minute replay window.

    Verify in Node.js

    import crypto from 'node:crypto'; // rawBody: the exact bytes received (do not re-serialise JSON before verifying) export function verify(rawBody, header, secret, toleranceSec = 300) { const parts = Object.fromEntries(header.split(',').map((kv) => kv.split('='))); const t = Number(parts.t); if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false; // replay guard const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex'); const a = Buffer.from(expected, 'hex'), b = Buffer.from(parts.v1 ?? '', 'hex'); return a.length === b.length && crypto.timingSafeEqual(a, b); }

    Verify in Python

    import hmac, hashlib, time def verify(raw_body: bytes, header: str, secret: str, tolerance: int = 300) -> bool: parts = dict(kv.split("=", 1) for kv in header.split(",")) t = int(parts.get("t", "0")) if abs(time.time() - t) > tolerance: # replay guard return False signed = f"{t}.".encode() + raw_body expected = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest() return hmac.compare_digest(expected, parts.get("v1", ""))

    Event reference

    EventMeaningHandle by
    payment_request.createdA payment request (invoice) now exists with an amount, asset, network and expiry.Store the request id against your order or invoice. Do not ship anything yet.
    payment.detectedA matching transaction was seen in the network but has 0 confirmations.Show "payment seen, confirming". Never treat as paid: it can still be replaced or dropped.
    payment.confirmingThe transaction is in a block; confirmations are increasing.Update progress. Make the handler idempotent; you may get several.
    payment.confirmedYour confirmation or finality threshold was reached.Mark the invoice paid, record the CAD value and rate source, then fulfil.
    payment.underpaidLess than the requested amount arrived before expiry.Follow your written underpayment policy: request the balance or refund.
    payment.overpaidMore than the requested amount arrived.Hold the excess as a liability until refunded under your policy.
    payment_request.expiredNo (or not enough) payment arrived before the quote expired.Release reserved stock; late payments need manual review.
    refund.sentYou (or your provider) broadcast a refund transaction.Link the refund hash to the original payment for your records.
    conversion.settledConverted CAD reached the bank account (provider or exchange off-ramp).Reconcile deposit amount against invoice, fees and FX.
    Rules that prevent most webhook bugs

    Verify the signature on the raw body; reject old timestamps; store the idempotency key and ignore repeats; never fulfil on payment.detected; tolerate events arriving out of order by checking state before acting. More in webhooks and payment events.

    How to use it

    1. Pick an event type and edit the sample payment.
    2. Inspect the JSON payload and the idempotency key.
    3. Sign it with a test secret and try tampering to see verification fail.
    Assumptions, not quotes

    Default values are illustrative planning inputs reviewed October 30, 2026, not market data or any provider’s pricing. Replace them with your own statements. This tool is educational and is not financial, legal or tax advice.

    Want a second look at your numbers?

    Describe your scenario and MITEY will review it with you by email. Free and educational; we do not sell or process payments.

    Request a scenario review