> ## Documentation Index
> Fetch the complete documentation index at: https://docs.synapsebuilder.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Payment Customization

> Customize payment methods with Shopify Functions

## Overview

Payment Customization Functions let you show, hide, or reorder payment methods based on cart contents, customer data, or other conditions.

## Use Cases

<CardGroup cols={2}>
  <Card title="Hide Payment Methods" icon="eye-slash">
    Remove options based on conditions

    * Hide COD for high-value orders
    * Remove Buy Now Pay Later for B2B
    * Restrict payment by location
  </Card>

  <Card title="Reorder Methods" icon="arrows-up-down">
    Change payment method order

    * Promote preferred methods
    * Push expensive methods down
    * Prioritize by customer segment
  </Card>

  <Card title="Rename Methods" icon="tag">
    Customize payment method names

    * Add processing fees
    * Show savings
    * Clarify payment terms
  </Card>

  <Card title="Conditional Display" icon="filter">
    Complex payment logic

    * VIP payment methods
    * Location-based options
    * Cart value restrictions
  </Card>
</CardGroup>

## How It Works

<Steps>
  <Step title="Checkout Loads">
    Customer reaches payment method selection in checkout
  </Step>

  <Step title="Function Executes">
    Your function receives cart data and available payment methods
  </Step>

  <Step title="Methods Customized">
    Function returns which methods to show/hide and their order
  </Step>

  <Step title="Checkout Updates">
    Payment method list updates based on function output
  </Step>
</Steps>

## Example: Hide COD for High-Value Orders

Generate a function that hides cash on delivery for expensive orders:

<Steps>
  <Step title="Describe Your Function">
    ```
    Create a payment customization function that hides the 
    "Cash on Delivery" payment method when the cart total 
    is over $200. For orders under $200, show all payment 
    methods as normal.
    ```
  </Step>

  <Step title="Review Generated Code">
    Synapse creates:

    * Function logic (Rust or JavaScript)
    * Input query for cart and payment data
    * Customization rules
    * Configuration
  </Step>

  <Step title="Deploy & Test">
    * Automatic validation
    * Deployed to dev store
    * Test with different cart totals
  </Step>

  <Step title="Activate Function">
    Payment functions are automatically active once deployed
  </Step>
</Steps>

## Generated Function Structure

```
extensions/payment-customization/
├── src/
│   ├── run.rs                 # Function logic (Rust)
│   │   OR
│   ├── run.js                 # Function logic (JS)
│   └── run.graphql           # Input query
├── shopify.extension.toml     # Config
└── Cargo.toml / package.json
```

## Function Code Examples

<Tabs>
  <Tab title="Hide COD (Rust)">
    ```rust theme={null}
    use shopify_function::prelude::*;
    use shopify_function::Result;

    #[shopify_function_target(
        query_path = "src/run.graphql",
        schema_path = "schema.graphql"
    )]
    fn run(input: input::ResponseData) -> Result<output::FunctionRunResult> {
        // Calculate cart total
        let cart_total: f64 = input
            .cart
            .cost
            .subtotal_amount
            .amount
            .parse()
            .unwrap_or(0.0);
        
        // Find COD payment method
        let operations = input
            .payment_methods
            .iter()
            .filter_map(|method| {
                // Check if this is Cash on Delivery
                if method.name.to_lowercase().contains("cash") {
                    // Hide if cart over $200
                    if cart_total > 200.0 {
                        return Some(output::Operation::Hide(output::HideOperation {
                            payment_method_id: method.id.clone(),
                        }));
                    }
                }
                None
            })
            .collect();
        
        Ok(output::FunctionRunResult {
            operations,
        })
    }
    ```
  </Tab>

  <Tab title="Reorder Methods (JavaScript)">
    ```javascript theme={null}
    export function run(input) {
      const isVIP = input.cart.buyerIdentity?.customer?.hasTag?.('vip') || false;
      
      const operations = [];
      
      // Find preferred payment method
      const preferredMethod = input.paymentMethods.find(
        method => method.name.includes('Express Checkout')
      );
      
      if (isVIP && preferredMethod) {
        // Move to top for VIP customers
        operations.push({
          move: {
            paymentMethodId: preferredMethod.id,
            index: 0
          }
        });
      }
      
      return { operations };
    }
    ```
  </Tab>

  <Tab title="Rename Method">
    ```rust theme={null}
    // Add fee to payment method name
    let operations = input
        .payment_methods
        .iter()
        .filter_map(|method| {
            if method.name.contains("Credit Card") {
                Some(output::Operation::Rename(output::RenameOperation {
                    payment_method_id: method.id.clone(),
                    name: format!("{} (+3% fee)", method.name),
                }))
            } else {
                None
            }
        })
        .collect();
    ```
  </Tab>

  <Tab title="Input Query">
    ```graphql theme={null}
    query RunInput {
      cart {
        cost {
          subtotalAmount {
            amount
          }
        }
        buyerIdentity {
          customer {
            id
            hasTags(tags: ["vip", "wholesale"])
          }
        }
      }
      paymentMethods {
        id
        name
      }
    }
    ```
  </Tab>
</Tabs>

## Common Patterns

<AccordionGroup>
  <Accordion title="Cart Value Restrictions" icon="dollar-sign">
    Show/hide payment methods based on order total:

    ```rust theme={null}
    let cart_total: f64 = input.cart.cost.subtotal_amount.amount
        .parse()
        .unwrap_or(0.0);

    let operations = input.payment_methods
        .iter()
        .filter_map(|method| {
            match method.name.as_str() {
                "Cash on Delivery" if cart_total > 200.0 => {
                    Some(Operation::Hide(HideOperation {
                        payment_method_id: method.id.clone(),
                    }))
                },
                "Buy Now Pay Later" if cart_total < 50.0 => {
                    Some(Operation::Hide(HideOperation {
                        payment_method_id: method.id.clone(),
                    }))
                },
                _ => None,
            }
        })
        .collect();
    ```

    **Prompt Example:**

    ```
    "Hide Cash on Delivery for orders over $200. Hide Buy Now Pay 
    Later for orders under $50. Show all other payment methods."
    ```
  </Accordion>

  <Accordion title="Customer Segment Restrictions" icon="users">
    Different payment methods for different customers:

    ```rust theme={null}
    let is_wholesale = input.cart.buyer_identity
        .as_ref()
        .and_then(|identity| identity.customer.as_ref())
        .map(|customer| customer.has_tags(vec!["wholesale"]))
        .unwrap_or(false);

    if is_wholesale {
        // Only show Net 30 for wholesale customers
        let operations = input.payment_methods
            .iter()
            .filter_map(|method| {
                if !method.name.contains("Net 30") {
                    Some(Operation::Hide(HideOperation {
                        payment_method_id: method.id.clone(),
                    }))
                } else {
                    None
                }
            })
            .collect();
    }
    ```

    **Prompt Example:**

    ```
    "For customers tagged 'wholesale', only show the Net 30 payment 
    option. Hide all other payment methods for wholesale customers."
    ```
  </Accordion>

  <Accordion title="Product-Based Restrictions" icon="box">
    Payment restrictions based on cart contents:

    ```rust theme={null}
    let has_restricted_product = input.cart.lines
        .iter()
        .any(|line| {
            line.merchandise.product.has_tags(vec!["restricted"])
        });

    if has_restricted_product {
        // No COD for restricted products
        let operations = input.payment_methods
            .iter()
            .filter_map(|method| {
                if method.name.contains("Cash on Delivery") {
                    Some(Operation::Hide(HideOperation {
                        payment_method_id: method.id.clone(),
                    }))
                } else {
                    None
                }
            })
            .collect();
    }
    ```

    **Prompt Example:**

    ```
    "If cart contains any products tagged 'high-value', hide Cash 
    on Delivery and Buy Now Pay Later options. Only allow credit 
    card payments."
    ```
  </Accordion>

  <Accordion title="Location-Based Restrictions" icon="location-dot">
    Different payment options by shipping address:

    ```rust theme={null}
    let country = input.cart.delivery_address
        .as_ref()
        .map(|addr| addr.country_code.as_str())
        .unwrap_or("");

    let operations = input.payment_methods
        .iter()
        .filter_map(|method| {
            match (country, method.name.as_str()) {
                ("IN", name) if name.contains("Cash on Delivery") => None,
                (_, "Cash on Delivery") => {
                    Some(Operation::Hide(HideOperation {
                        payment_method_id: method.id.clone(),
                    }))
                },
                _ => None,
            }
        })
        .collect();
    ```

    **Prompt Example:**

    ```
    "Only show Cash on Delivery for customers in India. Hide it 
    for all other countries."
    ```
  </Accordion>
