Skip to main content

Payment events (legacy)

danger

This is legacy API documentation for reference only for those that built python payment plugins.

See transaction events instead.

Introduction

Payment webhooks are synchronously sent webhooks that allow delegating payment handling to Saleor Apps. Synchronous means that these webhooks expect a response of a particular shape to be returned from the App to continue processing in Saleor. Payment webhooks only support the HTTP(S) protocol, they are sent as POST requests with the application/json body and expect a response of the same content type.

Available payment events are:

NameDescription
PAYMENT_AUTHORIZEAuthorize payment
PAYMENT_CAPTURECapture payment
PAYMENT_CONFIRMConfirm payment
PAYMENT_LIST_GATEWAYSList payment gateways
PAYMENT_PROCESSProcess payment
PAYMENT_REFUNDRefund payment
PAYMENT_VOIDVoid payment

First, you need to create an App to react to payment webhooks. You can read more about apps here. Remember to make the App active and grant it the HANDLE_PAYMENTS permission.

Register PAYMENT_LIST_GATEWAYS webhook

When enabling payment webhooks, first, you need to subscribe to the PAYMENT_LIST_GATEWAYS event. This event is called whenever Saleor lists available payment gateways in the API or internal use. This webhook needs to return information about payment methods defined in your App.

Below are two example cases when the PAYMENT_LIST_GATEWAYS event is triggered:

Listing all available payment gateways

This query returns information about available payment gateways without any additional context:

{
shop {
availablePaymentGateways(currency: "USD", channel: "default-channel") {
name
id
config {
field
value
}
currencies
}
}
}

The availablePaymentGateways field accepts the optional currency argument. If provided, it will be passed in the webhook payload and can be used to return payment methods that support a particular currency.

Listing available payment gateways for a checkout

You can also query for the available payment gateways in the context of a specific checkout. It is helpful if payment methods depend on the current checkout (e.g. user’s shipping country etc.)

{
checkout(token: "checkout-uuid-token") {
availablePaymentGateways {
name
}
}
}

See the example payload sent from Saleor for this event: List payment gateways payload.

Expected webhook response

In the response, you should return a list of the supported payment methods, for example:

[
{
"id": "credit-card",
"name": "Credit Card",
"currencies": ["EUR"],
"config": []
},
{
"id": "apple-pay",
"name": "Apple Pay",
"currencies": ["EUR", "USD"],
"config": [
{
"field": "apple-pay-config-field",
"value": "value"
}
]
}
]
Expand ▼

Each item on the list should have the following fields:

  • id - the ID of a payment method. Must be unique within your App.
  • name - the name of the payment method.
  • currencies - a list of currencies supported by this payment method.
  • config - optional configuration, such as additional payment data that may be needed to proceed with the payment in the frontend.

Register webhooks for payment actions

To subscribe to particular payment events (such as capture or authorization), you can have multiple webhooks with separate URLs for each action or a single webhook that handles all events (each webhook has the Saleor-Event header that contains the type of event).

List of payment events:

  • PAYMENT_AUTHORIZE
  • PAYMENT_CAPTURE
  • PAYMENT_CONFIRM
  • PAYMENT_PROCESS
  • PAYMENT_REFUND
  • PAYMENT_VOID
note

If an App has more than one webhook that listens to the same payment event, Saleor will always pick the first webhook from the list.

See the example payload sent from Saleor for these payment events: Payment actions payload.

For payments that require confirmation (such as 3D Secure) Saleor triggers the following events:

  • PAYMENT_PROCESS - when the checkoutComplete mutation is run for the first time, a payment is created and waits for the user's confirmation.
  • PAYMENT_CONFIRM - when the checkoutComplete mutation is run for the second time, the payment is confirmed. Depending on the payment gateway, multiple events can be triggered.

For payments without a confirmation step, Saleor triggers only the PAYMENT_PROCESS event.

Expected response

Below is the list of fields that a webhook can return in the JSON response for a payment action. All fields are optional:

  • action_required - (boolean) determines if additional action (confirmation) is required.
  • action_required_data - (object) additional data that may be needed to confirm the payment. An example would be a URL to redirect the user to the confirmation page in the frontend.
  • kind - (string) Transaction kind, one of: action_to_confirm, auth, cancel, capture, capture_failed, confirm, external, pending, refund, refund_failed, refund_ongoing, refund_reversed, void.
  • amount - (number) transaction amount. Use this field only if the charged amount is different than the checkout's total.
  • customer_id - (string) gateway's customer ID.
  • error - (string) error message. If provided, the transaction will be marked as failed in Saleor and payment will have to be retried. Use this field if you need to return any errors.
  • payment_method - (object) information about the payment method chosen by the user.
  • psp_reference - (string) external payment reference id. Can be used for finding transactions in the payment provider dashboard or relevant orders in the Saleor dashboard.
  • transaction_id - (string) gateway's transaction ID.
  • transaction_already_processed - (boolean) use this field to mark a transaction as already processed in your gateway.

The response fields match the GatewayResponse data class used in Saleor to represent a response from a payment gateway; you can read more about these fields here.

Example response for the PAYMENT_PROCESS event when confirmation is required:

{
"action_required": true,
"action_required_data": {
"confirmation_url": "https://www.example.com/3ds-confirmation/"
},
"customer_id": "customer-1234",
"payment_method": {
"brand": "Visa",
"exp_month": "01",
"exp_year": "2025",
"last_4": "4242",
"name": "John Doe",
"type": "Credit card"
},
"transaction_id": "transaction-1234"
}

Example response for the PAYMENT_PROCESS event when the payment should be authorized, but unpaid (e.g. to be captured in the dashboard):

{
"action_required": false,
"kind": "auth",
"customer_id": "customer-1234",
"payment_method": {
"brand": "Visa",
"exp_month": "01",
"exp_year": "2025",
"last_4": "4242",
"name": "John Doe",
"type": "Credit card"
},
"transaction_id": "transaction-1234"
}

Use the webhook's payment method in checkout

If payment webhooks are configured properly, you can use their payment methods in checkout. To do this, you need to list available payment methods for your checkout or shop. Each payment method from a payment webhook has an ID of this format: app:<app-database-id>:<id-returned-by-webhook>

Example: app:1:credit-card

To use this gateway in checkout, run checkoutPaymentCreate mutation and pass this ID as the gateway parameter:

mutation {
checkoutPaymentCreate(
checkoutId: "example-checkout-id"
input: { gateway: "app:1:credit-card", amount: 22.36 }
) {
payment {
id
}
}
}

Running the checkoutComplete mutation afterward will use the payment method set above and trigger your payment webhook.

Read more about checkout mutations here.