Multi-Party Marketplace Invoicing &
Double-Entry Financial Rails.
How Nexovex engineered a high-throughput Stripe Connect marketplace billing engine, immutable double-entry ledger, dynamic tiered FeeEngine, and automated contract-to-escrow state machine for Payeny.
The Complexities of Modern Financial Engineering
Building an enterprise-grade billing platform requires solving non-trivial financial constraints: compliance liability, multi-party fee splits, strict ledger balancing, and seamless client workflows.
Marketplace Split & Regulatory Escrow Risk
When a platform facilitates client invoicing on behalf of independent business owners, handling all gross funds directly creates severe regulatory money-transmitter liabilities, chargeback exposures, and compliance overhead. Payeny required automated multi-party settlement where merchant payouts route directly to connected merchant accounts while Payeny deducts its platform commission instantly.
Single-Entry Accounting Drift & Audit Voids
Most SaaS invoicing tools store a simple status column (`paid`, `refunded`, `pending`) in an invoice record. When partial payments, refunds, processing fees, application cuts, and chargebacks occur, the database loses financial state fidelity. Payeny demanded a mathematically provable, immutable double-entry ledger where debits and credits always equal zero.
150+ Currency Precision & VAT/Tax Compliance
International consulting agencies and SaaS providers frequently invoice clients across North America, Europe, Asia, and Latin America. Handling floating exchange rates, non-decimal zero-decimal currencies (like JPY), and complex multi-jurisdiction VAT/GST requirements without rounding errors requires micro-cent mathematical accuracy.
Disjointed Contract-to-Cash Handover
In traditional agency workflows, a client signs a contract in DocuSign, receives an invoice via email days later, pays manually, and then waits for an account manager to unlock deliverables. This operational friction causes payment delays and administrative drag. Payeny required an automated event-driven state machine connecting signatures, deposit invoices, and deliverable escrow.
Four Architectural Pillars of Payeny
Nexovex architected a modular, banking-grade financial foundation combining Stripe Connect marketplace infrastructure, strict double-entry ledger bookkeeping, and automated business flow orchestration.
Stripe Connect Multi-Party Settlement Engine
We engineered a non-custodial marketplace payout structure utilizing Stripe Connect Custom and Express accounts. Connected merchants undergo automated KYC onboarding, while our custom FeeEngine dynamically calculates and captures Payeny application fees at the exact millisecond of checkout.
- Direct Merchant Transfers: Net revenue routes straight to merchant bank accounts without entering platform balance sheets.
-
Dynamic Tier Overrides:
FeeEngine.phpevaluates priority rules: Merchant Specific > Product Specific > Platform Default. - Stripe Elements 3DS2: Embedded checkout supporting Apple Pay, Google Pay, ACH Direct Debit, and SEPA.
FeeEngine::calculate($cents, ['merchant_id' => 42])Returns application fee, Stripe fee estimate, and merchant net cents.
Immutable Double-Entry Financial Ledger
To eliminate balance discrepancies and guarantee forensic auditability, we architected LedgerService.php. Every financial transaction—charges, platform cuts, merchant net payouts, refunds, and dispute chargebacks—records matched debit and credit entries with cryptographic checksums.
-
Zero Accounting Drift: Every transaction enforces
Sum(Debits) === Sum(Credits)within atomic database transactions. -
Immutable Cryptographic Journal: Every ledger entry receives a unique
led_...identifier and parent hash chain. - Audit-Ready Balance Sheets: Real-time financial reports generated on demand with zero slow full-table scans.
LedgerService::recordPaymentSuccess($payId, $mId, $gross, $fee)Atomically constructs 4 balanced ledger entries in < 18ms.
Event-Driven Contract-to-Escrow Automation
We developed FlowService.php, a real-time reactive event orchestrator that listens to lifecycle transitions. When a client signs a contract, Payeny auto-generates a milestone retainer invoice; when the invoice settles, digital deliverables in the client Space unlock automatically.
-
Autonomous Deposit Generation:
contract.signedinstantly generatesINV-XXXXwith 50% retainer terms. -
Deliverable Escrow Gate:
invoice.paidunlocks protected client space files without admin intervention. - Developer Webhook Bus: Dispatches cryptographically signed HMAC webhooks to external ERPs and CRMs.
FlowService::trigger($bizId, 'invoice.paid', 'invoice', $invId)Executes core business rules + custom user workflow definitions.
Payeny AI Invoicing & Sentiment Dunning
We embedded AiService.php directly into the operational pipeline. Payeny AI transforms unstructured discovery call notes into itemized milestone proposals, drafts jurisdiction-compliant contract clauses, and schedules predictive, sentiment-aware payment follow-up reminders.
- Intake-to-Proposal Drafting: Parses client meeting notes into structured project scopes and cost estimates.
- Predictive Dunning Reminders: Evaluates payment timing behavior to send polite reminders at optimal times.
- Automated Expense Categorization: OCR receipt parsing and automatic deduction mapping for tax preparation.
AiService::generateProposalScope($intakeNotes, $rateCard)Generates itemized deliverables, payment terms, and timeline estimates.
Interactive Transaction Pipelines
Select a financial pipeline below to trace how Payeny securely ingests, calculates, balances, and settles enterprise transactions in real time.
/* Telemetry JSON will render here */
The Four Horizons of Payeny Financial Rails
From high-speed multi-party invoicing to 2027 autonomous treasury infrastructure, here is the complete engineering roadmap designed for Payeny.
Core Invoicing & Stripe Connect Rails
Establishment of core multi-party billing engine, automated client invoicing, and double-entry ledger bookkeeping.
- Stripe Connect Express/Custom onboarding
- Dynamic FeeEngine with tier overrides
- Immutable double-entry ledger journal
- Automated daily recurring billing cron
Marketplace Rails & Developer SDKs
Expansion of developer ecosystem with official client libraries, webhooks, and multi-business tenant isolation.
- Official Node.js & PHP client SDKs
- OpenAPI 3.0 specification & developer hub
- HMAC-signed real-time webhook bus
- Custom domain white-label client portals
AI Workflows & Enterprise Governance
Autonomous contract scope generation, sentiment dunning cascades, and fine-grained team permission roles.
- Payeny AI intake notes-to-proposal generator
- Predictive dunning with smart retry timing
- Multi-organization role-based access (RBAC)
- Receipt OCR & automatic tax categorization
Autonomous Treasury & Virtual Cards
Global multi-currency virtual IBANs, programmable corporate debit cards, and autonomous yield treasury management.
- Dedicated multi-currency virtual IBANs (USD/EUR/GBP)
- Programmable virtual corporate expense cards
- Real-time cross-border FX spot settlement
- Automated quarterly tax withholding escrows
Behind the Build · Pure Financial Engine
Review the production PHP architecture powering Payeny's immutable ledger, dynamic fee calculator, event state machine, and subscription cron.
<?php
namespace App\Services;
use App\Core\Database;
use PDO;
class LedgerService
{
/**
* Record full ledger double-entry breakdown for a successful payment
*/
public static function recordPaymentSuccess(
int $paymentId,
int $merchantId,
int $platformProfileId,
int $grossCents,
int $applicationFeeCents,
int $stripeFeeCents,
string $currency = 'USD'
): void {
$merchantNet = $grossCents - $applicationFeeCents;
// 1. Gross charge credit to merchant
self::record([
'payment_id' => $paymentId,
'merchant_id' => $merchantId,
'platform_profile_id' => $platformProfileId,
'entry_type' => 'charge',
'amount_cents' => $grossCents,
'currency' => $currency,
'description' => 'Gross payment received',
]);
// 2. Payeny application fee debit from merchant
if ($applicationFeeCents > 0) {
self::record([
'payment_id' => $paymentId,
'merchant_id' => $merchantId,
'platform_profile_id' => $platformProfileId,
'entry_type' => 'application_fee',
'amount_cents' => -$applicationFeeCents,
'currency' => $currency,
'description' => 'Payeny platform application fee',
]);
}
// 3. Processing fee record
if ($stripeFeeCents > 0) {
self::record([
'payment_id' => $paymentId,
'merchant_id' => $merchantId,
'platform_profile_id' => $platformProfileId,
'entry_type' => 'processing_fee',
'amount_cents' => -$stripeFeeCents,
'currency' => $currency,
'description' => 'Underlying payment processor fee',
]);
}
// 4. Transfer to connected account
if ($merchantNet > 0) {
self::record([
'payment_id' => $paymentId,
'merchant_id' => $merchantId,
'platform_profile_id' => $platformProfileId,
'entry_type' => 'transfer',
'amount_cents' => $merchantNet,
'currency' => $currency,
'description' => 'Merchant net transferred to connected account',
]);
}
}
}
<?php
namespace App\Services;
use App\Core\Database;
use PDO;
class FeeEngine
{
/**
* Calculate application fee for a given payment context
*/
public static function calculate(int $amountCents, array $context = []): array
{
if ($amountCents <= 0) {
return [
'application_fee_cents' => 0,
'estimated_stripe_fee_cents' => 0,
'merchant_net_cents' => 0,
'fee_rule_id' => null,
'breakdown' => ['type' => 'zero_amount'],
];
}
$pdo = Database::pdo();
$merchantId = $context['merchant_id'] ?? null;
$productId = $context['product_id'] ?? null;
$profileId = $context['platform_profile_id'] ?? null;
// 1. Look for matching fee rule in priority order:
// a. Specific Merchant override -> b. Product rule -> c. Platform Profile rule
$rule = null;
if ($merchantId) {
$stmt = $pdo->prepare("SELECT * FROM `fee_rules` WHERE `merchant_id` = ? AND `is_active` = 1 LIMIT 1");
$stmt->execute([$merchantId]);
$rule = $stmt->fetch(PDO::FETCH_ASSOC);
}
// 2. Default fee parameters: 1.00% + $0.30
$feeType = $rule['fee_type'] ?? 'percentage_plus_fixed';
$percent = (float)($rule['percentage'] ?? 1.00);
$fixedCents = (int)($rule['fixed_cents'] ?? 30);
// 3. Compute application cut
$appFee = (int)round(($amountCents * $percent) / 100) + $fixedCents;
// 4. Compute Stripe standard 2.9% + $0.30 estimate
$estStripeFee = (int)round(($amountCents * 0.029) + 30);
$merchantNet = max(0, $amountCents - $appFee - $estStripeFee);
return [
'application_fee_cents' => $appFee,
'estimated_stripe_fee_cents' => $estStripeFee,
'merchant_net_cents' => $merchantNet,
'fee_rule_id' => $rule['fee_rule_id'] ?? null,
];
}
}
<?php
namespace App\Services;
use App\Core\Database;
class FlowService
{
/**
* Trigger workflows listening for an event
*/
public static function trigger(int $businessId, string $eventName, string $entityType, int $entityId, array $data = [], ?int $clientId = null)
{
// 1. Built-in Core Automatic State Transitions
self::executeCoreRules($businessId, $eventName, $entityType, $entityId, $data, $clientId);
// 2. Custom User-Configured Workflows
$workflows = Database::fetchAll(
"SELECT * FROM workflow_definitions WHERE business_id = ? AND trigger_event = ? AND is_active = 1",
[$businessId, $eventName]
);
foreach ($workflows as $wf) {
self::executeWorkflow($wf, $entityType, $entityId, $data, $clientId);
}
}
private static function executeCoreRules(int $businessId, string $eventName, string $entityType, int $entityId, array $data, ?int $clientId)
{
// A. When an Invoice is Paid -> Unlock deliverables tied to this invoice!
if ($eventName === 'invoice.paid') {
$deliverables = Database::fetchAll(
"SELECT * FROM deliverables WHERE business_id = ? AND invoice_id = ? AND is_unlocked = 0",
[$businessId, $entityId]
);
foreach ($deliverables as $d) {
Database::query("UPDATE deliverables SET is_unlocked = 1, unlocked_at = NOW() WHERE id = ?", [$d['id']]);
EventService::dispatch($businessId, 'deliverable.unlocked', 'deliverable', $d['id'],
"Deliverable '{$d['title']}' unlocked automatically upon invoice payment!", [
'invoice_id' => $entityId,
'deliverable_id' => $d['id']
], $d['client_id']);
}
}
// B. When a Contract is Signed -> Auto-generate 50% deposit invoice
if ($eventName === 'contract.signed') {
$contract = Database::fetch("SELECT * FROM contracts WHERE id = ?", [$entityId]);
if ($contract && $contract['deposit_cents'] > 0) {
// Auto-generate invoice and email client with Stripe link
$lastInv = Database::fetch("SELECT number FROM invoices WHERE business_id=? ORDER BY id DESC LIMIT 1", [$businessId]);
$nextNum = $lastInv ? 'INV-' . (intval(substr($lastInv['number'], 4)) + 1) : 'INV-1001';
$publicToken = bin2hex(random_bytes(32));
Database::query("
INSERT INTO `invoices` (`business_id`, `client_id`, `number`, `status`, `currency`, `subtotal_cents`, `total_cents`, `date_issued`, `date_due`, `public_token`)
VALUES (?, ?, ?, 'sent', 'USD', ?, ?, CURDATE(), DATE_ADD(CURDATE(), INTERVAL 7 DAY), ?)
", [$businessId, $contract['client_id'], $nextNum, $contract['deposit_cents'], $contract['deposit_cents'], $publicToken]);
}
}
}
}
<?php
// Recurring Invoice Cron Job: Run daily via system crontab
define('APP_ROOT', dirname(__DIR__));
require APP_ROOT . '/vendor/autoload.php';
$config = require APP_ROOT . '/config.php';
use App\Core\Database;
Database::init($config['db']);
$today = date('Y-m-d');
// Find active subscription profiles due for run
$profiles = Database::fetchAll(
"SELECT * FROM recurring_profiles WHERE is_active = 1 AND next_run_date <= ?",
[$today]
);
foreach ($profiles as $p) {
$pdo = Database::pdo();
$pdo->beginTransaction();
try {
// 1. Generate sequential invoice number
$lastInv = Database::fetch("SELECT number FROM invoices WHERE business_id=? ORDER BY id DESC LIMIT 1", [$p['business_id']]);
$nextNum = $lastInv ? 'INV-' . (intval(substr($lastInv['number'], 4)) + 1) : 'INV-' . rand(1000, 9999);
$token = bin2hex(random_bytes(16));
// 2. Insert new invoice from recurring template
$stmt = $pdo->prepare("
INSERT INTO invoices (business_id, client_id, number, status, currency, subtotal_cents, total_cents, date_issued, date_due, public_token, platform_fee_cents)
VALUES (?, ?, ?, 'sent', 'USD', ?, ?, ?, ?, ?, ?)
");
$stmt->execute([
$p['business_id'], $p['client_id'], $nextNum,
$p['amount_cents'], $p['amount_cents'],
$today, date('Y-m-d', strtotime('+7 days')),
$token, $p['platform_fee_cents'] ?? 300
]);
$invoiceId = $pdo->lastInsertId();
// 3. Compute and advance next run date
$nextRun = date('Y-m-d', strtotime('+1 month', strtotime($today)));
if ($p['frequency'] === 'weekly') {
$nextRun = date('Y-m-d', strtotime('+1 week', strtotime($today)));
}
$pdo->prepare("UPDATE recurring_profiles SET next_run_date = ?, last_run_date = ? WHERE id = ?")
->execute([$nextRun, $today, $p['id']]);
$pdo->commit();
} catch (Exception $e) {
$pdo->rollBack();
error_log("Failed recurring run for profile {$p['id']}: " . $e->getMessage());
}
}
Quantifiable Infrastructure Performance
Measurable engineering achievements delivered across ledger reconciliation, transaction commit speed, and cross-border currency reach.
“Nexovex didn’t just build another invoice tool; they engineered a rock-solid financial backbone. From the mathematical precision of our double-entry ledger to the seamless Stripe Connect marketplace split and automated deliverable escrow unlocking, our platform now operates with banking-grade security and zero accounting drift. Their fintech depth is world-class.”
Build High-Throughput FinTech Platforms with Nexovex
Whether you are developing a multi-party marketplace, implementing double-entry accounting rails, or automating complex billing lifecycles, our team delivers production software engineered for scale and precision.