> Documentation index: [Saleor](/llms.txt) · [This section](/developer/llms.txt)
> Source: https://docs.saleor.io/developer/payments/transactions

# Transactions

A transaction represents a payment instance created in Order or Checkout. It holds a list of events that make up the payment process. Each event has a type that describes the action taken on the transaction. You can see the complete list of events in the [`TransactionEventTypeEnum`](/api-reference/payments/enums/transaction-event-type-enum.md).

Besides the events, a transaction also contains other payment information, like the amount or currency.

<a id="amount-rounding"></a>

### Amount rounding

If the provided amount uses more decimal places than used currency, it will be rounded to the nearest value.

For example:

-   `19.999 USD` will become `20.00 USD`
-   `10.2 JPY` will become `10 JPY`

<a id="creating-transactions"></a>

### Creating transactions

Transaction stores details of a payment transaction attached to an order or a checkout:

The [`transactionCreate`](/api-reference/payments/mutations/transaction-create.md) mutation takes the following arguments:

-   `id`: The ID of the checkout or order.
-   `transaction`: Input data required to create a new transaction object.
-   `transactionEvent`: Data that defines a transaction event. It can be used to provide more context about the current state of the transaction.

info

The [`transactionCreate`](/api-reference/payments/mutations/transaction-create.md) can only be called by staff users or apps with the [`HANDLE_PAYMENTS`](/api-reference/users/enums/permission-enum.md#handle-payments) permission.

The following example shows how you can use the [`transactionCreate`](/api-reference/payments/mutations/transaction-create.md) mutation to create a new transaction.

The transaction was authorized, and the payment was made with a credit card. The actions that can be called from Saleor are: `CANCEL` and `CHARGE`. The authorized amount is **$99**.

**Mutation**

```graphql
mutation TransactionCreate($id: ID!, $transaction: TransactionCreateInput!) {
  transactionCreate(id: $id, transaction: $transaction) {
    transaction {
      id
    }
  }
}
```

**Variables**

```json
{
  "id": "Q2hlY2tvdXQ6MWQzNmU5YzctYWEwYS00NzM5LTk0MGQtNzdjNmU4Mjc5YmQ0",
  "transaction": {
    "name": "Credit card",
    "message": "Authorized",
    "pspReference": "PSP-ref123",
    "availableActions": [
      "CANCEL",
      "CHARGE"
    ],
    "amountAuthorized": {
      "currency": "USD",
      "amount": 99
    },
    "externalUrl": "https://saleor.io/payment-id/123"
  }
}
```

**Result**

```json
{
  "data": {
    "transactionCreate": {
      "transaction": {
        "id": "VHJhbnNhY3Rpb25JdGVtOjE="
      }
    }
  },
  "extensions": {
    "cost": {
      "requestedQueryCost": 0,
      "maximumAvailable": 50000
    }
  }
}
```

info

-   Transactions attached to the checkout are accessible via the [`checkout.transactions`](/api-reference/checkout/objects/checkout.md#transactions) field.
-   Transactions attached to order are accessible via the [`order.transactions`](/api-reference/orders/objects/order.md#transactions) field.

<a id="updating-transactions"></a>

### Updating transactions

The [`transactionUpdate`](/api-reference/payments/mutations/transaction-update.md) mutation allows updating the transaction details. It takes the following arguments:

-   `id`: The ID of the transaction.
-   `transaction`: Input data that will be used to update the transaction object.
-   `transactionEvent`: Data that defines a transaction event. It can be used to provide more context about the current state of the transaction.

info

The [`transactionUpdate`](/api-reference/payments/mutations/transaction-update.md) can only be called by staff users with the [HANDLE\_PAYMENTS](/api-reference/users/enums/permission-enum.md#handle-payments) permission or by the App that created the the transaction and has [`HANDLE_PAYMENTS`](/api-reference/users/enums/permission-enum.md#handle-payments) permission.

The following example shows how you can use the [`transactionUpdate`](/api-reference/payments/mutations/transaction-update.md) mutation to update the transaction.

The available action is `REFUND`. The authorized funds are charged, so `amountAuthorized` is **$0** and `amountCharged` is **$99**.

**Mutation**

```graphql
mutation TransactionUpdate($id: ID, $transaction: TransactionUpdateInput, $transactionEvent: TransactionEventInput) {
  transactionUpdate(
    id: $id
    transaction: $transaction
    transactionEvent: $transactionEvent
  ) {
    transaction {
      id
    }
  }
}
```

**Variables**

```json
{
  "id": "VHJhbnNhY3Rpb25JdGVtOjE=",
  "transaction": {
    "name": "Credit card",
    "message": "Authorized",
    "pspReference": "PSP-ref123",
    "availableActions": [
      "REFUND"
    ],
    "amountAuthorized": {
      "currency": "USD",
      "amount": 0
    },
    "amountCharged": {
      "currency": "USD",
      "amount": 99
    }
  },
  "transactionEvent": {
    "message": "Payment charged",
    "pspReference": "PSP-ref123.charge"
  }
}
```

**Result**

```json
{
  "data": {
    "transactionUpdate": {
      "transaction": {
        "id": "VHJhbnNhY3Rpb25JdGVtOjE="
      }
    }
  },
  "extensions": {
    "cost": {
      "requestedQueryCost": 0,
      "maximumAvailable": 50000
    }
  }
}
```

note

During the update of transactions, all funds that go to a new state should be subtracted from the previous state. Assuming we have a transaction with `authorizedAmount` equal to 100 USD. Moving the `authorizedAmount` to `chargedAmount` requires setting the `authorizedAmount` to 0.

This complexity is handled automatically when Payment Apps are used instead of a custom app.

**Mutation**

```graphql
mutation TransactionUpdate($id: ID, $transaction: TransactionUpdateInput, $transactionEvent: TransactionEventInput) {
  transactionUpdate(
    id: $id
    transaction: $transaction
    transactionEvent: $transactionEvent
  ) {
    transaction {
      id
    }
  }
}
```

**Variables**

```json
{
  "id": "VHJhbnNhY3Rpb25JdGVtOjE=",
  "transaction": {
    "availableActions": [
      "REFUND"
    ],
    "amountAuthorized": {
      "currency": "USD",
      "amount": 0
    },
    "amountCharged": {
      "currency": "USD",
      "amount": 100
    }
  },
  "transactionEvent": {
    "message": "Payment charged",
    "pspReference": "PSP-ref123.charge"
  }
}
```

<a id="reporting-actions-for-transactions"></a>

### Reporting actions for transactions

The [`transactionEventReport`](/api-reference/payments/mutations/transaction-event-report.md) is used to report a new transaction event. The newly created event will be used to [recalculate](/developer/payments/lifecycle.md#transactions-recalculation-of-amounts) the transaction's amounts. The mutation should be used for handling [action requests](#handling-action-requests-for-transactions) or reporting any changes that happened on the payment provider side (eg. asynchronous webhooks for delayed payment methods, chargebacks, disputes etc.).

It takes the following arguments:

-   `id`: The id of the transaction.
-   `type`: Type of the reported action.
-   `amount`: The amount of the reported action. The amount is rounded based on the given currency precision. It is mandatory for all `REQUEST`, `SUCCESS`, `ACTION_REQUIRED`, and `REQUEST` events. For other events, if the amount is not provided, it will be calculated based on previous events with the same pspReference. If the amount cannot be determined, an error will be raised. (Refer to the additional details [below](#amount-calculations-for-reporting-an-action-with-missing-amount-value) ).
-   `pspReference`: The reference assigned to the action.
-   `time`: The time of the action.
-   `externalUrl`: The URL for the staff user to check the details of the action on the payment provider's page. This URL will be available in the Saleor Dashboard.
-   `message`: Message related to the action. The maximum length is 512 characters; any text exceeding this limit will be truncated.
-   `availableActions`: Current list of actions available for the transaction.

info

The [`transactionEventReport`](/api-reference/payments/mutations/transaction-event-report.md) can only be called by staff users with [`HANDLE_PAYMENTS`](/api-reference/users/enums/permission-enum.md#handle-payments) permission or by the App that created the transaction and has [`HANDLE_PAYMENTS`](/api-reference/users/enums/permission-enum.md#handle-payments) permission.

The following example shows how the [transactionEventReport](/api-reference/payments/mutations/transaction-event-report.md) mutation is used to report an event that happened for a given transaction. The report is a success charge action, with 20 as an amount. The currency is the same as declared for the transaction. Available action that can proceed for a transaction is `REFUND`. The provided data will be used to create a new [TransactionEvent](/api-reference/payments/objects/transaction-event.md) object that will be included in the recalculation process.

**Mutation**

```graphql
mutation TransactionEventReport($amount: PositiveDecimal, $availableActions: [TransactionActionEnum!], $externalUrl: String, $id: ID, $message: String, $pspReference: String!, $time: DateTime, $type: TransactionEventTypeEnum!) {
  transactionEventReport(
    id: $id
    type: $type
    amount: $amount
    pspReference: $pspReference
    time: $time
    externalUrl: $externalUrl
    message: $message
    availableActions: $availableActions
  ) {
    errors {
      field
      code
    }
    alreadyProcessed
    transaction {
      id
    }
    transactionEvent {
      id
    }
  }
}
```

**Variables**

```json
{
  "id": "VHJhbnNhY3Rpb25JdGVtOjE=",
  "type": "CHARGE_SUCCESS",
  "amount": 20,
  "pspReference": "psp-123",
  "time": "2022-01-01",
  "externalUrl": "https://saleor.io/event-details/123",
  "message": "Charge completed",
  "availableActions": [
    "REFUND"
  ]
}
```

In the response, Saleor returns:

-   `alreadyProcessed` - Defines if the reported event hasn't been processed earlier. If there is an event with the same `pspReference`, `amount`, and `type` as the ones provided in the input mutation, Saleor will return it instead of creating a new one, and the flag will be set to `true`.

danger

Saleor will throw an exception if events cannot be deduplicated in following cases:

-   **Other event has the same `pspReference` but different amount**: [`INCORRECT_DETAILS`](/api-reference/payments/enums/transaction-event-report-error-code.md#incorrect-details) error will be raised
-   **`AUTHORIZATION_SUCCESS` event already exists with different `amount` or with different `pspReference`**: [`ALREADY_EXISTS`](/api-reference/payments/enums/transaction-event-report-error-code.md#already-exists) error will be raised

-   `transaction` - Transaction that has been updated based on the received report.
-   `transactionEvent` - [TransactionEvent](/api-reference/payments/objects/transaction-event.md) that has been created based on the received report.

<a id="amount-calculations-for-reporting-an-action-with-missing-amount-value"></a>

#### Amount calculations for reporting an action with missing amount value

The `amount` value is required for the following event `type`s:

-   [`AUTHORIZATION_SUCCESS`](/api-reference/payments/enums/transaction-event-type-enum.md#authorization-success),
-   [`AUTHORIZATION_ADJUSTMENT`](/api-reference/payments/enums/transaction-event-type-enum.md#authorization-adjustment),
-   [`AUTHORIZATION_REQUEST`](/api-reference/payments/enums/transaction-event-type-enum.md#authorization-request),
-   [`CHARGE_ACTION_REQUIRED`](/api-reference/payments/enums/transaction-event-type-enum.md#charge-action-required),
-   [`CHARGE_SUCCESS`](/api-reference/payments/enums/transaction-event-type-enum.md#charge-success),
-   [`CHARGE_REQUEST`](/api-reference/payments/enums/transaction-event-type-enum.md#charge-request),
-   [`REFUND_SUCCESS`](/api-reference/payments/enums/transaction-event-type-enum.md#refund-success),
-   [`REFUND_REQUEST`](/api-reference/payments/enums/transaction-event-type-enum.md#refund-request),
-   [`CANCEL_SUCCESS`](/api-reference/payments/enums/transaction-event-type-enum.md#cancel-success),
-   [`CANCEL_REQUEST`](/api-reference/payments/enums/transaction-event-type-enum.md#cancel-request).

It's optional for the rest of the events. In case of missing `amount` value the following rules are used to calculate the `amount`:

-   In case of missing amount for event `INFO`, the 0 is used.
-   In case of missing amount for all `*_FAILURE`, the amount is taken from the corresponding `*_SUCCESS` or `*_REQUEST` event with the same `pspReference`. In case of multiple events, the value from the newest event is taken:
    -   for `REFUND_FAILURE` the `amount` is taken from the newest event of one of the following types: `REFUND_SUCCESS`, `REFUND_REQUEST`, `CHARGE_SUCCESS`, `CHARGE_FAILURE`, `CHARGE_REQUEST`;
    -   for `CHARGE_FAILURE` the `amount` is taken from the newest event of one of the following types: `CHARGE_SUCCESS`, `CHARGE_REQUEST`, `AUTHORIZATION_SUCCESS`, `AUTHORIZATION_FAILURE`, `AUTHORIZATION_REQUEST`;
    -   for `AUTHORIZATION_FAILURE` the `amount` is taken from the newest event of one of the following types: `AUTHORIZATION_SUCCESS`, `AUTHORIZATION_REQUEST`;
    -   for `CANCEL_FAILURE` the `amount` is taken from the newest event of one of the following types: `CANCEL_SUCCESS`, `CANCEL_REQUEST`, `AUTHORIZATION_SUCCESS`, `AUTHORIZATION_FAILURE`, `AUTHORIZATION_REQUEST`.
-   In case of `REFUND_REVERSE` the `amount` is taken from the `REFUND_SUCCESS` event with the same `pspReference`.
-   In case of `CHARGEBACK` the `amount` is taken from the `CHARGE_SUCCESS` event with the same `pspReference`.
-   If the specific event for the pspReference doesn't exist, the error will be raised.

<a id="events-not-requiring-pspreference"></a>

#### Events Not Requiring pspReference

The following events do not require a `pspReference`:

-   `CHARGE_ACTION_REQUIRED`
-   `AUTHORIZATION_ACTION_REQUIRED`
-   `CHARGE_FAILURE`
-   `AUTHORIZATION_FAILURE`
-   `REFUND_FAILURE`
-   `CANCEL_FAILURE`

If the `pspReference` is missing, the event will still be created but will be excluded from transaction amount recalculations. Consequently, it will not impact the `charge`, `refund`, `cancel`, or `authorize` amounts. Additionally, it will not affect any existing `transactionEvent` of the same type that has a `pspReference` set.

<a id="handling-action-requests-for-transactions"></a>

### Handling action requests for transactions

An action request is called when a staff user or an app requests an action for a given transaction.

Two mutations can trigger the action on the app side:

-   [`transactionRequestAction`](/api-reference/payments/mutations/transaction-request-action.md): will also create a new [`TransactionEvent`](/api-reference/payments/objects/transaction-event.md) with one of the request type ([`AUTHORIZATION_REQUEST`](/api-reference/payments/enums/transaction-event-type-enum.md#authorization-request), [`CHARGE_REQUEST`](/api-reference/payments/enums/transaction-event-type-enum.md#charge-request), [`REFUND_REQUEST`](/api-reference/payments/enums/transaction-event-type-enum.md#refund-request), [`CANCEL_REQUEST`](/api-reference/payments/enums/transaction-event-type-enum.md#cancel-request)), `amount` and the `owner` (User or App). Saleor will send a synchronous webhook dedicated to the action [`TRANSACTION_CHARGE_REQUESTED`](/api-reference/webhooks/enums/webhook-event-type-sync-enum.md#transaction-charge-requested), [`TRANSACTION_CANCELATION_REQUESTED`](/api-reference/webhooks/enums/webhook-event-type-sync-enum.md#transaction-cancelation-requested), [`TRANSACTION_REFUND_REQUESTED`](/api-reference/webhooks/enums/webhook-event-type-sync-enum.md#transaction-refund-requested)
    
-   [`transactionRequestRefundForGrantedRefund`](/api-reference/payments/mutations/transaction-request-refund-for-granted-refund.md): will create a new [`TransactionEvent`](/api-reference/payments/objects/transaction-event.md) with [`REFUND_REQUEST`](/api-reference/payments/enums/transaction-event-type-enum.md#refund-request) type, `amount` and the `owner` (User or App). Saleor will send a synchronous webhook [`TRANSACTION_REFUND_REQUESTED`](/api-reference/webhooks/enums/webhook-event-type-sync-enum.md#transaction-refund-requested). [`OrderGrantedRefund`](/api-reference/orders/objects/order-granted-refund.md) will be included in the webhook payload (if requested in a [subscription query](/developer/extending/webhooks/subscription-webhook-payloads.md#custom-payloads) for the webhook). This mutation is useful when the payment provider requires details about lines that are related to refund action.
    

The response should contain at least `pspReference` of the action. The `pspReference` will be placed in the previously created event of `…_REQUEST` type. Optionally the response can contain the details of the completed action.

More information about request webhooks can be found [in the synchronous webhooks for transactions guide](/developer/extending/webhooks/synchronous-events/transaction.md).

note

The webhook will be sent only to the app that created the transaction.

<a id="asynchronously-processing-actions"></a>

#### Asynchronously processing actions

When action is processed asynchronously on the payment provider side, the app should call the [`transactionActionRequest`](/api-reference/payments/mutations/transaction-request-action.md) mutation once it receives a webhook notification from the payment provider.

The diagram below shows an example of processing asynchronous refund action.

```mermaid
sequenceDiagram
   Staff ->>+ Saleor: Request refund<br>[transactionActionRequest]
   Saleor ->> Saleor: Create REQUEST event for transaction
   Saleor ->> Saleor: Schedule transaction action webhook
   Saleor -->>- Staff: Requested
   Note over Saleor,App: Background task
   Saleor -->>+ App: Send transaction-refund-requested <br>webhook
   App ->>+ PaymentProvider: Request refund
   PaymentProvider -->>- App: Processing refund
   App -->>- Saleor: PSP reference
   Note over Saleor,PaymentProvider: Async notification
   PaymentProvider -)+ App: Refund processed
   App ->>+ Saleor: Call transactionEventReport <br>mutation with all details<br> of completed action
   Saleor ->> Saleor: Update transaction amounts
   Saleor -->>- App: Updated
   App --)- PaymentProvider: OK
```

<a id="synchronously-processing-the-action"></a>

#### Synchronously processing the action

The app immediately receives the status of the requested action. It can provide the details of the action in response to the received Saleor webhook. The following webhook events can accept action details in the response: [`TRANSACTION_CHARGE_REQUESTED`](/api-reference/webhooks/enums/webhook-event-type-sync-enum.md#transaction-charge-requested), [`TRANSACTION_CANCELATION_REQUESTED`](/api-reference/webhooks/enums/webhook-event-type-sync-enum.md#transaction-cancelation-requested), [`TRANSACTION_REFUND_REQUESTED`](/api-reference/webhooks/enums/webhook-event-type-sync-enum.md#transaction-refund-requested).

The below diagram shows an example of processing synchronous refund action.

```mermaid
sequenceDiagram
    Staff ->>+ Saleor: Request refund<br>[transactionActionRequest]
    Saleor ->> Saleor: Create REQUEST event for transaction
    Saleor ->> Saleor: Schedule transaction action webhook
    Saleor -->>- Staff: Requested
    Note over Saleor,App: Background task
    Saleor ->>+ App: Send transaction-refund-requested <br>webhook
    App ->>+ PaymentProvider: Request refund
    PaymentProvider -->>- App: Refunded
    App -->>- Saleor: Return PSP<br> Reference and details<br> about completed action
    Saleor ->> Saleor: Update transaction amounts
```

<a id="transactionitem-and--transactionevents-pspreference-matching"></a>

### TransactionItem and TransactionEvents pspReference Matching

Both [TransactionItem](/api-reference/payments/objects/transaction-item.md) and [TransactionEvent](/api-reference/payments/objects/transaction-event.md) contain a `pspReference` field, which refers to the payment service provider reference.

-   The `pspReference` on `TransactionItem` identifies the overall payment.
-   The `pspReference` on `TransactionEvent` identifies specific actions that occurred within the `Transaction`.

**Key Assumptions:**

-   For a specific `TransactionItem`, only one `TransactionEvent` of a given `type` and `pspReference` may exist, except for the following types:
    -   [`AUTHORIZATION_ACTION_REQUIRED`](/developer/payments/lifecycle.md#authorization_action_required)
    -   [`CHARGE_ACTION_REQUIRED`](/developer/payments/lifecycle.md#charge_action_required)
    -   [`INFO`](/developer/payments/lifecycle.md#info)
-   Only one `TransactionEvent` of type `AUTHORIZATION_SUCCESS` is allowed to exist. If an update is needed, the existing `AUTHORIZATION_SUCCESS` event can be modified using the [`AUTHORIZATION_ADJUSTMENT`](/developer/payments/lifecycle.md#authorization_adjustment) event.

<a id="setting-the-pspreference-on-the-transactionitem"></a>

#### Setting the `pspReference` on the `TransactionItem`

The `pspReference` value in a `TransactionItem` may initially be empty if it is not provided during the `TransactionCreate` mutation or as a result of the `TransactionInitialize` mutation.

The `transactionItem.pspReference` is updated during payment processing and reflects the `pspReference` from the most recent event received from the payment application. For example: • If a transaction is successful, the `pspReference` will be set based on the last `SUCCESS` event from the payment provider. • If the event sequence changes or multiple events are received, the `pspReference` always represents the value from the latest processed event.

The `pspReference` can be updated through the `transactionUpdate` mutation if necessary.

<a id="events-with-optional-pspreference"></a>

#### Events with optional `pspReference`

Certain event types do not require a pspReference. For more details, see [Events Not Requiring pspReference](#events-not-requiring-pspreference).

<a id="handling-transactionevent-reports-for-existing-types"></a>

#### Handling TransactionEvent Reports for Existing Types

When a `TransactionEvent` is reported:

1.  **Event Type Check:** If the event type is `AUTHORIZATION_ACTION_REQUIRED`, `CHARGE_ACTION_REQUIRED`, or `INFO`, a new event is always created.
2.  **Existing Event Check:** For other types, the system searches for an existing event with the same `type` and `pspReference` assigned to the `TransactionItem` requested in the input.
    -   **Amount Match:** If an existing event is found, the system compares its amount to the reported event’s amount.
        -   If the amounts match, the existing event is reused, and the `transactionEvent.alreadyProcessed` value is set to `True`. For more information about this field, refer to the [Reporting actions for transactions](#reporting-actions-for-transactions).
        -   If they do not match, an error is raised.
    -   **No Existing Event:** If no matching event is found, a new one is created, except for `AUTHORIZATION_SUCCESS`, which must be unique, attempting to create a duplicate raises an error.

```mermaid
flowchart TD
    A[TransactionEvent report] --> B{
      The event type is
      AUTHORIZATION_ACTION_REQUIRED,
      CHARGE_ACTION_REQUIRED, or INFO}
    B -->|YES| D[Create a new event]
    B -->|NO| E{
      The event with provided
      pspReference and type
      already exist}
    E -->|YES| F{
      The provided amount
      match the existing
      event amount}
    E -->|NO| G{
      The event type
      is AUTHORIZE_SUCCESS
      }
    G --> |NO| D
    G --> |YES| H[Raise an error]
    F --> |YES| I[Return an existing event]
    F --> |NO|H
```

<a id="storing-payment-method-details"></a>

### Storing payment method details

Saleor allows storing two types of payment method details:

-   `CARD`
-   `OTHER`

These details are available on the `TransactionItem.paymentMethodDetails` field.

Payment method details can be stored in two ways:

-   Via Transaction Webhooks
-   Via Transaction Mutations

<a id="via-transaction-webhooks"></a>

#### Via transaction webhooks

Apps can return `paymentMethodDetails` while processing payments using the following webhooks:

-   `TRANSACTION_INITIALIZE_SESSION`
-   `TRANSACTION_PROCESS_SESSION`

[View details about saving via webhook](/developer/extending/webhooks/synchronous-events/transaction.md#response-4)

<a id="via-transaction-mutations"></a>

#### Via transaction mutations

The following mutations accept a `paymentMethodDetails` input field:

-   `transactionEventReport`
-   `transactionCreate`
-   `transactionUpdate`

<a id="examples"></a>

#### Examples

Example: Storing `card` details via `transactionEventReport`:

**Mutation**

```graphql
mutation TransactionEventReport($amount: PositiveDecimal, $availableActions: [TransactionActionEnum!], $id: ID, $pspReference: String!, $type: TransactionEventTypeEnum!, $paymentMethodDetails: PaymentMethodDetailsInput) {
  transactionEventReport(
    id: $id
    type: $type
    amount: $amount
    pspReference: $pspReference
    availableActions: $availableActions
    paymentMethodDetails: $paymentMethodDetails
  ) {
    errors {
      field
      code
    }
    alreadyProcessed
    transaction {
      id
    }
    transactionEvent {
      id
    }
  }
}
```

**Variables**

```json
{
  "id": "VHJhbnNhY3Rpb25JdGVtOjE=",
  "type": "CHARGE_SUCCESS",
  "amount": 20,
  "pspReference": "psp-123",
  "paymentMethodDetails": {
    "card": {
      "name": "Payment name",
      "brand": "BRAND",
      "firstDigits": "1234",
      "lastDigits": "4321",
      "expMonth": 11,
      "expYear": 2000
    }
  }
}
```

Example: Storing non-card (`other`) details via `transactionEventReport`:

**Mutation**

```graphql
mutation TransactionEventReport($amount: PositiveDecimal, $id: ID, $pspReference: String!, $type: TransactionEventTypeEnum!, $paymentMethodDetails: PaymentMethodDetailsInput) {
  transactionEventReport(
    id: $id
    type: $type
    amount: $amount
    pspReference: $pspReference
    paymentMethodDetails: $paymentMethodDetails
  ) {
    errors {
      field
      code
    }
    alreadyProcessed
    transaction {
      id
    }
    transactionEvent {
      id
    }
  }
}
```

**Variables**

```json
{
  "id": "VHJhbnNhY3Rpb25JdGVtOjE=",
  "type": "CHARGE_SUCCESS",
  "amount": 20,
  "pspReference": "psp-123",
  "paymentMethodDetails": {
    "other": {
      "name": "Cash"
    }
  }
}
```

<a id="recognized-payment-method-brands"></a>

#### Recognized payment method brands

When payment method details include a recognized `brand` value, the Saleor Dashboard will display the corresponding brand logo alongside the transaction. Brand matching is **case-insensitive**.

**Card payment methods** (`CARD` type — `brand` field):

-   `visa`,
-   `mastercard`, `mc`
-   `american_express`
-   `amex`
-   `discover`
-   `jcb`
-   `diners_club`
-   `unionpay`
-   `maestro`
-   `givex`

**Other payment methods** (`OTHER` type — `name` field):

To check all available logos, check [this list](https://github.com/saleor/saleor-dashboard/tree/main/public/payment-methods). Integration should return brand matching file name without extension (e.g. `braintree` will load `braintree.svg` file).

For any other value, the Dashboard will display a generic payment method name.

tip

To get brand logos in the Dashboard, make sure to pass one of the recognized values listed above when reporting transaction events via webhooks or mutations.

<a id="showing-payment-history-to-the-customer"></a>

### Showing payment history to the customer

Added in Saleor 3.23.

`Order.transactions` requires the `MANAGE_ORDERS` or `HANDLE_PAYMENTS` permission, so a storefront cannot use it to tell the customer how their order was paid. Use `Order.transactionSummaries` instead: it is meant for storefronts that display the payment history of an order, for example on an order confirmation page or in the customer's account.

The field requires no permission. Like `billingAddress` or `userEmail`, it is available to whoever can read the order.

Each entry is a `TransactionSummary` - a read-only projection of one transaction that exposes only:

-   `createdAt` - when the transaction was created.
-   `paymentMethodDetails` - the payment method, using the same [`PaymentMethodDetails`](/api-reference/miscellaneous/interfaces/payment-method-details.md) types as `TransactionItem`.
-   `authorizedAmount`, `authorizePendingAmount`, `chargedAmount`, `chargePendingAmount`, `refundedAmount`, `canceledAmount` - the money that moved.

**Query**

```graphql
query OrderPaymentHistory($id: ID!) {
  order(id: $id) {
    number
    transactionSummaries {
      createdAt
      paymentMethodDetails {
        name
        ... on CardPaymentMethodDetails {
          brand
        }
      }
      chargedAmount {
        amount
        currency
      }
      refundedAmount {
        amount
        currency
      }
    }
  }
}
```

**Response**

```json
{
  "data": {
    "order": {
      "number": "123",
      "transactionSummaries": [
        {
          "createdAt": "2025-09-01T10:15:30+00:00",
          "paymentMethodDetails": {
            "name": "Credit card",
            "brand": "visa"
          },
          "chargedAmount": { "amount": 99.0, "currency": "USD" },
          "refundedAmount": { "amount": 0.0, "currency": "USD" }
        }
      ]
    }
  }
}
```

Two things are deliberately hidden from this field:

-   **Card digits and expiration date.** `firstDigits`, `lastDigits`, `expMonth` and `expYear` of `CardPaymentMethodDetails` are always `null` here. The customer sees the payment method and the brand, and nothing that identifies the instrument. Staff and apps read the full card data through `Order.transactions` as before.
-   **Transactions that moved no money.** A transaction whose amounts are all zero is an abandoned payment attempt. It carries no information for the customer, so it is not returned.

`TransactionSummary` also has no `id`, no `events`, no `externalUrl` and no available actions. If you need any of those, query `Order.transactions` with the required permission.

<a id="webhooks"></a>

### Webhooks

Follow [Transactions Webhook Events](/developer/extending/webhooks/synchronous-events/transaction.md) guide.

<a id="automatic-checkout-completion"></a>

### Automatic Checkout Completion

The `Checkout` can be automatically converted into an [`Order`](/api-reference/orders/objects/order.md) once the related [`TransactionItems`](/api-reference/payments/objects/transaction-item.md) fully cover the `Checkout`.

A checkout is considered fully covered when the [`Checkout.authorizeStatus`](/developer/payments/lifecycle.md#authorize-status) is set to `FULL`. This occurs when the total of `authorizedAmount`, `chargedAmount`, `authorizePendingAmount`, and `chargePendingAmount` from all transactions connected to the `Checkout` covers the [`checkout.totalPrice`](/api-reference/checkout/objects/checkout.md#total-price).

note

**Added in Saleor 3.20:** Basic automatic completion with boolean flag `automaticallyCompleteFullyPaidCheckouts`

**Enhanced in Saleor 3.22:** Added `automaticCompletion` input with `delay` and `cutOffDate` configuration options. The old boolean flag is deprecated but still functional. See the [3.21 to 3.22 upgrade guide](/upgrade-guides/core/3-21-to-3-22.md#automatic-checkout-completion-behavior-change-for-checkouts-with-total-being-0) for more details.

caution

This feature isn't compatible with [legacy Payments API](/developer/extending/plugins/payment-gateways.md) that uses [plugins](/developer/extending/plugins/overview.md) (instead of apps). For example this setting won't work with [Stripe plugin](/developer/app-store/legacy-plugins/stripe.md).

Payments API uses `checkoutComplete` mutation to pass payment data to a plugin and return payment status, thanks to this `Order` is always created right after such payment is made. **This means that this setting doesn't impact Payments API**.

info

Automatic checkout completion is managed by a scheduled task that runs every minute. During each run, up to 20 checkouts are processed. The system prioritizes:

1.  Checkouts that have never had an automatic completion attempt, prioritized by the oldest `updatedAt` timestamp.
2.  Checkouts that have already had an automatic completion attempt, processed in order of the oldest attempt first.

Checkouts modified more than 30 days ago are excluded from automatic completion.

To enable the feature, adjust the channel checkout settings. The `automaticCompletion` field in `CheckoutSettingsInput` provides the following options for configuring automatic checkout completion:

-   **`enabled`**: A boolean value to enable or disable automatic checkout completion. When set to `true`, the system will attempt to complete checkouts automatically once they are fully covered.
-   **`delay`**: An optional integer value (in minutes) that specifies the delay from last update before a checkout is automatically completed. If not provided, the default delay is 30 minutes.
-   **`cutOffDate`**: An optional ISO 8601 timestamp that defines the earliest checkout creation time eligible for automatic completion. Checkouts created before this date will not be automatically completed. If not provided, the current time is used as the default.

<a id="configuring-automatic-checkout-completion"></a>

#### Configuring automatic checkout completion

Use the `automaticCompletion` field to configure when checkouts should be automatically completed. The `cutOffDate` parameter allows you to safely enable this feature for new checkouts only, without affecting existing ones.

**Mutation**

```graphql
mutation UpdateChannel($id: ID!,$input: ChannelUpdateInput!){
  channelUpdate(id: $id, input: $input){
    channel{
      id
      checkoutSettings {
        automaticCompletionDelay
        automaticCompletionCutOffDate
      }
    }
    errors{
      field
      code
      message
    }
  }
}
```

**Variables**

```json
{
  "id": "Q2hhbm5lbDox",
  "input": {
    "checkoutSettings": {
        "automaticCompletion": {
          "enabled": true,
          "delay": 120,
          "cutOffDate": "2025-11-01T00:00:00Z"
        }
      }
  }
}
```

Safe rollout

Use `cutOffDate` set to the current date/time when first enabling this feature. This ensures only newly created checkouts will be automatically completed, allowing you to verify your storefront handles the flow correctly before applying it to all checkouts.

<a id="important-behavior-notes"></a>

#### Important behavior notes

**Checkout validation:** Checkouts will not be automatically completed if validation issues occur. Use the `Checkout.problems` query to identify issues. Common validation problems include:

-   Unavailable items (missing product/variant listings, unavailable products, hidden products)
-   Missing billing address
-   Invalid voucher or gift card
-   Invalid shipping method
-   Inactive channel

See the [Checkout Problems page](/developer/checkout/problems.md) for details.

**Checkout lifecycle:** Once a checkout is automatically completed:

-   The `Checkout` object is deleted and queries/mutations on it will no longer work
-   Running `checkoutComplete` on an already completed checkout returns the previously created `Order`
-   Ensure your storefront handles this flow correctly before enabling

**Pending transactions:** Checkouts are automatically completed when `authorizeStatus` reaches `FULL`, even if some transactions are still pending confirmation from the payment provider. A pending transaction might be rejected later, resulting in an unpaid order. Use [Order Expiration](/developer/order/order-expiration.md) to handle unpaid orders.

info

When testing this feature, use the `cutOffDate` parameter to limit automatic completion to new checkouts only. This allows you to verify your integration works correctly before enabling it for all checkouts.

caution

Once `Checkout` is converted to into `Order`, the `authorizeStatus` might change from `FULL` to `NONE` or `PARTIAL`. This happens because [`Order.authorizeStatus`](/api-reference/orders/enums/order-authorize-status-enum.md#values) uses different logic to calculate its value.

-   **For checkouts**: pending Transactions **are** considered "paid" and are included in the [`Checkout.authorizeStatus`](/api-reference/checkout/enums/checkout-authorize-status-enum.md) calculation.
-   **For orders**: pending Transactions **are not** considered "paid" and will not be included in the [`Order.authorizeStatus`](/api-reference/orders/enums/order-authorize-status-enum.md#values) calculation.

<a id="related-resources"></a>

## Related Resources

-   [Building Payment Apps](/developer/extending/apps/building-payment-app.md)
