For production-ready sample code, refer to the official SDKs:
Webhook Event Handling
1. Overview: What Are Webhooks?
MartianPay leverages webhooks to proactively notify merchants of payment event changes, enabling real-time updates on transaction status.
- Trigger Conditions: Key events such as payment success, failure, or refunds will trigger a webhook notification.
- Notification Method: HTTP POST requests to your specified endpoint.
2. Webhook Request Format
- HTTP Method:
POST - Request URL Example:
https://yourdomain.com/webhook_endpoint - Headers:
| Header Name | Description | Example |
|---|---|---|
| Content-Type | Always application/json | application/json |
| Martian-Pay-Signature | Signature header for authenticity verification | t=1745580845,v1=c16a830eae640a659025a5f4bf91866d... |
| User-Agent | Always MartianPay/1.0 | MartianPay/1.0 |
3. Signature Verification
Webhook authenticity is enforced using HMAC SHA-256 signatures.
3.1 Signature Calculation (Go Example)
mac := hmac.New(sha256.New, []byte(secret))
mac.Write([]byte(fmt.Sprintf("%d", timestamp)))
mac.Write([]byte("."))
mac.Write(payload)
signature := mac.Sum(nil)
- secret: Your webhook secret key (provided by MartianPay)
- timestamp: The
tfield in theMartian-Pay-Signatureheader - payload: The raw request body (event JSON data)
3.2 Signature Header Example
Martian-Pay-Signature: t=1745580845,v1=c16a830eae640a659025a5f4bf91866ddd4be0c85619a82defad3c10af42ec89
4. Webhook Event Data Structure
A typical webhook event payload:
{
"id": "evt_056qw9fr9PndljykFUqSIf6t",
"object": "event",
"api_version": "2025-01-22",
"created": 1745580845,
"data": {
"object": {...}, // Full resource object (e.g., PaymentIntent)
"previous_attributes": null // Only for *.updated events
},
"livemode": false,
"pending_webhooks": 0,
"type": "payment_intent.succeeded"
}
Field Reference
| Field Name | Type | Description |
|---|---|---|
| id | string | Unique event identifier |
| object | string | Always event |
| api_version | string | API version |
| created | int64 | Event creation timestamp (Unix seconds) |
| data | EventData | Event data payload |
| data.object | object | Full resource data (e.g., PaymentIntent, Refund) |
| data.previous_attributes | object | Previous data before update (for *.updated) |
| livemode | bool | true for production, false for test |
| pending_webhooks | int64 | Number of undelivered webhooks |
| type | string | Event type (see below) |
5. Supported Event Types
5.1 Payment Intent Events
| Event Type | Description |
|---|---|
| payment_intent.created | New payment intent is created |
| payment_intent.succeeded | Payment intent has been fully paid and completed successfully |
| payment_intent.payment_failed | Payment attempt for a payment intent fails |
| payment_intent.processing | Payment intent is being processed (e.g., waiting for blockchain confirmation) |
| payment_intent.partially_paid | Payment intent has received partial payment but is not yet fully paid |
| payment_intent.canceled | Payment intent is canceled |
5.2 Refund Events
| Event Type | Description |
|---|---|
| refund.created | New refund is created |
| refund.succeeded | Refund has been successfully processed and funds returned to customer |
| refund.updated | Refund's details are updated |
| refund.failed | Refund attempt fails |
5.3 Payout Events
| Event Type | Description |
|---|---|
| payout.created | New payout is created |
| payout.succeeded | Payout has been successfully transferred to the recipient |
| payout.updated | Payout's details are updated |
| payout.failed | Payout attempt fails |
5.4 Payroll Events
| Event Type | Description |
|---|---|
| payroll.created | New payroll batch is created |
| payroll.approved | Payroll batch has been approved for execution |
| payroll.rejected | Payroll batch approval is rejected |
| payroll.canceled | Payroll batch is canceled |
| payroll.executing | Payroll batch execution has started |
| payroll.completed | All items in a payroll batch have been processed successfully |
| payroll.failed | Payroll batch execution fails |
5.5 Payroll Item Events
| Event Type | Description |
|---|---|
| payroll_item.processing | Individual payroll item is being processed |
| payroll_item.succeeded | Individual payroll item has been successfully paid |
| payroll_item.failed | Individual payroll item payment fails |
| payroll_item.address_verification_sent | Address verification email has been sent to the recipient |
| payroll_item.address_verified | Recipient has verified their wallet address |
5.6 Subscription Events
| Event Type | Description |
|---|---|
| subscription.created | New subscription is created |
| subscription.updated | Subscription's details are updated (e.g., plan, quantity, billing cycle) |
| subscription.deleted | Subscription is deleted or permanently canceled |
| subscription.paused | Subscription is temporarily paused |
| subscription.resumed | Paused subscription is resumed |
| subscription.trial_will_end | Subscription's trial period is about to end (typically 3 days before) |
5.7 Invoice Events
| Event Type | Description |
|---|---|
| invoice.created | New invoice is created (draft state) |
| invoice.finalized | Invoice is finalized and ready for payment |
| invoice.paid | Invoice has been fully paid |
| invoice.payment_succeeded | Payment attempt for an invoice succeeds |
| invoice.payment_failed | Payment attempt for an invoice fails |
| invoice.payment_action_required | Invoice payment requires additional action from the customer |
| invoice.upcoming | Upcoming invoice will be generated soon (for subscriptions) |
| invoice.updated | Invoice's details are updated |
| invoice.voided | Invoice is voided and can no longer be paid |
6. Complete Event Examples
6.1 Payment Intent Event Example
payment_intent.succeeded event:
{
"id": "evt_q9URpE8tUiss94d7gEbmOVu9",
"object": "event",
"api_version": "2025-01-22",
"created": 1768808932,
"data": {
"previous_attributes": null,
"object": {
"id": "pi_qdtSBE2FL4dB0WCHHIW9SQk9",
"object": "payment_intent",
"amount": {
"asset_id": "USD",
"amount": "399"
},
"payment_details": {
"amount_captured": {"asset_id": "USD", "amount": "399"},
"amount_refunded": {"asset_id": "USD", "amount": "0"},
"tx_fee": {"asset_id": "USD", "amount": "0"},
"tax_fee": {"asset_id": "USD", "amount": "0"},
"frozen_amount": {"asset_id": "USD", "amount": "0"},
"net_amount": {"asset_id": "USD", "amount": "0"},
"gas_fee": {},
"network_fee": {"asset_id": "USD", "amount": "0"}
},
"canceled_at": 0,
"cancellation_reason": "",
"client_secret": "pi_qdtSBE2FL4dB0WCHHIW9SQk9_secret_xxx",
"created": 1768808930,
"updated": 1768808931,
"currency": "USD",
"customer": {
"id": "cus_pgDypQUDGe64EDI21rYEMRR0",
"object": "customer",
"total_expense": 0,
"total_payment": 0,
"total_refund": 0,
"currency": "USD",
"created": 1761816999,
"name": "",
"email": "customer@example.com",
"description": "",
"phone": ""
},
"description": "Subscription payment for invoice",
"livemode": false,
"metadata": {
"auto_confirm": "true",
"billing_reason": "subscription_cycle",
"invoice_id": "in_zVruEzygoq3CgvSgYRUE5Op3",
"subscription_id": "sub_VUjMu3pP2jQbayU6PXM8CQX6"
},
"payment_link_details": null,
"merchant_order_id": "inv_in_xxx",
"charges": [
{
"id": "ch_d8d4gFIzAXcrnUMUH09yaYJ5",
"object": "charge",
"amount": {"asset_id": "USD-STRIPE", "amount": "399"},
"payment_details": {
"amount_captured": {"asset_id": "USD-STRIPE", "amount": "399"},
"amount_refunded": {"asset_id": "USD-STRIPE", "amount": "0"},
"tx_fee": {"asset_id": "USD-STRIPE", "amount": "0"},
"tax_fee": {"asset_id": "USD-STRIPE", "amount": "0"},
"frozen_amount": {"asset_id": "USD-STRIPE", "amount": "0"},
"net_amount": {"asset_id": "USD-STRIPE", "amount": "0"},
"gas_fee": {},
"network_fee": {"asset_id": "USD-STRIPE", "amount": "0"}
},
"exchange_rate": "1.0",
"captured": false,
"created": 0,
"payment_intent": "pi_qdtSBE2FL4dB0WCHHIW9SQk9",
"payment_method_type": "cards",
"payment_method_options": {"crypto": null, "fiat": null},
"transactions": [],
"refunds": [],
"stripe_payload": {
"client_secret": "pi_xxx_secret_xxx",
"public_key": "pk_test_xxx",
"status": "Success",
"customer_id": "cus_TKXMIdQoIegNp5"
},
"payment_provider": "stripe"
}
],
"receipt_email": "customer@example.com",
"return_url": "",
"status": "Success",
"payment_intent_status": "Confirmed",
"complete_on_first_payment": false,
"permanent_deposit": false,
"expired_at": 1768809830,
"unfreeze_withdraws": [],
"invoice": "in_zVruEzygoq3CgvSgYRUE5Op3",
"subscription": "sub_VUjMu3pP2jQbayU6PXM8CQX6"
}
},
"livemode": false,
"pending_webhooks": 0,
"type": "payment_intent.succeeded"
}
6.2 Refund Event Example
refund.succeeded event:
{
"id": "evt_syp6mjiytrGC9E7vLKqiKpK1",
"object": "event",
"api_version": "2025-01-22",
"created": 1768615924,
"data": {
"previous_attributes": null,
"object": {
"id": "rf_0QNyCuiLN6tUsoIEcMkLQ98M",
"object": "refund",
"amount": {"asset_id": "CNY-WECHAT", "amount": "6.99"},
"network_fee": {"asset_id": "CNY-WECHAT", "amount": "0"},
"net_amount": {"asset_id": "CNY-WECHAT", "amount": "6.99"},
"created": 1768615474,
"description": "",
"transactions": [],
"failure_reason": "",
"metadata": null,
"charge": "ch_Sq6LbNYCI7x5KhpE8FJHcsRk",
"payment_intent": "pi_YPJaDrlWqySYWbpNwvVujbhn",
"refund_address": "decided by provider",
"reason": "customer requested",
"status": "Success",
"exchange_rate": "0.14317688"
}
},
"livemode": false,
"pending_webhooks": 0,
"type": "refund.succeeded"
}
6.3 Payout Event Example
payout.succeeded event:
{
"id": "evt_2j3e4IyNFG3FkrJbnquMZegz",
"object": "event",
"api_version": "2025-01-22",
"created": 1768327851,
"data": {
"previous_attributes": null,
"object": {
"id": "payout_gMNCmvjEY7WCe9VCmZYqVw0C",
"object": "payout",
"livemode": false,
"arrival_date": 0,
"automatic": false,
"transactions": [
{
"tx_id": "e9e5d451-b658-4ab7-ae3c-1151d3ab289c",
"source_address": "0x89Dbc88f04dc48572a2C7AfD609cdA144fc794D8",
"destination_address": "0x36279Ac046498bF0cb742622cCe22F3cE3c2AfD9",
"tx_hash": "0x03598d72b2b2d0913d7bafd283f6cda111e3392b13f3d8fb25602712f7c143c3",
"amount": "90000",
"decimals": 6,
"asset_id": "USDC-Ethereum-TEST",
"token": "USDC",
"network": "Ethereum Sepolia",
"type": "refund",
"created_at": 1768327817,
"status": "confirmed",
"aml_status": "approved",
"charge_id": "",
"refund_id": "wd_eeGt8qgrPBEVIMTNxGuwgZT0",
"fee_info": "network_fee:\"0.000093147072981046\"",
"fee_currency": "ETH-Ethereum-TEST"
}
],
"created": 1768326555,
"updated": 1768327159,
"merchant_id": "accu_M7PTgveSgMtTtPHbjFgEtAlD",
"source_amount": "0.1",
"source_coin": "USDC",
"exchange_rate": "1",
"receive_coin": "USDC",
"receive_asset_id": "USDC-Ethereum-TEST",
"receive_account_type": "wallet",
"receive_bank_account": null,
"receive_wallet_address": {
"id": "ma_HDbjWWxLdS764gK37jbMpvsF",
"merchant_id": "accu_M7PTgveSgMtTtPHbjFgEtAlD",
"network": "Ethereum Sepolia",
"address": "0x36279Ac046498bF0cb742622cCe22F3cE3c2AfD9"
},
"receive_amount": "0.09",
"receive_amount_min": "0.09",
"payment_network_fee": "0.01",
"payment_service_fee": "0",
"payment_total_fee": "0.01",
"payment_net_amount": "0.09",
"status": "paid",
"approval_status": null,
"internal_note": "",
"statement_descriptor": "",
"external_id": "",
"failure_message": "",
"aml_status": "approved",
"metadata": null
}
},
"livemode": false,
"pending_webhooks": 0,
"type": "payout.succeeded"
}
6.4 Subscription Event Example
subscription.created event:
{
"id": "evt_u1N7ITc2Z82GH8mK67bb1MXS",
"object": "event",
"api_version": "2025-01-22",
"created": 1768322030,
"data": {
"previous_attributes": null,
"object": {
"id": "sub_BieOI2aDKI8YyZgRSHuMm6y6",
"merchant_id": "accu_M7PTgveSgMtTtPHbjFgEtAlD",
"customer_id": "cus_7Xpxk2n22WAEBDaBVlG5dnRf",
"selling_plan_id": "sp_uW3FnJfV5XQrvyNcIz",
"product_id": "prod_nWk5kgCeMj1zGP",
"variant_id": "var_G7i3rzmsCFBAnGSYrX",
"status": "incomplete",
"collection_method": "send_invoice",
"billing_cycle_anchor": 1768322030,
"current_period_start": 1768322030,
"current_period_end": 1768322630,
"trial_start": 1768322030,
"trial_end": 1768322030,
"cancel_at_period_end": false,
"metadata": {
"product_snapshot": {
"id": "prod_nWk5kgCeMj1zGP",
"name": "Example Product",
"description": "Product description",
"price": "100",
"currency": "USD"
},
"selling_plan_snapshot": {
"id": "sp_uW3FnJfV5XQrvyNcIz",
"name": "Monthly Plan",
"billing_policy": {
"interval": "month",
"interval_count": "1",
"min_cycles": "3"
}
},
"variant_snapshot": {
"id": "var_G7i3rzmsCFBAnGSYrX",
"price": "100",
"currency": "USD",
"option_values": {"Color": "White", "Size": "S"}
}
},
"created_at": 1768322030,
"updated_at": 1768322030
}
},
"livemode": false,
"pending_webhooks": 0,
"type": "subscription.created"
}
6.5 Invoice Event Example
invoice.paid event:
{
"id": "evt_15bqsIvT0sjaQ39N6HCAvQld",
"object": "event",
"api_version": "2025-01-22",
"created": 1768809532,
"data": {
"previous_attributes": null,
"object": {
"id": "in_DLh2bVnufD7Jqu1qtxXPyuic",
"merchant_id": "accu_M7PTgveSgMtTtPHbjFgEtAlD",
"subscription_id": "sub_VUjMu3pP2jQbayU6PXM8CQX6",
"payment_intent_id": "pi_XLdPhPJ574vFkmY7HpxXF697",
"customer_id": "cus_pgDypQUDGe64EDI21rYEMRR0",
"amount": "39900",
"currency": "USD",
"status": "paid",
"billing_reason": "subscription_cycle",
"attempt_count": 0,
"due_date": 1768809490,
"paid_at": 1768809532,
"lines": [
{
"description": "Subscription payment",
"product_id": "prod_kAter0gUH6JPd1",
"variant_id": "var_tD4KoBAbj1C9Pv4geL",
"quantity": 1,
"unit_amount": "39900",
"amount": "39900",
"currency": "USD",
"metadata": {
"base_price": "39900",
"billing_cycle": "month",
"cycle_number": 2143,
"selling_plan_id": "sp_HaJJN9UQNKo3ndKIPI",
"selling_plan_name": "Monthly Plan"
}
}
],
"metadata": {
"current_period_end": 1768810090,
"current_period_start": 1768809490,
"cycle_number": 2143,
"selling_plan_id": "sp_HaJJN9UQNKo3ndKIPI",
"subscription_id": "sub_VUjMu3pP2jQbayU6PXM8CQX6"
},
"external_id": "sub_VUjMu3pP2jQbayU6PXM8CQX6_xxx",
"created_at": 1768809530,
"updated_at": 1768809532,
"version": 4
}
},
"livemode": false,
"pending_webhooks": 0,
"type": "invoice.paid"
}
6.6 Payroll Event Example
payroll.completed event:
{
"id": "evt_AbffXbMclPMq36UPcljqJH7a",
"object": "event",
"api_version": "2025-01-22",
"created": 1768318454,
"data": {
"previous_attributes": null,
"object": {
"id": "payroll_vgnHtE0QqZsATtrydvnZ44Cn",
"created_at": 1768317233,
"updated_at": 1768318454,
"canceled_at": 0,
"merchant_id": "accu_M7PTgveSgMtTtPHbjFgEtAlD",
"external_id": "",
"approval_status": "approved",
"status": "paid",
"total_item_num": 1,
"total_amount": "0.01",
"total_service_fee": "0",
"currency": "USD"
}
},
"livemode": false,
"pending_webhooks": 0,
"type": "payroll.completed"
}
7. Reference Implementation
For production-ready sample code, refer to the official SDKs: