Skip to main content
This guide provides step-by-step instructions for implementing Flex as a Stripe custom payment method, with complete code examples based on a working implementation.

Overview

This implementation enables a dual-payment system where:
  • Stripe handles traditional payment methods (cards, Apple Pay, etc.) with embedded processing
  • Flex handles HSA/FSA payments with a hosted checkout redirect flow
Both payment options appear in a single Stripe Payment Element, providing a unified customer experience.

Implementation Steps

1

Create Server Actions

Server actions handle payment processing on the backend, ensuring API keys remain secure.
2

Build the Checkout Form Component

The checkout form integrates the Stripe Payment Element and handles payment routing.
3

Create Success Page

Display order confirmation after successful payment.
4

Configure Validation Schemas

Set up form validation using Zod for type safety and error handling.

1. Server Actions

Stripe Payment Intent Creation

Create a server action to generate Stripe PaymentIntents:
app/actions/stripe.ts
The automatic_payment_methods setting allows Stripe to automatically display all enabled payment methods, including cards, digital wallets, and bank transfers.

Flex Checkout Session Creation

Create a server action to generate Flex checkout sessions:
app/actions/flex.ts
The Flex integration uses a hosted checkout model, meaning customers are redirected to Flex’s domain to complete payment. Ensure your success_url and cancel_url are properly configured.

2. Checkout Form Component

The checkout form is the heart of the integration, rendering the Payment Element and routing payments appropriately.

Form Wrapper Component

components/checkout-form.tsx
The customPaymentMethods configuration registers Flex as a payment option. The type: "static" setting displays Flex as a selectable option without embedded interactive elements.

Main Checkout Form

components/checkout-form-inner.tsx

Key Implementation Details

Payment Method Detection:
The elements.submit() method returns the selected payment method ID, allowing you to route to the appropriate processor. Conditional Routing:
This pattern keeps the payment logic clean and maintainable. The form doesn’t need to know about the specifics of each payment processor—it simply routes based on selection.

3. Validation Schemas

Use Zod for type-safe form validation:
lib/schemas.ts

4. Utility Functions

Amount Formatting

Convert amounts to cents for Stripe:
lib/utils.ts

Plan Details Retrieval

Fetch plan information from your data source:
lib/utils.ts
In production, replace this with a database query or API call to fetch plan details dynamically.

5. Success Page

Display order confirmation after payment:
app/success/page.tsx
Security Note: The success page currently displays order details from URL parameters. In production, you should verify the payment status by querying the appropriate payment provider’s API before displaying the confirmation.

6. Checkout Page Integration

Create your checkout page that uses the form:
app/checkout/page.tsx

Payment Flow Diagram

Testing Your Integration

Test Mode Setup

  1. Stripe Test Mode: Use test API keys (starting with sk_test_ and pk_test_)
  2. Flex Test Mode: Ensure you’re using Flex test credentials
  3. Test Cards: Use Stripe test cards

Testing Checklist

  • Flex appears as a payment option in the Payment Element
  • Selecting Flex redirects to Flex hosted checkout
  • Selecting card payment processes inline with Stripe
  • Success page displays correct order information
  • Error messages display appropriately
  • Form validation works as expected
  • Payment confirmation emails are sent (if configured)

Common Test Scenarios

Test Stripe Payment Flow:
Test Flex Payment Flow:

Production Considerations

Security

Critical Security Practices:
  1. Never expose secret keys to the client side
  2. Always validate user input on the server
  3. Verify payment status on the success page via API calls
  4. Use HTTPS for all production traffic
  5. Implement rate limiting on payment endpoints
  6. Log security events for audit trails

Error Handling

Implement comprehensive error handling:

Webhook Integration

For production deployments, implement webhooks to handle payment events: Stripe Webhooks:
  • payment_intent.succeeded
  • payment_intent.payment_failed
  • charge.refunded
Flex Webhooks:
  • Configure in your Flex Dashboard
  • Handle success/failure events
  • Update order status in your database

Performance Optimization

  1. Lazy load Stripe.js to improve initial page load
  2. Cache plan details to reduce database queries
  3. Implement loading states for better UX
  4. Monitor payment processing times

Troubleshooting

Flex Not Appearing in Payment Element

Problem: Custom payment method doesn’t show up. Solutions:
  • Verify FLEX_CUSTOM_PAYMENT_METHOD_ID is correct
  • Check that the custom payment method is enabled in Stripe Dashboard
  • Ensure the ID is properly passed to Elements configuration
  • Clear browser cache and reload

Payment Intent Creation Fails

Problem: Stripe returns an error when creating payment intent. Solutions:
  • Verify Stripe secret key is correct and not expired
  • Check that the amount is in the correct format (cents)
  • Ensure currency is supported
  • Review Stripe Dashboard for API errors

Redirect Not Working After Flex Payment

Problem: User isn’t redirected back after Flex checkout. Solutions:
  • Verify success_url and cancel_url are correct
  • Check that URLs are publicly accessible (not localhost in production)
  • Ensure Flex API credentials are valid
  • Review Flex Dashboard for session details

Form Validation Errors

Problem: Form submission fails with validation errors. Solutions:
  • Check Zod schema matches form fields
  • Verify all required fields are included
  • Review browser console for validation errors
  • Test with minimal valid data first

Next Steps

  • Implement webhook handlers for payment events
  • Add payment status verification on the success page
  • Set up error tracking and monitoring
  • Configure production environment variables
  • Test thoroughly in production mode before going live
  • Review Stripe and Flex production checklists

Additional Resources

Support

If you encounter issues:
  1. Review this documentation thoroughly
  2. Check Stripe and Flex Dashboard logs
  3. Review browser console for errors
  4. Contact Flex support with specific error messages and request IDs