Webhooks notify your application when events happen in your account. When an event occurs, we send an HTTP POST request to each configured endpoint with a JSON payload describing the event.
Payload Structure
Every webhook event follows this structure:
{
"id" : "evt_1abc2def3ghi" ,
"object" : "event" ,
"type" : "payment_intent.succeeded" ,
"created" : 1709942400 ,
"livemode" : false ,
"data" : {
"object" : { }
}
}
Verifying Webhook Signatures
Every webhook request includes an X-Signature header that you should use to verify the payload originated from our servers.
The header format is:
X-Signature: t=<timestamp>,v1=<signature>
The signature is computed as:
HMAC-SHA256(webhook_secret, "v1=" + timestamp + "." + payload)
Where:
webhook_secret is the signing secret from your webhook endpoint configuration.
timestamp is the Unix timestamp from the t= portion of the header.
payload is the raw JSON request body.
Verification Example
import hmac
import hashlib
def verify_signature ( payload : bytes , header : str , secret : str ) -> bool :
parts = dict (item.split( "=" , 1 ) for item in header.split( "," ))
timestamp = parts[ "t" ]
expected_sig = parts[ "v1" ]
signed_payload = f "v1= { timestamp } . { payload.decode( 'utf-8' ) } "
computed_sig = hmac.new(
secret.encode( "utf-8" ),
signed_payload.encode( "utf-8" ),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(computed_sig, expected_sig)
Always verify webhook signatures before processing the event. Reject any request where the signature does not match.
Payment Intent Events
payment_intent.created
Occurs when a new PaymentIntent is created.
{
"id" : "evt_1abc2def3ghi" ,
"object" : "event" ,
"type" : "payment_intent.created" ,
"created" : 1709942400 ,
"livemode" : false ,
"data" : {
"object" : {
"id" : "pi_3abc4def5ghi" ,
"object" : "payment_intent" ,
"amount" : 2000 ,
"currency" : "usd" ,
"status" : "requires_payment_method" ,
"customer" : "cus_9abc0def1ghi" ,
"description" : "Order #1234" ,
"metadata" : {},
"created" : 1709942400 ,
"livemode" : false
}
}
}
payment_intent.succeeded
Occurs when a PaymentIntent completes successfully and the payment is confirmed.
{
"id" : "evt_2bcd3efg4hij" ,
"object" : "event" ,
"type" : "payment_intent.succeeded" ,
"created" : 1709942460 ,
"livemode" : false ,
"data" : {
"object" : {
"id" : "pi_3abc4def5ghi" ,
"object" : "payment_intent" ,
"amount" : 2000 ,
"currency" : "usd" ,
"status" : "succeeded" ,
"customer" : "cus_9abc0def1ghi" ,
"payment_method" : "pm_card_visa" ,
"description" : "Order #1234" ,
"metadata" : {},
"created" : 1709942400 ,
"livemode" : false
}
}
}
payment_intent.payment_failed
Occurs when a payment attempt on a PaymentIntent fails.
{
"id" : "evt_3cde4fgh5ijk" ,
"object" : "event" ,
"type" : "payment_intent.payment_failed" ,
"created" : 1709942520 ,
"livemode" : false ,
"data" : {
"object" : {
"id" : "pi_3abc4def5ghi" ,
"object" : "payment_intent" ,
"amount" : 2000 ,
"currency" : "usd" ,
"status" : "requires_payment_method" ,
"customer" : "cus_9abc0def1ghi" ,
"last_payment_error" : {
"type" : "payment_error" ,
"code" : "card_declined" ,
"message" : "Your card was declined."
},
"metadata" : {},
"created" : 1709942400 ,
"livemode" : false
}
}
}
payment_intent.canceled
Occurs when a PaymentIntent is canceled.
{
"id" : "evt_4def5ghi6jkl" ,
"object" : "event" ,
"type" : "payment_intent.canceled" ,
"created" : 1709942580 ,
"livemode" : false ,
"data" : {
"object" : {
"id" : "pi_3abc4def5ghi" ,
"object" : "payment_intent" ,
"amount" : 2000 ,
"currency" : "usd" ,
"status" : "canceled" ,
"cancellation_reason" : "requested_by_customer" ,
"customer" : "cus_9abc0def1ghi" ,
"metadata" : {},
"created" : 1709942400 ,
"livemode" : false
}
}
}
payment_intent.requires_action
Occurs when a PaymentIntent requires additional action such as 3D Secure authentication.
{
"id" : "evt_5efg6hij7klm" ,
"object" : "event" ,
"type" : "payment_intent.requires_action" ,
"created" : 1709942640 ,
"livemode" : false ,
"data" : {
"object" : {
"id" : "pi_3abc4def5ghi" ,
"object" : "payment_intent" ,
"amount" : 2000 ,
"currency" : "usd" ,
"status" : "requires_action" ,
"customer" : "cus_9abc0def1ghi" ,
"next_action" : {
"type" : "redirect_to_url" ,
"redirect_to_url" : {
"url" : "https://hooks.example.com/3ds/authenticate?pi=pi_3abc4def5ghi" ,
"return_url" : "https://shop.example.com/order/complete"
}
},
"metadata" : {},
"created" : 1709942400 ,
"livemode" : false
}
}
}
Charge Events
charge.succeeded
Occurs when a charge succeeds.
{
"id" : "evt_6fgh7ijk8lmn" ,
"object" : "event" ,
"type" : "charge.succeeded" ,
"created" : 1709942700 ,
"livemode" : false ,
"data" : {
"object" : {
"id" : "ch_1abc2def3ghi" ,
"object" : "charge" ,
"amount" : 2000 ,
"currency" : "usd" ,
"status" : "succeeded" ,
"paid" : true ,
"payment_intent" : "pi_3abc4def5ghi" ,
"customer" : "cus_9abc0def1ghi" ,
"payment_method" : "pm_card_visa" ,
"created" : 1709942700 ,
"livemode" : false
}
}
}
charge.failed
Occurs when a charge attempt fails.
{
"id" : "evt_7ghi8jkl9mno" ,
"object" : "event" ,
"type" : "charge.failed" ,
"created" : 1709942760 ,
"livemode" : false ,
"data" : {
"object" : {
"id" : "ch_2bcd3efg4hij" ,
"object" : "charge" ,
"amount" : 2000 ,
"currency" : "usd" ,
"status" : "failed" ,
"paid" : false ,
"failure_code" : "card_declined" ,
"failure_message" : "Your card was declined." ,
"payment_intent" : "pi_3abc4def5ghi" ,
"customer" : "cus_9abc0def1ghi" ,
"created" : 1709942760 ,
"livemode" : false
}
}
}
charge.refunded
Occurs when a charge is fully or partially refunded.
{
"id" : "evt_8hij9klm0nop" ,
"object" : "event" ,
"type" : "charge.refunded" ,
"created" : 1709942820 ,
"livemode" : false ,
"data" : {
"object" : {
"id" : "ch_1abc2def3ghi" ,
"object" : "charge" ,
"amount" : 2000 ,
"amount_refunded" : 2000 ,
"currency" : "usd" ,
"status" : "succeeded" ,
"refunded" : true ,
"payment_intent" : "pi_3abc4def5ghi" ,
"customer" : "cus_9abc0def1ghi" ,
"created" : 1709942700 ,
"livemode" : false
}
}
}
Customer Events
customer.created
Occurs when a new customer is created.
{
"id" : "evt_9ijk0lmn1opq" ,
"object" : "event" ,
"type" : "customer.created" ,
"created" : 1709942880 ,
"livemode" : false ,
"data" : {
"object" : {
"id" : "cus_9abc0def1ghi" ,
"object" : "customer" ,
"name" : "Jane Doe" ,
"email" : "jane@example.com" ,
"phone" : null ,
"description" : null ,
"metadata" : {},
"created" : 1709942880 ,
"livemode" : false
}
}
}
customer.updated
Occurs when a customer record is updated.
{
"id" : "evt_0jkl1mno2pqr" ,
"object" : "event" ,
"type" : "customer.updated" ,
"created" : 1709942940 ,
"livemode" : false ,
"data" : {
"object" : {
"id" : "cus_9abc0def1ghi" ,
"object" : "customer" ,
"name" : "Jane Doe" ,
"email" : "jane.doe@example.com" ,
"phone" : "+15551234567" ,
"description" : "Updated customer" ,
"metadata" : {
"tier" : "premium"
},
"created" : 1709942880 ,
"livemode" : false
}
}
}
Refund Events
refund.created
Occurs when a refund is created.
{
"id" : "evt_1klm2nop3qrs" ,
"object" : "event" ,
"type" : "refund.created" ,
"created" : 1709943000 ,
"livemode" : false ,
"data" : {
"object" : {
"id" : "re_1abc2def3ghi" ,
"object" : "refund" ,
"amount" : 1000 ,
"currency" : "usd" ,
"status" : "pending" ,
"payment_intent" : "pi_3abc4def5ghi" ,
"charge" : "ch_1abc2def3ghi" ,
"reason" : "requested_by_customer" ,
"metadata" : {},
"created" : 1709943000
}
}
}
refund.updated
Occurs when a refund’s status changes (e.g., from pending to succeeded or failed).
{
"id" : "evt_2lmn3opq4rst" ,
"object" : "event" ,
"type" : "refund.updated" ,
"created" : 1709943060 ,
"livemode" : false ,
"data" : {
"object" : {
"id" : "re_1abc2def3ghi" ,
"object" : "refund" ,
"amount" : 1000 ,
"currency" : "usd" ,
"status" : "succeeded" ,
"payment_intent" : "pi_3abc4def5ghi" ,
"charge" : "ch_1abc2def3ghi" ,
"reason" : "requested_by_customer" ,
"metadata" : {},
"created" : 1709943000
}
}
}
Dispute Events
dispute.created
Occurs when a customer disputes a charge (chargeback).
{
"id" : "evt_3mno4pqr5stu" ,
"object" : "event" ,
"type" : "dispute.created" ,
"created" : 1709943120 ,
"livemode" : false ,
"data" : {
"object" : {
"id" : "dp_1abc2def3ghi" ,
"object" : "dispute" ,
"amount" : 2000 ,
"currency" : "usd" ,
"status" : "needs_response" ,
"charge" : "ch_1abc2def3ghi" ,
"payment_intent" : "pi_3abc4def5ghi" ,
"reason" : "fraudulent" ,
"evidence_due_by" : 1710547200 ,
"created" : 1709943120 ,
"livemode" : false
}
}
}
Best Practices
Verify signatures Always verify the X-Signature header before processing any webhook event.
Return 2xx quickly Respond with a 200 status code within 5 seconds. Process events asynchronously if needed.
Handle duplicates Use the event id to deduplicate. We may send the same event more than once.
Use event type filtering Only subscribe to the event types you need to reduce unnecessary traffic.