Stripe Connect Marketplace Accounting Workflow
A practitioner's guide to posting charges, fees, transfers, refunds, disputes, and reserves into a marketplace ledger that reconciles cleanly.
Most marketplace accounting problems trace back to a single mistake: treating the Stripe bank payout as if it were revenue. The payout is the net residue of dozens of separate economic events, and posting it as one income line erases the platform's commission, the seller's liability, and every fee and dispute buried inside it. A correct workflow decomposes the payout before anything touches the ledger.
This guide traces each Stripe Connect balance-transaction category into its proper accounting home: receivables, commission revenue, seller liabilities, processing expense, and suspense. It uses Nordlet's documented import and settlement endpoints as the posting mechanism, includes a worked settlement example, and ends with a reconciliation checklist you can run before every close.
Identify the Connect charge model before designing anything
Accounting rules cannot be written until you know which charge model each payment flow uses. The model determines whose Stripe balance carries the charge, who bears fees, and where refunds and disputes hit first.
| Connect model | Charge created on | Bears Stripe fees | Refunds/disputes reduce | Accounting consequence |
|---|---|---|---|---|
| Direct charges | Connected account | Configurable per party | Connected account balance | Platform records its application fee as revenue; seller payment activity lives mostly on the connected-account ledger |
| Destination charges | Platform, with immediate transfer to one connected account | Platform | Platform | Platform records the customer receivable and Stripe fee; seller share is a payable, not revenue |
| Separate charges and transfers | Platform charge, then one or more separate transfers | Platform | Platform | Charge and seller transfers are separate events; seller liability tracked independently of the customer charge |
Stripe's own guidance on how charges work in a Connect integration confirms that for destination charges and separate charges and transfers, the platform balance bears payment fees, refunds, and chargebacks. For direct charges, the connected account receives the charge, and fees can be debited from either party.
The practical rule: do not say "the Stripe payout is seller revenue" or "the seller pays the fees" until you have written down the charge model for each flow. Store that model alongside every transaction. Mixing direct and destination charges under one posting rule is the fastest way to misstate both revenue and liability.
This guide assumes destination charges or separate charges and transfers, because that is where the platform balance carries the accounting weight and where most marketplace ledgers get built.
Map the funds flow before importing a single row
Before touching an import, draw a one-page transaction map for each flow:
Customer payment
-> Stripe charge / payment balance transaction
-> Stripe fee
-> platform application fee (commission)
-> transfer to connected account
-> refund or dispute (if applicable)
-> Stripe payout
-> bank receipt
Each arrow is a distinct balance transaction with its own ID, category, amount, and dates. Treat the Stripe balance as a bank-like clearing account: charges flow in, fees and transfers flow out, and the payout moves the remainder to the real bank. Nordlet's bank and payment import documentation recommends exactly this treatment for ordinary Stripe activity.
Choose the right Stripe source report
For automatic-payout settlement batches, use Stripe's Payout reconciliation, itemized report. It gives one row per balance transaction, groups rows by reporting_category, associates each with an automatic_payout_id, and provides gross, fee, and net totals. Stripe's report selection guide documents this report and confirms charge_id, connected_account_id, and destination_payment_id as available Connect fields.
Where automatic payouts are not enabled (some manual-payout arrangements), use the Balance report instead. Do not treat a Dashboard payout summary as sufficient evidence for posting. The summary proves the batch total; only the itemized report explains the components.
Stripe recommends classifying by reporting_category rather than the older type field, and each row carries a source ID that joins to the underlying object. Note the timing constraint: Stripe states daily report data is normally available by noon the following day, and instant payouts cannot be cleanly assigned to individual transactions, so they need separate transaction-history reconciliation.
Classify every balance transaction by category
Use reporting_category as the primary classifier, then inspect source_id, charge_id, and descriptions. The mapping that matters:
| Stripe activity | Reporting category | Accounting interpretation |
|---|---|---|
| Customer charge, card or local payment method | charge |
Customer-funded receivable or sale settlement |
| Refund | refund |
Reversal of the original customer payment |
| Processing fee withheld by Stripe | fee |
Payment processing expense |
| Platform application fee | platform_earning |
Commission revenue |
| Refunded application fee | platform_earning_refund |
Reduction of commission revenue |
| Transfer to connected account | transfer |
Reduction of seller liability |
| Reversed transfer | transfer_reversal |
Recovery from the connected account |
| Chargeback | dispute |
Chargeback loss; inspect the source dispute object |
| Chargeback won or reversed | dispute_reversal |
Recovery of a previously booked chargeback |
| Payout to bank | payout |
Bank movement, not revenue |
| Reversed payout | payout_reversal |
Funds return to the Stripe balance |
| Held reserve | connect_reserved_funds / risk_reserved_funds |
Restricted funds, not an expense by default |
| Long-standing negative balance collection | connect_collection_transfer |
Funding or recovery event needing a risk policy |
One terminology caution: the older balance-transaction type field uses different labels for the same events, among them payment, application_fee, and adjustment. Stripe's balance transaction types documentation lists both vocabularies. Do not mix a type value into a reporting_category rule, and do not invent a category such as dispute_loss that Stripe does not export. If an export carries a label you do not recognise, preserve the exported value and verify it against the source object.
Post normal marketplace activity to the ledger
For a platform on destination charges or separate charges and transfers, the conceptual entries are these.
Customer charge (customer money enters the Stripe clearing balance):
Dr Stripe clearing Gross customer charge
Cr Trade receivables Gross customer charge
Stripe processing fee:
Dr Stripe fee expense Stripe fee
Cr Stripe clearing Stripe fee
Do not net the Stripe fee against revenue unless your accounting policy explicitly requires and supports net presentation.
Platform commission (your revenue, carved out of what would otherwise be owed to the seller):
Dr Seller payable Commission amount
Cr Commission revenue Commission amount
Seller transfer (settling money owed, not an expense):
Dr Seller payable Transfer amount
Cr Stripe clearing Transfer amount
A transfer is never automatically an expense. The seller's share becomes a liability when the charge lands, and the transfer discharges that liability. Nordlet's settlement posting rules follow this: platform_earning rows post to commission revenue while transfer rows reduce seller liability. The documented default posting keys are settlements.commissionRevenue (default 5001), settlements.sellerPayable (default 4499), settlements.fees (default 6800), and settlements.suspense (default 4440), each overridable per company through the posting rules in the Nordlet API.
Handle refunds against the original sale, not as loose bank items
A refund links to the original charge or invoice. Conceptually:
Dr Refunds / sales reversals Refund amount
Cr Trade receivables Refund amount
The real entry depends on whether the sale was recognized, whether tax must reverse, and whether a platform application fee was refunded. A single refund can produce a receivable reversal, a tax reversal, an application-fee refund, a transfer reversal or seller-payable reduction, and a Stripe-fee consequence that must be checked rather than assumed.
The timing trap: a refund often settles in a later payout than the original charge. Prefer the itemized payout-reconciliation report over a synthesized refund from a charge-level export. Nordlet's documentation warns explicitly that a refund synthesized from a Payments export is only an approximation when the refund settles later. The settlement importer can ingest the refund row, match it to the original sale, and reverse the receivable when the batch posts.
Treat disputes separately from refunds
A dispute is a cardholder or issuing-bank claim, and Stripe can debit both the disputed amount and a dispute fee before resolution. For destination charges and separate charges and transfers, Stripe debits the platform balance for both, per its refunds and disputes guidance. The platform can attempt recovery by reversing the seller transfer.
A lost dispute, from the platform's side:
Dr Chargeback loss / receivable reopened Disputed amount
Dr Dispute-fee expense Dispute fee
Cr Stripe clearing Combined amount
If the seller bears the loss and recovery is confirmed:
Dr Seller payable / recovery account Recoverable amount
Cr Chargeback recovery Recoverable amount
Do not book seller recovery just because a transfer reversal was requested. Verify the reversal was created, succeeded, and appears in the Stripe balance. If the dispute is won, Stripe returns the disputed amount through a dispute_reversal row; reverse the chargeback loss and separately handle any dispute fee Stripe does not return. Nordlet matches chargeback rows using the charge_id of a previously matched charge, from the same file or from an earlier import.
A worked settlement example
Take one automatic payout batch. The itemized report contains:
- A
chargerow: gross 100.00, Stripe fee 3.20, net 96.80 - A
platform_earningrow: 15.00, the platform's commission - A
transferrow: 81.80 to the connected seller - A
refundrow from an earlier sale: gross 20.00, settling in this batch - A
payoutrow: the batch total moving to the bank
The payout composition, following Stripe's settlement identity:
Gross charges 100.00
- refunds 20.00
- Stripe fees 3.20
- transfers 81.80
= net to platform balance -5.00
The platform_earning row does not move money a second time. It names the 15.00 that stays in the platform balance once the fee and the seller transfer are out, so the platform can recognize commission revenue instead of inferring it.
Here the seller transfer plus the refund exceed net charge activity, so the batch nets to a small negative and reduces the next payout or draws on balance. The posted journal reverses the refunded receivable, recognizes 15.00 commission revenue, records 3.20 fee expense, reduces seller payable by the transfer, and books the refund reversal. The bank line matches the net that reaches the account. No single figure equals "revenue," which is the point.
Import and post through Nordlet's settlement endpoint
For payout-level reconciliation, use:
POST /v1/bank/settlements/import
with the Stripe provider and the itemized CSV. Nordlet groups rows by automatic_payout_id, turns each payout into a settlement batch with gross, fee, and net totals, skips re-imports of an already posted payout, skips payout rows from the settlement composition, and auto-matches charge, refund, and dispute rows using order, invoice, PaymentIntent, charge, source, or metadata references. Stripe splits the itemized report into one file per section, so import the charge, refund, and fee files together: rows belonging to a payout that is already imported but not yet posted merge into the existing batch. This is an import-and-post workflow driven by files and settlement endpoints, not a live Stripe connector; the features page lists what the bank and settlement side covers.
Match in order: charges to invoices, refunds to original charges, disputes to original charges, commission rows to commission treatment. Keep Stripe fees, adjustments, reserves, and payout rows out of invoice matching. Nordlet's payment reconciliation glossary states that fee and adjustment lines are not matchable to invoices by design; route unresolved money-bearing items to suspense. Manual correction uses bank/settlements/match { lineId, invoiceId }, with a null invoiceId to unmatch.
Then post one balanced batch:
POST /v1/bank/settlements/post
This creates one balanced journal, settles matched invoices, debits the bank account's ledger account for the net payout, debits fees, credits receivables for charges, reverses receivables for refunds and chargebacks, splits unmatched marketplace charges between commission revenue and seller payable when commissionPercent is supplied, and sends unresolved amounts to suspense. Any category it does not recognize also lands in suspense, and the response names those categories in a warning rather than absorbing them silently.
Reconciliation checklist
Run these assertions before every close:
- No duplicate
balance_transaction_id - No duplicate
(provider, payout_id)settlement batch - Sum of line
netequals the batch net - Batch net equals the bank payout, subject to timing and currency policy
- Every refund has an original charge or a logged exception
- Every dispute has a dispute or charge reference
- Every transfer has a connected-account ID
- Every
platform_earningrow has a defined commission treatment - Suspense is zero or fully reviewed, including any unrecognized categories named in the posting warning
- Seller payable is not negative without an approved advance or recovery policy
- Posted batches cannot be silently re-imported or reposted
- A payout in a currency other than the company's base currency converts at the payout-date rate, with the difference against each invoice's own rate booked as a realized exchange gain or loss; a payout that mixes currencies is rejected at import
Reconcile at three levels: row (each transaction has a preserved ID, category, amount, currency, source), payout (itemized nets equal the Stripe payout and bank receipt), and ledger (the posted journal balances and produces the intended revenue, fee, receivable, seller-liability, and suspense positions). For seller balances specifically, verify that opening seller payable plus new seller share, less transfers and valid reversals, equals closing seller payable.
The recurring failure across every marketplace ledger is the same one it started with: collapsing a structured payout into a single number. Keep the components separate, anchor each to a stable Stripe identifier, and let suspense hold anything you cannot yet explain. A clean close is what an auditor will trust.
FAQ
Is the Stripe payout the platform's revenue?
No. The payout is the net of charges, refunds, processing fees, seller transfers, disputes, and adjustments that happened to settle in the same batch. Posting it as one income line erases the seller liability and the processing expense inside it. For an agent marketplace, revenue is the commission, which the platform_earning rows identify.
Which Stripe report should I reconcile against?
The Payout reconciliation, itemized report, because it gives one row per balance transaction with a reporting_category, an automatic_payout_id, and gross, fee, and net amounts. A Dashboard payout summary proves only the batch total. Where automatic payouts are not enabled, use the Balance report instead.
Should a transfer to a seller be booked as an expense?
No. The seller's share becomes a liability the moment the customer charge lands, and the transfer discharges that liability. Booking transfers as expense double-counts cost and leaves the seller payable permanently overstated.
What happens to a Stripe row whose category the importer does not recognize?
It posts to the settlement suspense account, default 4440, and the posting response returns a warning naming the categories that went there. Reserves and unusual adjustments typically land this way, which is deliberate: the money stays visible and the journal stays balanced until someone decides where it belongs.
How are refunds that settle in a later payout handled?
They arrive as a refund row in the later payout's itemized report and are matched back to the original charge through the charge_id of the earlier matched charge. A refund synthesized from a charge-level Payments export is only an approximation in this case, so the itemized report is the safer source.