# Rename and reorder payment methods at checkout

> A Shopify payment customization Function that renames payment methods and changes their order at checkout from a JSON metafield. Tested JavaScript.

Page: https://lintelagency.com/resources/shopify-functions/rename-and-reorder-payment-methods

## In short

This payment customization Function renames payment methods and puts them in the order you choose at checkout, for example a clearer name for bank transfer and cards first. Both come from a JSON metafield, so nothing is hardcoded. It uses the cart.payment-methods.transform.run target of the Payment Customization API, version 2026-10, with the paymentMethodRename and paymentMethodMove operations.

## Facts

- **Function API:** Payment Customization
- **Target:** cart.payment-methods.transform.run
- **Plan:** Any plan in a public app; Shopify Plus in a custom app
- **App scope:** write_payment_customizations
- **API version:** 2026-10
- **Last checked:** 2 November 2026

## How to use it

1. Create an app with the Shopify CLI, then add the extension: shopify app generate extension --template payment_customization, with JavaScript.
2. Replace the generated shopify.extension.toml and the two files in src/ with the files below.
3. Run the fixtures with shopify app function run --input tests/rename-and-reorder.input.json.
4. Deploy with shopify app deploy and create the customization with paymentCustomizationCreate.
5. Set the $app:function-configuration metafield, for example {"renames": {"Bank Deposit": "Bank transfer"}, "order": ["Credit card", "Bank Deposit"]}.

## Code

### shopify.extension.toml

```toml
api_version = "2026-10"

[[extensions]]
name = "Rename and reorder payment methods"
handle = "rename-reorder-payment-methods"
type = "function"

  [[extensions.targeting]]
  target = "cart.payment-methods.transform.run"
  input_query = "src/cart_payment_methods_transform_run.graphql"
  export = "cart-payment-methods-transform-run"

  [extensions.build]
  command = ""
  path = "dist/function.wasm"
```

### src/cart_payment_methods_transform_run.graphql

```graphql
query CartPaymentMethodsTransformRunInput {
  paymentMethods {
    id
    name
  }
  paymentCustomization {
    metafield(namespace: "$app", key: "function-configuration") {
      jsonValue
    }
  }
}
```

### src/cart_payment_methods_transform_run.js

```js
// @ts-check

/**
 * @typedef {import("../generated/api").CartPaymentMethodsTransformRunInput} CartPaymentMethodsTransformRunInput
 * @typedef {import("../generated/api").CartPaymentMethodsTransformRunResult} CartPaymentMethodsTransformRunResult
 */

/**
 * Settings stored as JSON in the customization's metafield. Both are empty by
 * default, so checkout stays unchanged until the merchant configures them.
 */
const DEFAULT_CONFIG = {
  // Current name → name shown at checkout, matched case-insensitively.
  renames: /** @type {Record<string, string>} */ ({}),
  // Names in the order they should appear; unlisted methods keep their place after them.
  order: /** @type {string[]} */ ([]),
};

/**
 * @param {CartPaymentMethodsTransformRunInput} input
 * @returns {CartPaymentMethodsTransformRunResult}
 */
export function cartPaymentMethodsTransformRun(input) {
  const config = { ...DEFAULT_CONFIG, ...input.paymentCustomization?.metafield?.jsonValue };
  const renames = new Map(Object.entries(config.renames).map(([from, to]) => [from.toLowerCase(), to]));
  /** @param {string} name */
  const findMethod = (name) =>
    input.paymentMethods.find((method) => method.name.toLowerCase() === name.toLowerCase());

  // Rename operations refer to the method's ID, so they're independent of the order below.
  const renameOperations = input.paymentMethods
    .filter((method) => renames.has(method.name.toLowerCase()))
    .map((method) => ({
      paymentMethodRename: { paymentMethodId: method.id, name: renames.get(method.name.toLowerCase()) ?? method.name },
    }));

  // Index counts only methods present in this checkout, so a configured method
  // that isn't offered (another market, an inactive gateway) leaves no gap.
  const moveOperations = config.order
    .map(findMethod)
    .filter((method) => method != null)
    .map((method, index) => ({ paymentMethodMove: { paymentMethodId: method.id, index } }));

  return { operations: [...renameOperations, ...moveOperations] };
}
```

## Test input and expected output

