Payment Hub
Central payment processing, tokenization, and payment method management for the Clarity platform. A multi-provider architecture supporting dozens of the most common payment gateways with full lifecycle management including authorization, capture, and refund across credit cards, ACH/eCheck, and credit memos.
Payment Hub Overview
Dozens of the most common payment gateways supported through a unified provider interface. Switch providers without changing business logic.
Authorize, capture, refund, and void operations with complete state tracking across each payment source.
Credit cards, ACH/eCheck, and credit memos supported with type-specific fields and validation.
BIN-based surcharge calculation and tracking with full status lifecycle and decline handling.
Provider Interfaces
IPaymentProvider
Core interface for all payment transaction operations. Every payment gateway must implement this interface to handle authorization, capture, and refund workflows.
public interface IPaymentProvider {
Task<TransactionResult> AuthorizeTransactionAsync(PaymentTransactionModel model, ...);
Task<TransactionResult> CaptureTransactionAsync(CapturePaymentInput input, ...);
Task<TransactionResult> AuthorizeAndCaptureTransactionAsync(...);
Task<TransactionResult> RefundPaymentAsync(...);
}
IPaymentsMethodProvider
Interface for managing tokenized payment instruments. Handles wallet operations including adding, removing, and retrieving payment methods from the provider.
public interface IPaymentsMethodProvider {
Task<PipelineResult<PaymentMethod>> AddPaymentMethodAsync(CreatePaymentMethodInput input, ...);
Task<PipelineResult> RemovePaymentMethodAsync(RemovePaymentMethodInput input, ...);
Task<PipelineResult<PaymentMethod>> GetPaymentMethodInfoAsync(object paymentMethodId, ...);
}
BasePaymentsProviderPlugin
Abstract base class that extends Plugin and provides automatic provider seeding in the database. Each payment provider plugin inherits from this class and sets its unique Key property.
Each provider defines its unique identifier string (e.g., "Mock", "Nuvei", "Stripe"). Used for database seeding and provider resolution.
On startup, the base class ensures a PaymentMethodProvider record exists in the database for this provider key.
Each provider plugin is registered in the client's Startup.cs alongside its settings and DI configuration.
public class MockPaymentsProviderPlugin : BasePaymentsProviderPlugin
{
public override string Key => "Mock";
}
// In Client/Startup.cs
services.AddPlugin<MockPaymentsProviderPlugin>();
Entity Model
The payment system is composed of a rich entity model that tracks every aspect of payment processing, from the top-level payment record through individual sources, methods, and surcharges.
| Entity | Purpose |
|---|---|
| Payment | Core payment record — Amount, AmountIsValid, IsEmulated, Status, Type |
| PaymentMethod | Tokenized payment instrument — Token, CardLastFour, BankName, etc. |
| PaymentMethodProvider | Configured provider instance — Mock, Nuvei, Stripe, etc. |
| PaymentMethodSource | Individual payment source within a payment |
| PaymentMethodSourceStatus | Status per source — Pending, Authorized, Captured, etc. |
| PaymentMethodType | Type classification — CreditCard, ACH, Credit |
| PaymentCardType | Card type — Visa, Mastercard, Amex, Discover |
| PaymentCreditMemoSource | Credit memo applied to payment |
| PaymentStatus | Aggregate payment status |
| PaymentTarget | Invoice or target being paid |
| PaymentType | Payment type classification |
| Surcharge | Fee or surcharge on payment |
| SurchargeStatus | Surcharge lifecycle status |
Payment Lifecycle
Payments follow a state machine from creation through completion, with branches for declines, voids, refunds, and errors.
Payment Statuses
Aggregate Payment Statuses
Per-Source Statuses
Surcharge Statuses
Payment Method Types
Credit Cards
TokenCardLastFourCardExpirationMonth/YearCardHolderNamePaymentCardTypeIdBankIdNumber(BIN)
ACH / eCheck
BankAccountNumber(last 4 only)BankRoutingNumber(last 4 only)BankName
Credit
CurrentBalanceOriginalBalance
Common Fields (All Types)
IsForOneTimeUse
IsPrimary
ProviderId
ExpirationDate
Surcharges
Surcharges are computed through a dedicated pipeline that considers the payment method type, BIN range, and merchant configuration.
UpdateSurchargeForDeclinedPaymentPipeline reverses or adjusts surcharge records when payments are declined.
The first 6-8 digits of the card number (BIN) determine card type and applicable surcharge rate. Stored in the BankIdNumber field.
Surcharges track their own lifecycle (Pending, Assigned, Authorized, Completed, Refunded, Declined, Cancelled, Abandoned) independent of the parent payment status.
Tokenization
All sensitive payment data is tokenized before entering the Phoenix system. The full card number or bank account number never touches the server — only provider-issued tokens and display-safe fields are stored.
What PaymentMethod Stores
Provider-issued token that represents the payment method. Format and lifecycle vary by provider.
Provider-specific identifier for the payment method within the gateway system.
Only the last 4 digits of the card number, for display purposes. No full PAN ever enters the system.
No PII Storage
All sensitive data is tokenized before entering any persistence layer. Combined with TDE/encryption at rest, this provides defense in depth.
check_circleWhat IS Stored
- Provider-issued tokens
- Last 4 digits of card/account
- BIN (first 6-8 digits, for surcharge calculation)
- Cardholder name
- Expiration month/year
cancelWhat is NEVER Stored
- Full card numbers (PAN)
- Full bank account numbers
- CVV / CVC / security codes
- Social Security Numbers (SSN)
Provider Capability Matrix
| Provider | Wallet | Auth CC | Auth ACH | Cap CC | Cap ACH | A+C CC | A+C ACH | Subs |
|---|---|---|---|---|---|---|---|---|
| Authorize.Net | Yes | Yes | Yes | Yes | Yes | Yes | Yes | No |
| ChasePaymentTech | Yes | Yes | No | Yes | No | Yes | No | No |
| CyberSource | Yes | Yes | No | Yes | No | Yes | No | No |
| Heartland | Yes | Yes | No | Yes | No | Yes | No | No |
| MagnifyPayments | Yes | Yes | Yes | Yes | Yes | Yes | Yes | No |
| Mock | Yes | Yes | Yes | Yes | Yes | Yes | Yes | No |
| Nuvei | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
| Payengine | Yes | Yes | Yes | Yes | Yes | Yes | Yes | No |
| Payliance | Yes | No | Yes | No | Yes | No | Yes | No |
| PayPal | No | No | No | No | No | No | No | No |
| PayTrace | Yes | Yes | No | Yes | No | Yes | No | No |
| Stripe | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
Adding a Payment Provider
Follow this five-step checklist to add a new payment gateway to the platform.
Create a class that implements both interfaces with provider-specific API calls for authorization, capture, refund, and wallet management.
Create a plugin class that inherits from BasePaymentsProviderPlugin and set the Key property to a unique provider identifier.
Define a settings class for provider-specific configuration (API keys, endpoints, merchant IDs, secret keys).
Register the plugin, settings, and DI bindings for the provider implementation in the client startup configuration.
Create a frontend extension component for the provider's payment form (card input, ACH fields, etc.) using the wallet extension point.
Mock Provider (Reference)
Key = "Mock". Reference implementation used for development, testing, and integration validation.
Implementation split across partial classes: CreditCard, Method, and ACH for clear separation of payment type logic.
// Mock token format
Token = "MOCK:Token-{Guid}"
// Mock transaction format
TransactionId = "MOCK:Transaction-{Guid}"
Nuvei Provider (Production)
Key = "Nuvei". Production payment provider using HttpClient-based REST API integration.
UserTokenId derived from UserId/CustomerId for wallet association. Enables multi-card wallet management per customer.
Credit cards, ACH, and subscriptions fully supported. Secret key used for request signing and authentication.
Order-to-Cash Flow
End-to-end flow from sales collection through payment capture and ERP synchronization.
Key Pipelines
PayOnAccountPipeline
PayInvoicePipeline
CalculateBalanceDuePipeline
Quick Pay
Token-based payment flow for invoice links. Allows customers to pay invoices directly via a secure link without logging in.
Creates a secure, time-limited token that identifies the invoice and customer for payment.
Validates the token is not expired, not already used, and resolves to a valid invoice.
Executes the quick pay transaction using the validated token and provided payment method details.
Combined operation that generates the invoice and quick pay token in a single pipeline execution.
Credit Memos
Entity that links credit memos to payments. Tracks which credits have been applied and in what amounts.
Credits can be applied as a payment source alongside card or ACH payments, reducing the amount charged to external payment methods.
Credit-type payment methods track CurrentBalance and OriginalBalance for balance management.
Error Handling
PaymentStatus.PartiallyComplete handles cases where some but not all payment sources succeed.
UpdateSurchargeForDeclinedPaymentPipeline adjusts surcharge records when a payment is declined by the provider.
RefundPaymentPipeline processes full or partial refunds through the original payment provider.
Errors during ERP synchronization are logged and counted but do not roll back the payment transaction. Sync retries are handled by the connector layer.