Skip to main content

Webhooks

Webhooks allow you to receive real-time updates about events in your store. They open a lot of possibilities for extending and automating Reflow integrations.

PRO Feature

Webhooks are only available in the Reflow PRO plan. Subscribe to get access to webhooks, as well as many other features including digital products, email customization options, increased product limits, and more.

How Store Webhooks Work

Reflow uses webhooks to inform your application whenever an event occurs within your store. Events are sent in the form of an HTTP POST request to one or more URL endpoints on your server.

By monitoring these events, you can use the incoming data to perform custom backend operations specific to your store's use case. Here is a quick example:

  1. A customer completes the checkout process and places an order in a store.
  2. A new order.created event is initialized in Reflow.
  3. A POST request is sent to an endpoint on the store's website https://example.com/reflow-endpoint.
  4. The server receives the event. It contains all information about the placed order, including products, customer details, shipping, etc.
  5. Using that data, the store's backend code exports the new order in a PDF and sends it to the warehouse for fulfillment.
  6. The server returns an HTTP 200 response to Reflow, marking the event as successfully received.

The Webhook Event Object

When Reflow sends a webhook request, it sends a JSON payload containing information about the event, such as the event type, the object that triggered the event, and any additional data associated with the event.

Here is an example of a user.updated event.

{
"id": "evt_63c741d62a41c4282e58aea7707125e5590fe0a7",
"object": "event",
"api-version": "2023-01-30",
"created": 1676487635,
"data": {
"object": {
"id": "12345678",
"object": "user",
"created_at": 1676487635,
"email": "johndoe@example.com",
"meta": {
"address": {
"address": "123 Street Ave",
"city": "Paris",
"country": "FR",
"name": "John Doe",
"postcode": "1234"
},
"phone": "123456789"
},
"name": "John Doe",
"photo": "http://reflow.local/img/gravatar/default.png",
"provider": "google"
},
"previous_attributes": {
"email": "old.email@example.com",
"name": "Old Name Value"
}
},
"livemode": true,
"request_id": "req_cdf19b9c78cae64b12dabc4f8587283ee865c464",
"type": "user.updated"
}

The data->object property holds a JSON representation of the store resource that triggered the event. In the case of the example above, that is the user profile that has been updated.

Note

For *.updated events, the contents of data->object are in their state after the update.

The data->previous_attributes property holds the old values of the object, before the changes.

Webhook Event Types

Event types follow a naming pattern of resource.event. The webhook events we currently support are listed below.

  • order.created - Occurs when a new order has been placed in the store.
  • order.updated - Occurs when an existing order has been updated. For example, when an order payment is confirmed its payment_status changes from pending to paid.
  • user.created - This event occurs when a customer creates an account via the Store Registration feature.
  • user.updated - Occurs when a registered customer changes their user settings, e.g. their profile photo or email.
  • products.changed - Occurs when products are added, updated or deleted in the store.
  • categories.changed - Occurs when changes are made to the categories of your store.

In the future, we plan to expend the Webhooks API with more events, so stay tuned!

Examples

Capturing an Order Payment

In this example we will create a webhook endpoint that handles incoming orders. It will listen for the order.created and order.updated events to get all the order data and proceed with fulfillment once payment has been confirmed.

When a customer completes the shopping cart checkout process, the order.created event is triggered, indicating that a new order has been placed. This event contains all of the information about the purchased products, customer details, delivery, taxes, and more.

Initially, when an order is created, its payment_status is pending. After payment is confirmed, the payment_status of the order changes to paid. This status change is reflected by the order.updated event, which is asynchronous - the timing of the payment confirmation will depend on the used payment method.

function webhookHandler(Request $request)
{
$event = $request->getContent();

if ($event->type === 'order.created') {

// The store has received a new order.

// Save the order data to a local database.
$order = $event->data->object;
DB::saveOrder($order);
}

if ($event->type === 'order.updated') {

// An existing order has been updated.

// Get the order object and check the status.
$order = $event->data->object;

if ($order->payment_status === 'paid') {
// The order payment has been completed successfully.
// Proceed with fulfillment,
fulfillOrder($order);
}

if ($order->payment_status === 'failed') {
// There were multiple unsuccessful attempts to complete the payment.
// Contact the customer to assist them with their order.
contactCustomer($order->customer->email);
}
}

// Return a HTTP 200 response when we're done.
return response(['status' => 'success'], 200);
}

Content Revalidation

Another great use for webhooks is when developing with frameworks such as Next.js or Astro that support static static generation.

These frameworks can be configured to pre-render and cache content on the server for best performance. This comes with the drawback that once the cache is set, content can become stale - any updates to your store's products won't show up because the old version is cached.

The best way to get around this is to send webhooks to your static generated app when there are changes it should know about.

In this example, we've configured our Reflow store to send webhooks for the products.changed and categories.changed events. In our Next.js code, we will listen for these events and revalidate the server cache.

// Next.js example
// Webhook POST request are sent to `/api/revalidate` to control revalidation logic.

export async function revalidate(req: NextRequest): Promise<NextResponse> {
const body = await req.json();

const isCategoriesUpdate = body?.type == "categories.changed";
const isProductUpdate = body?.type == "products.changed";

// Revalidate the data for the respective cache tag.

if (isCategoriesUpdate) {
revalidateTag(TAGS.categories);
}

if (isProductUpdate) {
revalidateTag(TAGS.products);
}

return NextResponse.json({ cache_revalidated: true });
}