Skip to content

Testing Webhooks

Option 1 — Test via Client Portal

Go to Client Portal → Dashboard → Webhooks and click "Send Test Webhook".

TokenCashFlow sends a synthetic payment.completed-shaped payload to your configured URL and shows you:

  • Whether delivery succeeded (HTTP status code from your server)
  • The payload that was sent

The test delivery is signed with your configured secret. Use this to verify your signature verification code end-to-end.

Option 2 — Test via API

bash
curl -X POST https://api.tokencashflow.com/v1/webhooks/test \
  -H "X-API-Key: tcf_live_..."

Response:

json
{
  "success": true,
  "data": {
    "delivered": true,
    "status_code": 200,
    "response_body": "",
    "payload_sent": {
      "event": "payment.completed",
      "timestamp": "2026-05-16T12:00:00Z",
      "data": {
        "payment_id": "test-00000000-0000-0000-0000-000000000000",
        "status": "COMPLETED",
        "amount_usd": 100.00,
        "received_crypto": "0.05",
        "crypto_symbol": "ETH",
        "chain": "ethereum",
        "locked_rate_usd": 2000.00,
        "fees": { "service_fee_usd": 0.5, "conversion_fee_usd": 1.0 },
        "net_amount_usd": 98.50
      }
    }
  }
}

Option 3 — Local development with a tunnel

During development your webhook handler runs on localhost, which is not reachable by TokenCashFlow's servers. Use a tunnelling tool to expose a local port publicly.

Using ngrok

bash
# Install ngrok: https://ngrok.com/download
ngrok http 5000
# Output: https://a1b2c3d4.ngrok.io → http://localhost:5000

# Configure that URL in the Client Portal:
# https://a1b2c3d4.ngrok.io/webhook

Using Cloudflare Tunnel (free, no account needed for quick tests)

bash
# macOS/Linux
brew install cloudflared   # or download from https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/

cloudflared tunnel --url http://localhost:5000
# Output: https://random-name.trycloudflare.com

# Configure that URL in the Client Portal

Minimal test server

Start a local server to log incoming webhooks during development:

python
# test_webhook_server.py
import hmac, hashlib, json
from flask import Flask, request

app = Flask(__name__)
SECRET = "your_webhook_secret_here"

@app.route("/webhook", methods=["POST"])
def webhook():
    body = request.get_data()
    sig = request.headers.get("X-TCF-Signature", "")
    expected = "sha256=" + hmac.new(SECRET.encode(), body, hashlib.sha256).hexdigest()

    if not hmac.compare_digest(expected, sig):
        print("⚠️  Signature mismatch!")
        return "Bad signature", 400

    payload = json.loads(body)
    print(f"✅ [{payload['event']}] payment_id={payload['data'].get('payment_id')}")
    print(json.dumps(payload, indent=2))
    return "", 200

if __name__ == "__main__":
    app.run(port=5000)

Run with:

bash
pip install flask
python test_webhook_server.py

Verifying signature in test deliveries

Both the portal test button and the API POST /v1/webhooks/test sign the payload with your configured secret. Your signature verification code should handle test deliveries identically to real ones — there is no separate test mode for signatures.

TokenCashFlow Documentation