</AccordionGroup>

## Operation Types

Payment customization functions support three operations:

<Tabs>
  <Tab title="Hide">
    Remove a payment method from the list:

    ```rust theme={null}
    Operation::Hide(HideOperation {
        payment_method_id: method.id.clone(),
    })
    ```

    Use when:

    * Payment method not allowed
    * Condition not met
    * Customer segment restriction
  </Tab>

  <Tab title="Move">
    Change payment method position:

    ```rust theme={null}
    Operation::Move(MoveOperation {
        payment_method_id: method.id.clone(),
        index: 0, // Move to top
    })
    ```

    Use when:

    * Promoting preferred methods
    * Prioritizing by customer
    * Ordering by fee
  </Tab>

  <Tab title="Rename">
    Update payment method display name:

    ```rust theme={null}
    Operation::Rename(RenameOperation {
        payment_method_id: method.id.clone(),
        name: format!("{} (2.9% + 30¢)", method.name),
    })
    ```

    Use when:

    * Showing processing fees
    * Adding clarifications
    * Displaying savings
  </Tab>
</Tabs>

## Testing Payment Functions

<Steps>
  <Step title="Test in Checkout">
    1. Add items to cart
    2. Go to checkout
    3. Proceed to payment methods
    4. Verify correct methods appear
  </Step>

  <Step title="Test Different Scenarios">
    * Different cart values
    * Various customer types
    * Multiple product combinations
    * Different shipping addresses
  </Step>

  <Step title="Check Function Logs">
    ```bash theme={null}
    shopify app function logs
    ```

    View function input/output
  </Step>

  <Step title="Verify Performance">
    * Functions should execute in under 5ms
    * Test with many payment methods
    * Check with large carts
  </Step>
</Steps>

## Best Practices

<CardGroup cols={2}>
  <Card title="Always Show Some Method" icon="exclamation-triangle">
    Never hide all payment methods

    ```rust theme={null}
    // Ensure at least one method remains
    let visible_count = input.payment_methods.len() 
        - hide_operations.len();

    if visible_count == 0 {
        // Don't hide everything
        return Ok(FunctionRunResult {
            operations: vec![],
        });
    }
    ```
  </Card>

  <Card title="Clear Naming" icon="text">
    Make renamed methods descriptive

    ```rust theme={null}
    // Good: Clear fee structure
    name: "Credit Card (3% fee)"

    // Bad: Vague
    name: "Credit Card (extra charge)"
    ```
  </Card>

  <Card title="Fallback Logic" icon="shield">
    Handle missing data gracefully

    ```rust theme={null}
    let cart_total = input.cart.cost.subtotal_amount.amount
        .parse::<f64>()
        .unwrap_or(0.0); // Default to 0
    ```
  </Card>

  <Card title="Performance" icon="gauge">
    Keep functions fast

    * Minimize iterations
    * Use Rust for speed
    * Cache calculations
    * Limit query surface
  </Card>
</CardGroup>

## Advanced Examples

