Bare-bones app for testing Saleor's Transactions API
Tip
Questions or issues? Check our discord channel for help.
The Dummy Payment App allows you to test Saleor's payment and checkout features without needing to set up a real payment provider. You can create orders, process payments, issue refunds, and more, all within the Saleor Dashboard.
- Create new checkouts and orders from the Saleor Dashboard:
- Process payments and update transaction statuses:
Tip
Each Transaction has externalUrl that links to this page from Order details page in Saleor Dashboard:
- Issue refunds, process charges and cancellations for Transactions
The Dummy Payment App supports the following webhooks to enable payment flows:
The app implements webhooks to process payments initiated from your storefront:
PAYMENT_GATEWAY_INITIALIZE_SESSIONTRANSACTION_INITIALIZE_SESSIONTRANSACTION_PROCESS_SESSION
It also implements webhooks to allow updating the status of Transactions from the Saleor Dashboard, similar to how a real third-party payment provider would:
TRANSACTION_REFUND_REQUESTEDTRANSACTION_CHARGE_REQUESTEDTRANSACTION_CANCELATION_REQUESTED
To run the Dummy Payment App locally, follow these steps:
- Install dependencies
This project uses pnpm as the package manager. If you don't have it installed, you can enable it with corepack:
npm install --global corepack@latest
corepack enable pnpm
pnpm install- (Optional) Set up environment variables for custom URLs
By default, no environment variables are required. However, if you are developing locally with Docker or using tunnels, you may want to customize the app's URLs. Copy the example environment file if you want to override defaults:
cp .env.example .envCheck Saleor Docs about local app development for more details
- Run the app locally
Start the development server:
pnpm devThe app will be available at http://localhost:3000.
After installing the app in Saleor, visit the app's Dashboard.
There you can create a Checkout, a set shipping method on that checkout.
After that step is completed you can initialize a Transaction using transactionInitialize mutation. App's response to that mutation can be modified using provided input.
The checkout process in app looks like this:
- Select channel where you want to create the Checkout
- Click "Create checkout" to create Checkout in Saleor in your selected channel
- Click "Set delivery" to set delivery method on that checkout
- Set response you want the app to return for
TRANSACTION_INITIALIZE_SESSION - Click "Initialize transaction"
- Wait until response is returned and click "Complete checkout" to send
checkoutCompletemutation
Dummy Payment App provides a built-in storefront for creating Transactions in Saleor. If you want to test your own storefront before integrating a real payment provider or you prefer to make requests manually here is a description of all available Transaction mutations in Saleor supported by app.
When you send transactionInitialize or transactionProcess mutations to Saleor, you can include a data field in your mutation variables. This data field is passed through to the Dummy Payment App's webhooks. The app uses the content of this data field to determine how it should respond.
For this app, the crucial parts of the data field you send are:
data.event.type: Specifies the desired outcome of the transaction (e.g.,CHARGE_SUCCESS,AUTHORIZATION_FAILURE). This directly controls theresultfield in the app's response. SeeTransactionEventTypeEnumfor all possible values.data.event.includePspReference: A boolean indicating whether the app should generate and return apspReferencein its response or if it should returnundefined.
1. transactionInitialize Mutation
Use the transactionInitialize mutation to start a new transaction. It can be created on either Checkout or Order objects.
mutation TransactionInitialize(
$id: ID! # Checkout or Order ID
$action: TransactionFlowStrategyEnum # Override channel default action - e.g., CHARGE, AUTHORIZATION
$amount: PositiveDecimal # Override default amount (totalBalance)
$data: JSON! # Data object to control app behavior - required
) {
transactionInitialize(id: $id, action: $action, amount: $amount, data: $data) {
transactionEvent {
pspReference # Populated based on your data.event.includePspReference
amount {
amount
currency
}
type # Reflects your data.event.type
}
data # The JSON response from this app's webhook (see "App's Webhook Response Structure" below)
errors {
field
message
code
}
}
}Here's how you'd structure the variables, focus on the data field which is required by the app:
{
"id": "Q2hlY2tvdXQ6YWY3MDJkMGQtMzM0NC00NjMxLTlkNmEtMDk4Yzk1ODhlNmMy",
"action": "CHARGE",
"amount": 54.24,
"data": {
"event": {
"type": "CHARGE_SUCCESS", // See below for all possible types
"includePspReference": true // true or false
}
}
}When the app receives the TRANSACTION_INITIALIZE_SESSION webhook triggered by this mutation:
- If
data.event.includePspReferencefrom your mutation istrue, the app's response will contain apspReference(a v7 UUID). Otherwise,pspReferencewill beundefined(ornull). - The
data.event.typeyou send (e.g.,"CHARGE_SUCCESS") will become theresultin the app's JSON response. - The
actionsarray in the app's response (e.g.,["REFUND", "CANCEL"]) is also determined by thedata.event.type.
App accepts following types in data.event.type (these are taken from the possible responses the app can send to Saleor from the TRANSACTION_INITIALIZE_SESSION webhook, see Saleor docs for details):
CHARGE_REQUESTCHARGE_ACTION_REQUIREDCHARGE_FAILURECHARGE_SUCCESSAUTHORIZATION_REQUESTAUTHORIZATION_ACTION_REQUIREDAUTHORIZATION_FAILUREAUTHORIZATION_SUCCESS
2. transactionProcess Mutation
This mutation is used for subsequent steps in a transaction flow, such as handling 3D Secure authentication or other additional actions required by a payment provider. It is used after payment app returns CHARGE_ACTION_REQUIRED or AUTHORIZATION_ACTION_REQUIRED event types.
mutation TransactionProcess(
$id: ID! # Transaction ID from the previous step
$data: JSON! # Data object to control app behavior - required
) {
transactionProcess(id: $id, data: $data) {
transaction {
id
actions
}
transactionEvent {
message
type # Reflects your data.event.type
}
data # The JSON response from this app's webhook (see "App's Webhook Response Structure" below)
errors {
field
code
message
}
}
}{
"id": "VHJhbnNhY3Rpb25JdGVtOjRhODMxNThkLTU0NTAtNDU2Mi04MDE5LTAzYzY4NjMyZjA1Mg==",
"data": {
"event": {
"type": "CHARGE_SUCCESS",
"includePspReference": true
}
}
}When the app receives the TRANSACTION_PROCESS_SESSION webhook:
- The app handles the
datafield (specificallydata.event.typeanddata.event.includePspReference) similarly totransactionInitializeto shape its response. TheresultandpspReferencein the app's output will be based on these values.
When the Dummy Payment App's webhooks are called (triggered by transactionInitialize or transactionProcess mutations), the data field within Saleor's GraphQL mutation response (i.e., transactionInitialize.data or transactionProcess.data) will be structured by this app as follows:
{
"pspReference": "xxxxxxxx-xxxx-7xxx-xxxx-xxxxxxxxxxxx",
"result": "CHARGE_SUCCESS",
"message": "Great success!",
"actions": ["REFUND", "CANCEL"],
"amount": null,
"externalUrl": "https://your-app-deployment-url.com/app/transactions/<transaction_id>"
}If the data field you provide in the mutation doesn't match the app's expected schema (defined in src/modules/validation/sync-transaction.ts), the app will return an error structure within the data field of the mutation response:
{
"pspReference": "xxxxxxxx-xxxx-7xxx-xxxx-xxxxxxxxxxxx",
"result": "CHARGE_FAILURE",
"message": "Zod validation error message details...",
"amount": 54.24,
"actions": [],
"data": {
"exception": true
}
}- Apps guide - learn more how to build your own Saleor app
- Transactions API - learn how to use Transactions API in your store
- Payment App webhooks - learn how to build your own Payment App
You can find docs about App development in the Saleor documentation.
Please open GitHub issues if you find any problem with this app. PRs are welcome too 😄
You can find help with Saleor in these places:
- App logo: Lucide
This application is exempted from PCI DSS requirements due to not allowing users to input any credit card number.


