app/services/payment_processors/fiserv_adapter.rbcreate_customer_profile - Generates Fiserv customer IDcreate_payment_token - Tokenizes payment via Data Capture APIauthorize_payment - Authorizes payment using tokencapture_authorization - Captures authorized paymentrefund_transaction - Refunds captured paymentvoid_authorization - Voids authorized paymentprocess_payment_with_session - Convenience method combining token creation + authorizationapp/helpers/fiserv_helper.rbapp/controllers/app/api/payment_controller.rb/api/payment/session{ session_id:, public_key: } to frontendapp/views/app/quotes/payment.html.erbsession_id to backendpayment_nonce to backendconfig/routes.rbPOST /api/payment/sessionapp subdomainconfig/initializers/fiserv.rbDEFAULT_PAYMENT_PROCESSOR configuration.env.exampleDEFAULT_PAYMENT_PROCESSOR settingAdd Fiserv credentials to .env:
DEFAULT_PAYMENT_PROCESSOR=fiserv
FISERV_API_KEY=bG5L6qhCDXXl3M53VbbKXATU1aOZSlXx
FISERV_API_SECRET=pOyVKDgp1lxIrXASDM9g5q84SmtqjEet
FISERV_MERCHANT_ID=500100005000
FISERV_HOST_URL=https://connect-cert.fiservapis.com/ch
FISERV_ENVIRONMENT=sandbox
Run database migrations (if not already done):
bin/rails db:migrate
Restart your development server:
bin/dev
Test the payment flow:
Simply change the environment variable:
DEFAULT_PAYMENT_PROCESSOR=authorize_net
Then restart your server. No code changes needed!
Customer โ Payment Page
โ
[Frontend JavaScript]
โ (Fetch payment session)
POST /api/payment/session
โ
FiservHelper.create_payment_session
โ (Returns session_id + public_key)
Initialize Hosted Fields (iframes)
โ (Customer enters card data)
Validate fields
โ (Submit form with session_id)
POST /order/:token/process_payment
โ
PaymentProcessorFactory.for_order
โ
FiservAdapter.process_payment_with_session
โ
1. Create customer profile
2. Tokenize via Data Capture API
3. Authorize payment
โ
Save PaymentProfile + PaymentTransaction
โ
Redirect to complete page
Customer โ Payment Page
โ
[Frontend JavaScript]
โ (Customer enters card data)
Accept.js tokenizes card data
โ (Returns payment_nonce)
POST /order/:token/process_payment
โ
PaymentProcessorFactory.for_order
โ
AuthorizeNetAdapter.process_payment_with_nonce
โ
1. Create customer profile
2. Create payment token
3. Authorize payment
โ
Save PaymentProfile + PaymentTransaction
โ
Redirect to complete page
Both processors use the same database tables with processor-agnostic fields:
processor - 'authorize_net' or 'fiserv'processor_customer_id - Processor's customer identifierprocessor_token_id - Processor's payment token IDcard_type, last_four, exp_month, exp_year - Card detailsis_default - Default payment method flagprocessor - 'authorize_net' or 'fiserv'processor_transaction_id - Processor's transaction IDtransaction_type - 'auth_only', 'capture_only', 'refund', etc.status - 'approved', 'declined', 'error', etc.amount, card_type, last_four - Transaction detailsmetadata (jsonb) - Processor-specific extra dataBefore switching to production:
For Fiserv (Production):
DEFAULT_PAYMENT_PROCESSOR=fiserv
FISERV_API_KEY=<production_api_key>
FISERV_API_SECRET=<production_api_secret>
FISERV_MERCHANT_ID=<production_merchant_id>
FISERV_HOST_URL=https://connect.fiservapis.com/ch
FISERV_ENVIRONMENT=production
For Authorize.Net (if keeping as backup):
AUTHORIZENET_API_LOGIN_ID=<your_api_login_id>
AUTHORIZENET_TRANSACTION_KEY=<your_transaction_key>
AUTHORIZENET_SIGNATURE_KEY=<your_signature_key>
AUTHORIZENET_PUBLIC_CLIENT_KEY=<your_public_client_key>
The factory supports per-customer processor selection:
# In customer model (future enhancement):
customer.payment_processor = 'fiserv' # or 'authorize_net'
This allows gradual migration:
app/controllers/app/api/payment_controller.rb - Payment session APIconfig/initializers/fiserv.rb - Fiserv configurationdocs/phase3_fiserv_integration_complete.md - This fileapp/views/app/quotes/payment.html.erb - Conditional Fiserv/Authorize.Net renderingconfig/routes.rb - Added API payment session endpoint.env.example - Added payment processor configurationapp/services/payment_processors/base.rb - Base interfaceapp/services/payment_processors/authorize_net_adapter.rb - Authorize.Net adapterapp/services/payment_processors/fiserv_adapter.rb - Fiserv adapterapp/services/payment_processor_factory.rb - Factory for routingapp/helpers/fiserv_helper.rb - Fiserv API helperapp/models/payment_profile.rb - Updated modelapp/models/payment_transaction.rb - Updated model.env with production valuesOption A: Switch All at Once
DEFAULT_PAYMENT_PROCESSOR=fiservOption B: Gradual Migration
DEFAULT_PAYMENT_PROCESSOR=authorize_netcustomer.payment_processor = 'fiserv' for select customersOption C: New Customers Only
โ Processor Agnostic - Can switch processors with one environment variable โ Better PCI Compliance - SAQ-A vs SAQ A-EP โ Cost Savings - Free processing with Fiserv โ Backwards Compatible - Existing Authorize.Net data still works โ Future Proof - Easy to add more processors โ Per-Customer Selection - Can route customers to different processors โ Better Testing - Can mock processors in tests
Fiserv Documentation:
Sandbox Credentials:
docs/fiserv_credentials.md for complete sandbox detailsQuestions?
docs/payment_processor_abstraction.md for architecture detailsapp/services/payment_processors/base.rb for interface documentation