<AccordionGroup>
  <Accordion title="Dynamic Fee Display">
    ```rust theme={null}
    let operations = input.payment_methods
        .iter()
        .map(|method| {
            let fee_percentage = match method.name.as_str() {
                name if name.contains("Credit Card") => 2.9,
                name if name.contains("PayPal") => 3.5,
                _ => 0.0,
            };
            
            if fee_percentage > 0.0 {
                let fee_amount = cart_total * (fee_percentage / 100.0);
                Operation::Rename(RenameOperation {
                    payment_method_id: method.id.clone(),
                    name: format!(
                        "{} (+${:.2} processing fee)",
                        method.name,
                        fee_amount
                    ),
                })
            } else {
                Operation::Rename(RenameOperation {
                    payment_method_id: method.id.clone(),
                    name: method.name.clone(),
                })
            }
        })
        .collect();
    ```
  </Accordion>

  <Accordion title="Prioritize by Customer Tier">
    ```rust theme={null}
    let customer_tier = input.cart.buyer_identity
        .as_ref()
        .and_then(|id| id.customer.as_ref())
        .and_then(|c| {
            if c.has_tags(vec!["tier-gold"]) { Some(3) }
            else if c.has_tags(vec!["tier-silver"]) { Some(2) }
            else if c.has_tags(vec!["tier-bronze"]) { Some(1) }
            else { Some(0) }
        })
        .unwrap_or(0);

    let mut operations = vec![];

    // Move preferred methods to top based on tier
    if customer_tier >= 2 {
        if let Some(express) = input.payment_methods.iter()
            .find(|m| m.name.contains("Express")) {
            operations.push(Operation::Move(MoveOperation {
                payment_method_id: express.id.clone(),
                index: 0,
            }));
        }
    }
    ```
  </Accordion>

  <Accordion title="Multi-Condition Logic">
    ```rust theme={null}
    let cart_total = parse_amount(&input.cart.cost.subtotal_amount.amount);
    let is_international = input.cart.delivery_address
        .as_ref()
        .map(|addr| addr.country_code != "US")
        .unwrap_or(false);
    let has_subscription = input.cart.lines.iter()
        .any(|line| line.merchandise.product.has_tags(vec!["subscription"]));

    let operations = input.payment_methods
        .iter()
        .filter_map(|method| {
            // Complex rules
            if method.name.contains("Cash on Delivery") {
                if is_international || cart_total > 200.0 || has_subscription {
                    return Some(Operation::Hide(HideOperation {
                        payment_method_id: method.id.clone(),
                    }));
                }
            }
            
            if method.name.contains("Buy Now Pay Later") {
                if cart_total < 50.0 || has_subscription {
                    return Some(Operation::Hide(HideOperation {
                        payment_method_id: method.id.clone(),
                    }));
                }
            }
            
            None
        })
        .collect();
    ```
  </Accordion>
</AccordionGroup>

## Example Prompts

<AccordionGroup>
  <Accordion title="Hide COD for International">
    ```
    Create a payment customization function that hides Cash on 
    Delivery for any orders shipping outside the United States. 
    Check the shipping address country code.
    ```
  </Accordion>

  <Accordion title="VIP Express Priority">
    ```
    For customers tagged 'vip', move the Express Checkout payment 
    method to the top of the list. Keep all other methods in their 
    default order.
    ```
  </Accordion>

  <Accordion title="Show Processing Fees">
    ```
    Rename payment methods to show processing fees: Credit Card 
    shows +2.9%, PayPal shows +3.5%, and Bank Transfer shows +'Free'. 
    Display the fee percentage after the method name.
    ```
  </Accordion>

  <Accordion title="Subscription Restrictions">
    ```
    If cart contains any products tagged 'subscription', only allow 
    Credit Card and Bank Transfer payment methods. Hide all other 
    payment options including COD and Buy Now Pay Later.
    ```
  </Accordion>
</AccordionGroup>

## Troubleshooting

<AccordionGroup>
  <Accordion title="All Methods Disappeared">
    **Cause:** Function hiding all payment methods

    **Solution:** Add safeguard to ensure at least one method remains visible
  </Accordion>

  <Accordion title="Method Not Hiding">
    **Cause:** Name matching logic incorrect

    **Solution:** Check exact payment method name, use contains() or regex
  </Accordion>

  <Accordion title="Function Not Running">
    **Cause:** Function not activated

    **Solution:** Payment functions activate automatically on deployment, check logs
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Shipping Customization" icon="truck" href="/guides/shipping-customization">
    Customize shipping rates and options
  </Card>

  <Card title="Discount Functions" icon="percent" href="/guides/discount-functions">
    Create custom discount logic
  </Card>

  <Card title="Functions Overview" icon="function" href="/essentials/functions">
    Learn about all function types
  </Card>

  <Card title="Debugging" icon="bug" href="/advanced/debugging">
    Debug and optimize functions
  </Card>
</CardGroup>
