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 | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
| 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.
Embedded vs. Integrated Payments
open_in_new Integrated Payments
In an integrated model the payment system runs as a separate application. The user must leave their ERP workflow, navigate to an external payment portal, complete the transaction, and return. This creates a “bolted-on” experience with context-switching friction, higher abandonment rates, and a disjointed audit trail between the ERP and the payment system.
Separate login
External redirect
Manual reconciliation
integration_instructions Embedded Payments
In an embedded model, payment functionality is woven directly into the ERP user interface. The user never leaves D365 or NetSuite — payment forms appear as native elements within the existing workflow. Transactions are automatically linked to invoices, orders, and customer records without manual reconciliation.
Native UX
Auto-reconciled
Single workflow
How Clarity Supports Embedded Payments
The Remix frontend generates embeddable payment components that can be rendered inside ERP pages via iframe or Web Component injection, providing a seamless in-context payment experience.
Each ERP connector plugin includes frontend extension points that define where and how payment forms render within the host application, ensuring consistent placement across D365 and NetSuite.
The payment form submits card data directly to the provider from the client side. The host ERP page never handles sensitive data, and only a token is returned to the Clarity API.
GenerateQuickPayTokenPipeline produces embeddable payment links that can be sent via email or embedded in customer portals, extending the embedded experience beyond the ERP.
The eCommerce plugin is itself an embedded payment experience — checkout flows are rendered within the storefront with tokenized form submission directly to the provider.
PCI Compliance for Embedded Forms
The payment form is rendered as an isolated component (iframe or Web Component). The host ERP page cannot access the form’s DOM. The form submits directly to the payment provider via client-side JavaScript — card data never touches the Clarity server. Only the resulting token comes back. This architecture maintains SAQ-A eligibility for both Clarity and the host ERP application.
Embedded Payment Architecture Flow
Customer-Entered Data Processing (CEDP)
The platform tracks payment context so the correct transaction classification flows to the provider. This affects interchange qualification, chargeback liability rules, and 3D Secure requirements. Each entry mode is handled through the same tokenization pipeline but with different metadata and provider-level flags.
The customer enters card data directly via an eCommerce checkout, Quick Pay link, or embedded payment form. Card data flows directly from the browser to the payment provider — Clarity’s server never sees the full PAN or CVV. This mode qualifies for the lowest interchange rates and supports 3D Secure for chargeback liability shift.
Mail Order / Telephone Order. A CSR uses an admin-facing payment form on behalf of the customer. The same tokenization flow applies — data goes directly to the provider from the CSR’s browser. MOTO transactions carry higher interchange rates than CEDP and are not eligible for 3D Secure authentication, which means the merchant retains chargeback liability.
Subsequent charges use stored tokens from previous customer-initiated transactions. The PaymentMethod entity references the provider-issued token, and charges are submitted as merchant-initiated transactions (MIT). No customer interaction is required after initial tokenization.
Level 2 & Level 3 Transaction Data
Card networks offer reduced interchange rates for transactions that include enhanced data beyond the standard authorization fields. For B2B merchants processing corporate and purchasing cards, L2/L3 data can yield significant savings. Clarity’s architecture is purpose-built to populate these fields automatically from existing ERP data.
Card number, amount, merchant identifier, and authorization code. Every transaction includes Level 1 data by default. This is the baseline with the highest interchange cost.
Adds tax amount, customer/PO number, and merchant tax ID. Required for corporate card qualification. Typical interchange savings of 0.5–1.0% compared to Level 1.
Adds full line-item detail: descriptions, quantities, unit prices, commodity codes, discount amounts, and freight charges. Required for purchasing/government cards. Additional savings of 0.3–0.5% beyond Level 2.
Clarity’s L2/L3 Positioning
Because Clarity sits between the ERP and the payment gateway, it has access to all the source data needed for L2/L3 qualification. Invoices, sales orders, and product catalogs synced via the connector pipeline already contain line-item descriptions, quantities, tax amounts, and PO numbers. The IPaymentProvider interface accepts L2/L3 fields, and each provider implementation maps them to the gateway-specific format.
For a B2B client processing $10M annually on corporate and purchasing cards, L2/L3 data can reduce interchange costs by $50K–$100K per year. The ERP already has all the required data; Clarity is the ideal L2/L3 enabler because it bridges ERP line items to gateway-specific enhanced data fields.
L2/L3 Data Pipeline
Surcharge Compliance & Decision Flow
The first 6–8 digits of a card number (the BIN) determine the card type, issuing bank, and whether it is a credit or debit product. Surcharges can only be applied to credit cards — surcharging debit cards is prohibited by federal law (Durbin Amendment) and card brand rules.
CalculateSurchargePipeline determines the applicable surcharge rate based on card type, merchant configuration, and transaction context. The pipeline is fully hookable — custom plugins can inject additional logic for special pricing tiers or merchant-specific rules.
Surcharge records follow their own status lifecycle: Pending → Assigned → Authorized → Completed. If a payment is declined, UpdateSurchargeForDeclinedPaymentPipeline reverses the surcharge. For partial refunds, the surcharge is proportionally adjusted.
Connecticut, Maine, Massachusetts, and Oklahoma prohibit credit card surcharging entirely. Other states cap the rate, typically at 3–4%. The platform supports per-merchant configuration by state, ensuring that surcharge calculations automatically respect the jurisdiction of the transaction.
Visa requires merchants to register their surcharge program 30 days in advance. Mastercard enforces different rate caps and disclosure requirements. American Express has separate rules that may override state-level caps in certain scenarios. The platform’s configuration model accounts for each brand’s requirements.
Surcharge Decision Flow
Invoice Payment Flows
PaymentMethodSource allows submitting less than the full invoice amount. The payment transitions to PaymentStatus.PartiallyComplete, and CalculateBalanceDuePipeline recalculates the remaining balance on the invoice. Subsequent payments can be applied until the invoice is fully settled.
A single payment can combine multiple sources — for example, a credit memo applied alongside a credit card charge. PaymentCreditMemoSource tracks the credit memo application while PaymentMethodSource handles the card charge, each with independent status tracking.
A single payment can be allocated across multiple invoices by creating multiple PaymentTarget records. Each target references a specific invoice and the amount applied, enabling batch payment processing for customers with multiple outstanding invoices.
Payment terms such as Net 30, Net 60, and 2/10 Net 30 are managed in the ERP and synced to Clarity via the connector pipeline. The platform uses these terms to determine due dates, aging buckets, and early payment discount eligibility.
CalculateBalanceDuePipeline hooks evaluate whether the payment date falls within the discount window (e.g., the “2/10” in 2/10 Net 30). If eligible, the pipeline automatically reduces the balance due by the discount percentage before presenting the amount to the customer.
The Quick Pay pipeline sequence is: GenerateQuickPayTokenPipeline creates a secure, time-limited payment token linked to one or more invoices. ValidateQuickPayTokenPipeline verifies the token on access. DoQuickPayPipeline executes the payment using the customer’s selected method.
ACH / eCheck Processing
ACH (Automated Clearing House) and eCheck payments are critical for B2B and B2G transactions where lower processing costs and higher transaction limits are needed. ERP customers are predominantly B2B, making ACH support essential for the platform.
ACH/eCheck is supported across multiple provider implementations: Authorize.Net, MagnifyPayments, Mock, Nuvei, Payengine, Payliance, and Stripe.
ACH transactions have a 3–5 day settlement window (vs. real-time for cards), no real-time authorization, and return codes instead of decline codes. Processing costs are significantly lower at $0.20–$1.50 per transaction versus 2–3% for credit cards. Surcharging is not allowed for ACH transactions.
The PaymentMethod entity stores BankAccountNumber (last 4 digits only), BankRoutingNumber (last 4 digits only), and BankName. Full account and routing numbers are never stored in the Clarity database — they are tokenized at the provider level, consistent with the platform’s no-PII architecture.
ACH payments remain in ExternalPending / Authorized status until the ACH network confirms settlement. Failed returns (NSF, closed account, unauthorized) transition the payment to Declined or Error status, unlike credit cards which receive immediate authorization responses.
Common return codes: R01 (Insufficient Funds), R02 (Account Closed), R03 (No Account / Unable to Locate), R10 (Customer Advises Unauthorized). These are received asynchronously, typically 2–5 business days after initiation.