### tests/missing-method-skipped.input.json

```json
{
  "paymentMethods": [
    { "id": "gid://shopify/PaymentCustomizationPaymentMethod/1", "name": "Credit card" },
    { "id": "gid://shopify/PaymentCustomizationPaymentMethod/2", "name": "PayPal" },
    { "id": "gid://shopify/PaymentCustomizationPaymentMethod/3", "name": "Bank Deposit" }
  ],
  "paymentCustomization": {
    "metafield": { "jsonValue": { "order": ["Cash on Delivery (COD)", "PayPal"] } }
  }
}
```

### tests/missing-method-skipped.output.json

```json
{
  "operations": [
    { "paymentMethodMove": { "paymentMethodId": "gid://shopify/PaymentCustomizationPaymentMethod/2", "index": 0 } }
  ]
}
```

### tests/not-configured.input.json

```json
{
  "paymentMethods": [
    { "id": "gid://shopify/PaymentCustomizationPaymentMethod/1", "name": "Credit card" },
    { "id": "gid://shopify/PaymentCustomizationPaymentMethod/2", "name": "PayPal" },
    { "id": "gid://shopify/PaymentCustomizationPaymentMethod/3", "name": "Bank Deposit" }
  ],
  "paymentCustomization": { "metafield": null }
}
```

### tests/not-configured.output.json

```json
{ "operations": [] }
```

### tests/rename-and-reorder.input.json

```json
{
  "paymentMethods": [
    { "id": "gid://shopify/PaymentCustomizationPaymentMethod/1", "name": "Credit card" },
    { "id": "gid://shopify/PaymentCustomizationPaymentMethod/2", "name": "PayPal" },
    { "id": "gid://shopify/PaymentCustomizationPaymentMethod/3", "name": "Bank Deposit" }
  ],
  "paymentCustomization": {
    "metafield": {
      "jsonValue": {
        "renames": { "bank deposit": "Bank transfer (2% off, ships after payment)" },
        "order": ["Bank Deposit", "Credit card"]
      }
    }
  }
}
```

### tests/rename-and-reorder.output.json

```json
{
  "operations": [
    {
      "paymentMethodRename": {
        "paymentMethodId": "gid://shopify/PaymentCustomizationPaymentMethod/3",
        "name": "Bank transfer (2% off, ships after payment)"
      }
    },
    { "paymentMethodMove": { "paymentMethodId": "gid://shopify/PaymentCustomizationPaymentMethod/3", "index": 0 } },
    { "paymentMethodMove": { "paymentMethodId": "gid://shopify/PaymentCustomizationPaymentMethod/1", "index": 1 } }
  ]
}
```

## Limits and edge cases

- Methods whose name is a logo can’t be renamed: Shop Pay, Apple Pay, Google Pay, other wallets and the gift card field.
- Wallets can be hidden but not reordered; move operations for them have no effect.
- Names are matched as the customer sees them at checkout, ignoring case. A method listed in the configuration but not offered in this checkout is skipped.
- Inside Shop Pay, payment customizations only affect the gift card field.

## Questions

### How do I change the order of payment methods in Shopify checkout?

The payment settings don’t let you sort methods. A payment customization Function returns paymentMethodMove operations with the position for each method, which is what this example does.

### Can I rename Cash on Delivery or bank transfer?

Yes. Manual methods such as Cash on Delivery and bank deposit can be renamed with paymentMethodRename. Wallets and logo-only methods like Shop Pay can’t.

### Can the new name change by language?

This example uses one name. Add localization { language { isoCode } } to the input query and keep one renames map per language in the metafield if you sell in several languages.

## Shopify documentation

- [Payment Customization Function API](https://shopify.dev/docs/api/functions/latest/payment-customization)

## Related

- [Activate a delivery, payment or validation Function](https://lintelagency.com/resources/graphql/register-function-customization)
- [Hide Cash on Delivery above a cart total](https://lintelagency.com/resources/shopify-functions/hide-cash-on-delivery-above-cart-total)
- [Configuring Functions with metafields, so rules change without deploys](https://lintelagency.com/journal/configuring-functions-with-metafields)
- [Checkout UI extensions vs Shopify Functions](https://lintelagency.com/journal/checkout-ui-extensions-vs-shopify-functions)

License: MIT. Free to use in your own store and in client work.
