Webhooks
Receive real-time notifications when payment events occur. Webhooks allow your application to react instantly to completed payments without polling.
Overview
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Customer │ │ MakaPay │ │ Your Server │
│ │ │ │ │ │
│ Sends payment │ ──────→ │ Processes │ │ │
│ │ │ payment │ │ │
│ │ │ ↓ │ │ │
│ │ │ Sends webhook │ ──────→ │ Receives POST │
│ │ │ │ │ request │
│ │ │ │ │ ↓ │
│ │ │ │ │ Fulfills order │
└─────────────────┘ └─────────────────┘ └─────────────────┘Setup
Prerequisites
An active API key (required for webhook authentication)
An HTTPS endpoint on your server
Configure Webhook URL
Go to Dashboard → Webhooks
Enter your webhook URL (must be HTTPS)
Toggle Active to enable
Click Save
Generate API Key
If you don't have an API key:
Go to Dashboard → API Keys
Click Create New Key
Save the key securely
Webhook Events
payment.completed
payment.completedSent when a payment is successfully settled to your wallet.
payment.withdrawn
payment.withdrawnSent when a partial payment is manually withdrawn.
payment.awaiting_gas
payment.awaiting_gasSent when payment is received but Gas Tank balance is insufficient. Informational only - no retry on this event.
Webhook Security
Signature Verification
Every webhook includes a signature header for verification:
Verifying the Signature
Python Example
Retry Policy
Failed webhook deliveries are automatically retried:
1st
Immediate
2nd
5 minutes
3rd
10 minutes
What Counts as Failure
HTTP status code outside 200-299
Connection timeout (30 seconds)
SSL/TLS errors
DNS resolution failure
After All Retries Fail
Webhook is marked as failed
No further automatic retries
You can manually retry from the dashboard
Best Practices
1. Respond Quickly
Return a 200 response as fast as possible. Do heavy processing asynchronously.
2. Implement Idempotency
Webhooks may be delivered more than once. Use paymentId to prevent duplicate processing.
3. Verify Signatures
Always verify the X-Signature header before processing.
4. Use HTTPS
Webhook URLs must use HTTPS. HTTP endpoints are rejected.
5. Handle All Event Types
Your endpoint should gracefully handle unknown event types:
Testing Webhooks
Manual Trigger
Go to Dashboard → Payments
Click on a completed payment
Click Resend Webhook
Check your webhook logs
Webhook Logs
View delivery history in Dashboard → Webhooks → Logs:
Payment ID
Associated payment
Status
success / failed / pending
Status Code
HTTP response code
Attempts
Delivery attempts made
Response
Server response (truncated)
Local Testing
Use a tunnel service like ngrok for local development:
Payload Reference
Common Fields
event
string
Event type
paymentId
string
Unique payment identifier
orderId
string
Your order reference
merchant
string
Merchant wallet address
recipientAddress
string
Payment address
amount
string
Payment amount
token
string
Token contract address
chainId
number
Blockchain network ID
status
string
Payment status
timestamp
number
Unix timestamp (ms)
Optional Fields
description
string
If provided at creation
transactionHash
string
On completed payments
withdrawalTransactionHash
string
On withdrawals
amountWithdrawn
string
On partial withdrawals
overpayment
string
If customer overpaid
feeDetails
object
On completed payments
blockConfirmations
number
If confirmations required
Troubleshooting
Webhook Not Received
Check webhook is Active in dashboard
Verify URL is correct and uses HTTPS
Check your server logs for incoming requests
Review webhook logs for delivery status
Signature Mismatch
Ensure you're using the correct API key
Verify you're hashing the raw JSON payload
Check for encoding issues (UTF-8)
Timeouts
Respond with 200 before processing
Move heavy operations to background jobs
Increase server timeout if needed
Duplicate Events
Implement idempotency using
paymentIdCheck webhook logs for retry attempts
Review your response codes (non-2xx triggers retry)
Last updated