Subscription Webhook Payloads
Subscription Webhook Payloads for asynchronous events are available in Saleor 3.2.
Subscription Webhook payloads for synchronous events are available in Saleor 3.6.
Custom Payloads
You can define webhook payloads in Saleor with GraphQL subscriptions. Subscription queries allow you to subscribe to different events and determine what fields should be returned in the payload.
Building Subscription Query
To build a subscription query you can use any GraphQL interface (like GraphQL Playground). Just like with building a GraphQL query, you can use prompts and build the whole subscription from our API. Payload generation will use resolvers/permissions that are normally used in our API. Inside the query, you must define the event type for which the payload will be generated. The event type must be supported by our subscription mechanism (see the list of supported events).
When defining subscription payload for synchronous webhooks some fields are blocked to prevent circular calls.
The example below is a subscription query that would enable listening to the PRODUCT_UPDATED
event and requesting the products id and name in the webhook payload:
subscription {
event {
... on ProductUpdated {
product {
id
name
}
}
}
}
Filtering
This feature was introduced in Saleor 3.20.
This feature is in the Feature Preview stage, which means that it is available for experimentation and feedback. However, it is still undergoing development and is subject to modifications.
For some webhook events, you can create a filterable subscription. A filterable subscription means the event will be delivered only when the filter input matches the object. This can be useful in below cases:
- The app is responsible for additional actions for orders that come from a specific channel. For example:
US
channel requires to receive information that payment was charged, whereas the rest of the channels have auto-capture. - Making a separation between different markets. For example:
US
channel doesn't need to receive order events fromUK
market. - Reducing the traffic between Saleor and apps. Instead of sending each event to each app, the traffic will be reduced as only events for defined channels will be delivered.
All filterable events are available as a top-level subscription field, on the same level as the event field.
Below events can be filtered:
- draftOrderCreated
- draftOrderDeleted
- draftOrderUpdated
- orderBulkCreated
- orderCancelled
- orderCreated
- orderExpired
- orderFulfilled
- orderFullyPaid
- orderFullyRefunded
- orderMetadataUpdated
- orderPaid
- orderRefunded
- orderUpdated
Only one top field can be requested as a filterable subscription query. This means that in a single subscription, you cannot define more than one filterable event or mix it with the event
field. In that case, a new webhook with a new subscription should be created.
Subscription queries like the below will raise validation error:
subscription {
orderUpdated(channels: ["different-channel"]) {
order {
lines {
id
variant {
id
product {
id
}
}
}
}
}
orderCreated(channels: ["default-channel"]) {
order {
lines {
id
variant {
id
product {
id
}
}
}
}
}
}
subscription {
event {
... on OrderCreated {
order {
id
}
}
}
orderCreated(channels: ["default-channel"]) {
order {
lines {
id
variant {
id
product {
id
}
}
}
}
}
}
The example below is a subscription query that triggers a webhook only for orders that belong to given channels: uk
, us
:
subscription {
orderCreated(channels: ["uk", "us"]) {
order {
id
lines {
id
}
}
}
}
The input channels
will accept a maximally 500 values. Exceeding this value will cause a validation error.
The above subscription will generate the following webhook payload:
{
"data": {
"orderCreated": {
"order": {
"id": "T3JkZXI6YzhmY2FjMTgtMWQ5Yy00NWRkLTgxMGYtMGIzMTJiYTNjZDYz",
"lines": [
{
"id": "T3JkZXJMaW5lOjkzYTFjZGMxLTQxMzAtNDE4ZC05YTAxLTQyY2I5N2E3ZjIxMw=="
}
]
}
}
}
}
Creating Webhook With Subscription Query
To create a webhook that will have its payload generated using a subscription, you need to use the same mutation as with standard webhooks. The only difference is passing the query
field as an input with a subscription query converted to a string.
Webhook with the query
field defined will be treated as a subscription webhook, and its payload will be generated from the subscription query.
Example asynchronous webhook create mutation for subscription payload:
mutation {
webhookCreate(
input: {
app: "<app_id>"
name: "test_product_updated_subscription"
targetUrl: "<webhook_url>"
asyncEvents: [PRODUCT_UPDATED]
query: "subscription{event{...on ProductUpdated{product{id name}}}}"
}
) {
errors {
field
message
}
webhook {
id
}
}
}
Example asynchronous webhook payload:
{
"product": {
"id": "UHJvZHVjdDo3Ng==",
"name": "Coconut Juice"
}
}
Example synchronous webhook create mutation for subscription payload:
mutation {
webhookCreate(
input: {
app: "<app_id>"
name: "test_payment_capture_subscription"
targetUrl: "<webhook_url>"
syncEvents: [PAYMENT_CAPTURE]
query: "subscription{event{...on PaymentCaptureEvent{payment{id created}}}}"
}
) {
errors {
field
message
}
webhook {
id
}
}
}
Example synchronous webhook payload:
{
"payment": {
"id": "UGF5bWVudDoyNDE=",
"created": "2022-08-03T08:52:04.202449+00:00"
}
}
Synchronous Webhooks Payload
Defining synchronous webhook payloads using subscriptions is also supported. Each event subscription type has access to its specific object fields.
Keep in mind that some fields that use the synchronous event to be resolved are not allowed to be called in synchronous webhook payload subscriptions.
Blocked Fields for Subscription Payloads
Synchronous events are not allowed to request fields that are resolved using other synchronous events, which would lead to circular calls of the webhook. Fields that are currently unallowed:
Object | Fields |
---|---|
Checkout | shippingMethods , availableShippingMethods , availablePaymentGateways |
Order | shippingMethods , availableShippingMethods |
Permissions
Since subscriptions use the Saleor API to define a webhook payload, the App that has the webhook subscribed needs all the permissions that are typically required when querying for specified data. Otherwise, the payload will not be resolved correctly.