Webhooks

SureCart uses webhooks to notify your application when an event happens in your account. Webhooks are particularly useful for asynchronous events like when a subscription is updated or a charge is refunded.

You can create and manage your webhook endpoints through the API endpoints or within your dashboard. From your dashboard you can also see a log of recent events that have been sent.

Events

Webhooks are triggered based on events. Events are our way of letting you know when something interesting happens in your account. When an interesting event occurs, we create a new Event object. For example, when an order is created, we create a order.created event.

The request payload of each webhook will contain the Event object, which is structured like the following example.

{
  "id": "5bafe7b7-a4e3-4a7d-85e9-d8b512094b67",
  "object": "event",
  "data": {
    "object": {
      "id": "0d6edf76-98f3-441c-9c43-81a92e929988",
      "object": "order",
      "live_mode": true,
      "number": "0008",
      "order_type": "checkout",
      "statement_url": "https://app.surecart.com/statements/orders/0d6edf76-98f3-441c-9c43-81a92e929988",
      "status": "paid",
      "checkout": "f1a38ad4-f87d-4550-b2e0-91a128cadf06",
      "created_at": 1664479758,
      "updated_at": 1664479758
    }
  },
  "type": "order.created",
  "account": "b7cfbc09-371a-453e-ab29-2edf63de0dbe",
  "created_at": 1664479758
}

When listeneing for webhooks at your webhook endpoint you will want to look at the event.type value to determine what type of event your endpoint has received. For example, the above webhook is a order.created event.

Types of Events

This is a list of all the types of events we currently send. We may add more at any time, so in developing and maintaining your code, you should not assume that only these types exist.

You'll notice that these events follow a pattern: resource.event. Our goal is to design a consistent system that makes things easier to anticipate and code against.

Accounts

  • account.updated - Occurs when a account is updated

Affiliation Requests

  • affiliation_request.approved - Occurs when a affiliation request's status changes to approved
  • affiliation_request.created - Occurs when a affiliation request is created
  • affiliation_request.denied - Occurs when a affiliation status changes to denied
  • affiliation_request.updated - Occurs when a affiliation request is updated

Cancellation Acts

  • cancellation_act.created - Occurs when a cancellation act is created
  • cancellation_act.updated - Occurs when a cancellation act is updated

Customers

  • customer.created - Occurs when a customer is created
  • customer.updated - Occurs when a customer is updated

Fulfillments

  • fulfillment.created - Occurs when a fulfillment is created
  • fulfillment.deleted - Occurs when a fulfillment is deleted
  • fulfillment.updated - Occurs when a fulfillment is updated

Orders

  • order.created - Occurs when an order is created
  • order.delivered - Occurs when an order's shipment status changes to delivered
  • order.fulfilled - Occurs when an order's fulfillment status changes to fulfilled
  • order.made_processing - Occurs when an order's status changes to processing
  • order.paid - Occurs when an order's status changes to paid
  • order.partially_fulfilled - Occurs when an order's fulfillment status changes to partially_fulfilled
  • order.partially_shipped - Occurs when an order's shipment status changes to partially_shipped
  • order.payment_failed - Occurs when an order's status changes to payment_failed
  • order.shipped - Occurs when an order's shipment status changes to shipped
  • order.unfulfilled -Occurs when an order's fulfillment status changes to unfulfilled
  • order.unshipped - Occurs when an order's shipment status changes to unshipped
  • order.voided - Occurs when an order's status changes to void

Payout Groups

  • payout_group.created - Occurs when a payout group is created

Payouts

  • payout.created - Occurs when a payout is created
  • payout.completed - Occurs when a payout's status changes to completed
  • payout.made_processing - Occurs when a payout's status changes to processing

Purchases

  • purchase.created - Occurs when a purchase is created
  • purchase.invoked - Occurs when a purchase is invoked
  • purchase.revoked - Occurs when a purchase is revoked
  • purchase.updated - Occurs when a purchase is updated

Referrals

  • referral.approved- Occurs when a referral's status changes to approved
  • referral.canceled- Occurs when a referral's status changes to canceled
  • referral.created- Occurs when a referral is created
  • referral.denied- Occurs when a referral's status changes to denied
  • referral.made_reviewing- Occurs when a referral's status changes to reviewing
  • referral.updated- Occurs when a referral is updated

Refunds

  • refund.created - Occurs when a refund is created
  • refund.succeeded - Occurs when a refund's status changes to succeeded

Return Requests

  • return_request.completed - Occurs when a return request's status changes to completed
  • return_request.created - Occurs when a return request is created
  • return_request.deleted - Occurs when a return request is deleted
  • return_request.opened - Occurs when a return request's status changes to open
  • return_request.updated - Occurs when a return request is updated

Subscriptions

  • subscription.canceled - Occurs when a subscription's status changes to canceled
  • subscription.created - Occurs when a subscription is created
  • subscription.completed - Occurs when a subscription's status changes to completed
  • subscription.made_active - Occurs when a subscription's status changes to active
  • subscription.made_trialing - Occurs when a subscription's status changes to trialing
  • subscription.renewed - Occurs when a subscription renews
  • subscription.set_to_cancel - Occurs when a subscription is set to cancel at the end of the current billing period
  • subscription.updated - Occurs when a subscription is updated

Expanding Webhook Events

All webhooks contain the parent resource of the corresponding event and do not expand any related objects. This keeps webhook payloads small and ensures unecessary data is not being sent.

If you wish to expand a resource you will need to make a subsequent retrieve request with the expansions you need. See the Expanding Responses documentation for more detail.

Webhook Signatures

All webhooks include a signature in each request’s x-webhook-signature header. This allows you to verify that the events were sent by us, and not by a third party. We generate signatures using a hash-based message authentication code (HMAC) with SHA-256.

We generate a unique signing secret key for each endpoint. If you use multiple endpoints, you must use the unique signing secret for each one you want to verify signatures on. You can view the signing secret for each endpoint from within your dashboard, or you can retrive it from the API.

Preventing Replay Attacks

A replay attack is when an attacker intercepts a valid payload and its signature, then re-transmits them. To mitigate such attacks, we include a timestamp in the x-webhook-timestamp header. This timestamp is also part of the signed payload and verified by the signature, so an attacker cannot change the timestamp without invalidating the signature. If the signature is valid but the timestamp is too old, you can have your application reject the payload.

We generate the timestamp and signature each time we send an event to your endpoint. If we retry an event (for example, your endpoint previously replied with a non-2xx status code), then we generate a new signature and timestamp for the new delivery attempt.

Verify Signatures

Step 1: Extract Signature and Timestamp
The signature is sent in the x-webhook-signature header, and the timestamp is sent in the x-webhook-timestamp header.

x-webhook-signature = "287ace7f0267943970dca9e895be11a739b532b85dfed8a3d147ca2d08267f48"
x-webhook-timestamp = "1641873601"

Step 2: Prepare Signed Payload String
The signed_payload string is created by concatenating the timestamp and the payload with the . character.

Step 3: Determine Expected Signature
Compute an HMAC with the SHA256 hash function. Use the endpoint’s signing secret as the key, and use the signed_payload string as the message.

Step 4: Compare Signatures
Compare the signature in the header to the expected signature.