Stripe Integration Technical Documentation
Comprehensive technical reference for LocallyGrown.net's Stripe payment integration - architecture, API flows, security implementation, and database schema
Architecture Overview
Multi-Market Platform
LocallyGrown.net is a multi-tenant platform where each farmers market operates independently with its own Stripe account.
- Architecture: Each market has separate Stripe API keys (publishable and secret)
- Subdomain Routing: Markets are accessed via subdomains (e.g.,
market1.locallygrown.net
) - Key Storage: Stripe keys are stored in the MySQL database
- Key Selection: Runtime determination based on subdomain/marketId
Stripe Configuration per Market
Each market has Stripe configuration stored securely:
- Publishable Key - Client-side API key for secure tokenization
- Secret Key - Server-side API key (encrypted at rest)
- Approval Status - Whether market is approved for payment processing
- Prepayment Fee - Optional fee percentage for prepayments
- Prepayment Fee Label - Customer-facing fee description
Stripe Client Initialization
Server-Side Initialization
The server-side Stripe client is initialized through a secure service layer that manages API key retrieval and client instantiation.
1. API Key Retrieval
The system retrieves market-specific Stripe API keys from secure storage:
- Development environments can use override configuration for testing
- Production environments retrieve keys from encrypted database storage
- System throws errors if market configuration is missing or invalid
2. Client Creation
Stripe client initialization includes multiple safety mechanisms:
- Payment processing is disabled by default in non-production environments
- Explicit configuration flag required to enable live charges
- Prevents accidental charges during development and testing
- Uses current Stripe API version for compatibility
Safety Mechanism:
Payment processing must be explicitly enabled via configuration. The system defaults to disabled
state to prevent accidental charges in development/testing environments.
Client-Side Initialization
Cards are collected using Stripe Elements, a PCI-compliant client-side SDK that handles sensitive card data entirely within Stripe's infrastructure.
Integration Approach:
- Stripe.js library loaded dynamically from official CDN
- Initialized with market-specific publishable key
- Elements created for secure card input collection
- Card data never touches LocallyGrown servers
API Endpoints and Flows
1. SetupIntent Creation (Card Saving Initiation)
Flow:
- Authenticates user session
- Applies rate limiting to prevent abuse
- Verifies payment processing is enabled
- Creates Stripe SetupIntent via service layer
- Returns secure client token for card collection
Response Format:
Returns JSON with success status, client secret token, and configuration flags
2. Setup Intent Processing (Server-Side)
The server-side service layer handles SetupIntent creation through the Stripe API.
Implementation Details:
- Creates SetupIntent associated with customer account
- Configured for off-session (future) payment use
- Accepts all major card brands (credit, debit, prepaid)
- Includes market and transaction metadata for tracking
Card Types Supported: All major card brands including Visa, Mastercard, American Express, Discover, and international cards
3. Payment Method Attachment
Flow:
- Authenticates user session
- Applies rate limiting for card management operations
- Validates payment method token format
- Processes card attachment through service layer
- Returns card display details (brand, last 4 digits)
Service Implementation
The payment service handles the secure attachment of payment methods to customer accounts.
Processing Steps:
- Token Validation: Verifies payment method token has correct format before processing
- Existing Customer Handling:
- Retrieves customer record from Stripe
- Attaches new payment method
- Sets as default for future charges
- Removes outdated payment methods
- New Customer Creation:
- Creates Stripe customer with user email
- Attaches payment method
- Configures as default
- Record Update: Updates user record with customer ID and card display information
4. Payment Intent Creation (Charging Cards)
A. Single Order Payment
The payment service processes individual order payments through Stripe's PaymentIntent API with full off-session charge support.
Key Parameters:
- Market-specific configuration
- Customer ID from previous card setup
- Calculated amount in cents
- Descriptive payment label
- Transaction metadata for tracking
B. Grouped Order Payment (Multiple Orders, Single Charge)
For efficiency, the system can combine multiple orders into a single charge using idempotency keys and distributed locking.
Implementation Features:
- Unique idempotency key prevents duplicate charges
- Distributed lock prevents concurrent processing
- Metadata tracks all included order IDs
- Single customer charge for multiple orders
Critical Feature: Distributed locking mechanism prevents concurrent payment processing for the same user, ensuring charge integrity.
5. Core Payment Intent Function
The core payment processing function implements several critical safety features to ensure payment integrity.
Key Features:
1. Card Sync Verification
Before charging, the system verifies that the stored card information matches Stripe's records. If a mismatch is detected, the system attempts automatic correction to prevent charging the wrong card.
2. Default Payment Method Retrieval
Retrieves the customer's default payment method from Stripe. Throws an error if no payment method is configured, preventing failed charge attempts.
3. Payment Method Cleanup
Lists all payment methods attached to the customer and removes non-default cards. This ensures only one active card per customer, preventing confusion and wrong card charges.
4. Off-Session Charge
Creates and immediately confirms the PaymentIntent with off-session mode enabled. Uses optional idempotency key for grouped payments to prevent duplicate charges on retry.
Configuration:
- Amount in cents (Stripe standard)
- USD currency
- Customer and payment method IDs
- Off-session and immediate confirmation flags
- Descriptive transaction metadata
Stripe API Endpoints Used:
customers.retrieve
- Get customer datapaymentMethods.retrieve
- Get payment method detailspaymentMethods.list
- List customer's cardspaymentMethods.detach
- Remove old cardspaymentIntents.create
- Create and confirm charge
Card Saving Locations
There are two distinct UI locations where users can save cards:
Location 1: Cart Checkout Modal
Access: Users updating payment method during checkout process
Implementation Features:
- Modal Interface: Overlay dialog with progressive disclosure for card entry
- Lazy Loading: Stripe.js loaded on-demand when modal opens to improve page performance
- Data Security: User data snapshot captured at modal open to prevent information leaks
- Error Handling: Validates setup completion and handles API mismatches gracefully
Unique Features: In-flow card updates during checkout, current card display, charge timing information
Location 2: User Account Panel
Access: Users managing payment methods in their account settings
Implementation Features:
- State Management: Tracks Stripe Elements state, loading indicators, and user feedback messages
- Smart Initialization: Automatically prompts for card entry if none on file
Unique Features: Auto-expands payment section for first-time setup
Common Patterns Across All Locations
Security:
- All use Stripe Elements (PCI-compliant, tokenized input)
- Card data never touches LocallyGrown servers
- Only
paymentMethodId
(token) sent to backend
Flow:
- Create SetupIntent server-side → get
clientSecret
- Load Stripe.js from CDN
- Initialize Stripe with
stripePubKey
- Create Elements with
clientSecret
- Mount individual card field elements
- User enters card data (stays in Stripe iframe)
- Call
stripe.confirmCardSetup()
- Receive
paymentMethodId
- Send
paymentMethodId
to/api/user/save-card
- Server attaches to customer and updates database
Payment Processing
When Charges Occur
CRITICAL: Charges happen after pickup, not at order time or after packing.
Why After Pickup?
Orders are charged after pickup to allow for final adjustments based on what the customer actually receives:
- Growers may be out of some items
- Quantities might change (3 tomatoes available instead of 5)
- Customers may add items from an "extras table" at pickup
- Out-of-stock items can be removed before charging
Flow:
- Customer Places Order
- Order created with
paymentMethod: 'Pending Stripe'
- No charge occurs
applyPrepayment: 1
flag set if payment should be processed
- Order created with
- Grower Packs Order
- Grower marks items as packed
- May adjust quantities (missing/undelivered items)
- Background Worker Processes Payments
- Automated system detects packed orders flagged for payment
- Processes individual or grouped order payments through payment service
- Charge Calculation
- Spot Price: Actual cost based on packed quantities
- Prepayment Fee: Percentage fee if configured (default 0%)
- Total:
spotPrice + (spotPrice * prepaymentFeePercent / 100)
Example:- Order total: $50.00
- Prepayment fee: 3%
- Fee amount: $1.50
- Total charged: $51.50
- Stripe Charge
- Creates PaymentIntent with
off_session: true, confirm: true
- Uses customer's default payment method
- Includes metadata (orderId, userId)
- Creates PaymentIntent with
- Post-Charge Actions
- Records prepayment in
prepayments
table - Updates order:
paid: 1, prepaymentProcessed: 1, paymentMethod: 'Stripe'
- Queues payment confirmation email
- Clears
applyPrepayment
flag
- Records prepayment in
Minimum Charge Amount
Stripe Requirement: $0.50 minimum charge amount
- System validates minimum amount before processing
- Stores validation error if amount below minimum
- Order remains unpaid until valid amount available
Refund Processing
The system supports two refund methods: account credits (automated) and Stripe card refunds (manual).
Account Credits (Automated):
- Processed through
OrderService.processRefunds()
- Credits customer's account balance instantly
- Tracks refund amounts in order item records
- Balance can be used for future orders
Stripe Card Refunds (Manual):
- Must be processed manually via Stripe dashboard
- Market managers initiate refunds directly in Stripe
- Returns money to customer's original card (2-10 business days)
PaymentService.processRefund()
exists but is not currently integrated into workflows
Important: The PaymentService.processRefund()
method contains
Stripe refund API code but is not called by any current system workflows. All Stripe card
refunds are processed manually through the Stripe dashboard.
Webhook Integration
Security
Webhook security is implemented using Stripe's signature verification mechanism to ensure authenticity.
Verification Process:
- Validates Stripe signature header is present
- Verifies market context through request headers
- Uses webhook secret for signature validation
- Constructs verified event object from payload
Requirements:
- Valid Stripe signature header
- Market identification
- Active Stripe configuration
Webhook Events Handled
1. payment_intent.succeeded
Actions:
- Updates order status to paid
- Marks payment as processed
- Retrieves payment method details from Stripe
- Creates payment transaction record with amount, card details, and transaction ID
2. payment_intent.payment_failed
Actions:
- Updates order with error message
- Resets payment processing status
- Preserves error details for customer support
3. charge.refunded
Actions:
- Updates payment transaction record with refund amount
- Updates refund status through payment service
4. payment_method.updated
Actions:
- Updates user record with new card details
- Synchronizes card brand and last 4 digits
Note: Requires customer ID to user mapping for updates
Rate Limiting
Webhook endpoint implements rate limiting to prevent flooding attacks and abuse.
Security Implementation
PCI Compliance
Approach: Stripe Elements (SAQ-A compliance)
1. No Card Data Touching Servers
- Card input fields are Stripe-hosted iframes
- Only tokenized
paymentMethodId
transmitted to backend
2. HTTPS Only
- All Stripe communication over TLS
- Local dev uses SSL certificates via anchor-pki
3. Tokenization
- SetupIntent creates token
- PaymentMethod ID (
pm_xxx
) used for all operations - Raw card data never stored
Authentication & Authorization
API Endpoints:
- All endpoints protected by session-based authentication
- User sessions validated before payment operations
- Authorization guards prevent unauthorized access
Market Context:
- All operations scoped to user's market
- Stripe configuration retrieved per market
- Cross-market operations prevented
Rate Limiting
Comprehensive rate limiting is applied across all payment-related operations to prevent abuse and ensure system stability.
Protected Operations:
- Setup Intent Creation: Prevents repeated card save attempts
- Card Management: Limits add/remove card operations
- Webhook Processing: Prevents webhook flooding
Card Sync Verification
Purpose: Ensures displayed card information matches the card that will be charged
Verification Process:
- Before charging, system verifies stored card data matches Stripe's records
- Queries Stripe for customer's current default payment method
- Compares local card information with Stripe data
- If mismatch detected:
- Attempts automatic synchronization
- Updates local records with current Stripe data
- Throws error if synchronization fails
Protection: Prevents charging wrong card after data inconsistencies or race conditions
Environment-Based Safety
Payment Processing Control:
Payment processing is controlled by configuration flag that defaults to disabled state.
Modes:
- Disabled (Default): Simulation mode with no real charges
- Enabled: Production mode with real charges
Simulation Mode Features:
- Logs payment intents for debugging
- Returns mock transaction IDs
- Updates database records for testing
- Uses test card data
Database Schema
The database schema supports multi-market Stripe integration with secure storage of payment-related information.
User Payment Data
User records store minimal payment information required for processing:
- Stripe Customer Identifier - Links user to Stripe customer account
- Card Display Information - Card brand and last 4 digits for user interface
Market Payment Configuration
Market records store Stripe configuration and settings:
- Publishable Key - Client-side API key (public)
- Secret Key - Server-side API key (encrypted at rest)
- Prepayment Fee - Optional percentage fee configuration
- Fee Display Label - Customer-facing fee description
- Approval Status - Enables/disables payment processing
Order Payment Tracking
Order records track payment status and processing state:
- Payment Trigger Flag - Indicates payment should be processed
- Processing Status - Whether payment completed successfully
- Transaction Reference - Links to payment transaction record
- Error Information - Stores failure details for troubleshooting
- Payment Method Status - Tracks payment state transitions
Payment Transaction Records
Payment transactions are tracked with comprehensive information:
- Amount - Stored in cents (Stripe standard)
- Currency - Payment currency (default: USD)
- Vendor Transaction ID - Stripe PaymentIntent ID for reconciliation
- Payment Method Type - Identifies payment processor
- Card Display Information - Brand and last 4 digits for receipts
- Status Tracking - Paid, refunded, rejected flags
- Refund Information - Refund amount and status
- Audit Trail - Creation and modification timestamps
Error Handling and Retry Logic
Payment Intent Error Handling
The payment service implements comprehensive error handling to gracefully manage various failure scenarios.
Validation Errors
Invalid Amounts
- Validates numeric values before processing
- Enforces minimum amount requirements
- Stores validation errors for user feedback
- Prevents invalid API calls
Missing Configuration
- Verifies market has payment processing enabled
- Returns clear error if Stripe not configured
- Stores error message for troubleshooting
Stripe API Errors
Card Declined
- Stripe returns detailed error via PaymentIntent status
- Webhook delivers failure notification
- Error message stored for customer support
Missing Payment Method
- Detects when customer has no card on file
- Returns appropriate error response
- User prompted to add payment method
Sync Verification Failures
- Attempts automatic synchronization correction
- Throws error if correction fails
- Requires user to update payment method
Retry Logic
Idempotency Keys
Grouped payments use unique idempotency keys to prevent duplicate charges on retry.
Purpose:
- Prevents duplicate charges if request retries
- Stripe recognizes duplicate requests by key
- Returns original result for retries within 24 hours
Distributed Locks
Payment processing implements distributed locking to prevent race conditions:
- Prevents concurrent payment processing for same user
- Lock timeout ensures eventual recovery from failures
- Ensures only one payment process at a time per user
Double-Charge Prevention
Order Status Filtering
System filters orders by payment status to prevent reprocessing:
- Only processes orders in pending payment state
- Status transitions are atomic with payment
Status Transition
- Successful payment triggers status change
- Prevents reprocessing if worker runs again
- Status change synchronized with payment confirmation
Testing and Simulation Mode
Simulation Mode
The system supports development and testing through a simulation mode that allows full integration testing without live payment processing.
Simulation Features:
1. Customer Management
Creates mock customer objects with realistic identifiers for testing user payment flows
2. Payment Intents
Returns simulated PaymentIntent objects with successful status, allowing complete order payment testing
3. SetupIntents
Generates mock SetupIntent objects with properly formatted client secrets for card saving flows
4. Database Integration
Full business logic execution in simulation mode:
- All database operations execute normally
- Test card data (Visa 4242) stored for verification
- Complete payment workflow from initiation to completion
Test Environment
The system includes comprehensive automated testing infrastructure for payment operations.
Test Database:
- Isolated test database separate from development and production
- Transaction-based test isolation with automatic rollback
- Real database operations ensuring production-like behavior
Test Coverage:
- Unit tests for payment service logic
- Integration tests for complete payment flows
- Race condition prevention tests
- Data validation and error handling tests
- Multi-order grouped payment tests
Test Organization:
Tests are organized into focused suites covering payment creation, grouped payments, validation logic, and concurrency scenarios.
API Reference Summary
Stripe API Endpoints Used
Customers
customers.create
- Create new customercustomers.retrieve
- Get customer detailscustomers.update
- Update default payment method
Payment Methods
paymentMethods.attach
- Attach card to customerpaymentMethods.detach
- Remove old cardspaymentMethods.retrieve
- Get card detailspaymentMethods.list
- List customer's cards
SetupIntents
setupIntents.create
- Initiate card save
PaymentIntents
paymentIntents.create
- Create and charge (withconfirm: true
)
Refunds
refunds.create
- Process refund
Webhooks
webhooks.constructEvent
- Verify and parse webhook
LocallyGrown API Endpoints
Public APIs
GET /api/stripe/setup-intent
- Create SetupIntentPOST /api/user/save-card
- Save payment methodPOST /api/webhooks/stripe
- Stripe webhook handler
Internal Services
The payment service layer provides:
- Single and grouped order payment processing
- Prepayment transaction recording
- Refund processing capabilities
- Payment method management (save/remove cards)
System Architecture Overview
Service Layer Architecture
The payment system is organized into distinct service layers:
- Core Stripe integration services for API communication
- Payment processing services for transaction management
- User services for payment method and customer management
API Endpoint Organization
Public API endpoints are organized by functionality:
- SetupIntent creation endpoint for card saving flows
- Payment method management endpoints
- Webhook handlers for Stripe event processing
User Interface Components
Payment-related UI components include:
- Customer-facing checkout and card management modals
- Administrative panels for account and payment oversight
Data Layer
Payment data is managed through:
- Secure database schema for payment information
- Encrypted storage of sensitive payment data
- Transaction-safe operations for payment processing
Background Processing
Asynchronous payment operations handled by:
- Background task queues for order payment processing
- Automated payment workflows for packed orders
- Retry mechanisms for failed payment attempts
Contact Information
For questions about this integration, please contact:
- Technical Issues: [email protected]
- Stripe Account: Each market manages their own Stripe account
- Security Concerns: [email protected]