QuickBooks Class Tracking for Stripe Revenue

Stripe has no class field, so a class reaches QuickBooks only through the product your transaction maps to. That one fact explains blank fee classes,...

Acodei Content Team · 9/17/2026 · 16 min read

You turned on class tracking in QuickBooks, turned it on in Acodei, and the Class column on your synced Stripe sales is still empty. Or it is filled in correctly on every sales receipt and blank on every Stripe fee. Or one invoice came through with two different classes and you cannot work out why the sales receipt next to it only ever gets one.

These look like three separate bugs. They are one design fact, seen from three angles, and once you have it the rest of this is bookkeeping rather than troubleshooting.

Here is the fact. Stripe has no class field. There is no property on a charge, an invoice line, or a payout that says "Wholesale" or "Clinic B". A class is a QuickBooks concept, so the class has to be attached on the QuickBooks side, and the only QuickBooks object your sync has any control over is the product it posts to. That is the whole mechanism. Acodei's documentation says it in one line: in QuickBooks, "classes serve as categories linked to your products".

So you are never really mapping a Stripe transaction to a class. You are mapping it to a product, and the product carries a class. Every question below falls out of that.

Start a free trial and see how your own Stripe products land in QuickBooks before you build a class list around them.

Turning it on, and what turning it on actually does

Class Tracking is a premium Acodei feature. You enable it from the Acodei Dashboard by opening the Account Mapping module, scrolling to the Class Tracking section, clicking yes, then saving with the blue Save Changes button at the bottom.

What that switch does is narrower than most people expect. In Acodei's own words, at the simplest level Class Tracking "will add classes to your sales receipts and invoices, as indicated in your default products."

Read that phrase carefully: as indicated in your default products. The class comes from the QuickBooks product the transaction maps to, and the switch is what tells the sync to carry it through. If your products carry no class, turning the feature on changes nothing you can see. That produces the most disorienting version of the symptom, because the feature is on, the save went through, and the column is still empty.

The QuickBooks side has its own prerequisites, and they are worth confirming before you debug anything in Acodei. Class tracking is available on QuickBooks Online Plus and Advanced only, and when you enable it you choose whether a class applies to the entire transaction or to each row on it. Our definition of QuickBooks class tracking covers that side in full, including how classes differ from locations and projects.

You are not mapping classes, you are mapping products that carry classes

This is where the setup stops being a switch and starts being a decision.

Because the class rides on the product, a product can only ever carry one class. If you sell two things and track two segments, one product per thing is not enough. Acodei's documentation walks through exactly this case. With two products (A and B) and two classes (A and B), "each product-class combination needs its own setup":

QuickBooks productStripe productClass
Product 1Product AClass A
Product 2Product AClass B
Product 3Product BClass A
Product 4Product BClass B

Four QuickBooks items for two things you sell. The arithmetic is multiplication, not addition, and it is the part of class tracking that catches people out six months later rather than on day one. Ten products and four regions is forty items. Forty items is a list nobody maintains accurately, and a class list applied inconsistently produces reports that look authoritative and are quietly wrong.

There is a real design decision buried in that table, and it is worth making deliberately: keep whichever axis changes less often as the class axis. Segments that are stable (three clinics, two legal entities, four product lines you have sold for years) work well. Segments that churn (campaigns, cohorts, sales territories that get redrawn each January) turn into item sprawl.

Intuit's guide to adding product and service items is the reference for building these, and one setup rule overrides anything it says about tax: every QuickBooks product used in Acodei mapping must be marked non-taxable. Marking mapping products taxable in QuickBooks conflicts with the sales and payout math. Tax calculated by Stripe reaches QuickBooks through the Stripe Tax feature instead.

Why an invoice can carry several classes and a sales receipt carries one

This is the distinction that resolves the third symptom at the top of this post, and it is the most useful thing to know about class tracking on Stripe revenue.

A real-time sales receipt gets one class. When a charge arrives, the mapping engine walks your rules from top to bottom, and the moment one matches it stops searching and uses that rule to decide the QuickBooks product, and with it the linked income account. One match, one product, one class for that record. Ordering matters enormously here, because a broad rule sitting above a specific one will intercept transactions meant for the specific one. Our guide to why a Stripe charge maps to the wrong QuickBooks product covers the ordering failure modes in depth.

A synced invoice can get several. Invoice Sync does not treat a Stripe invoice as one lump. When a Stripe invoice is finalized, Acodei creates a QuickBooks invoice that reproduces every line item and tax line as your mapping settings allow, and each invoice line uses the product returned by product mapping, falling back to the default product when nothing matches. Different lines can resolve to different products. Different products can carry different classes. So a three-line Stripe invoice covering a subscription, an onboarding fee, and an add-on can land in QuickBooks carrying three classes, one per row, provided each of those lines resolves to a product that carries the class you want and your QuickBooks file is set to apply a class to each row rather than to the whole transaction.

That asymmetry surprises people, and it is not arbitrary. An invoice arrives with structured line items, so there is something to resolve per line. A charge arrives as a single amount, so there is one thing to resolve.

The practical consequence: if you need per-line segment reporting out of Stripe revenue, the invoice path gives it to you and the real-time sales receipt path does not. That is a reason to care about which record type your account produces, which is a different setting and a different decision, covered in daily summary versus real-time sync.

Why the class is blank on your Stripe fees

This one has a specific and slightly unsatisfying answer, and it is worth stating plainly because support sees it repeatedly.

During onboarding, Acodei automatically creates a QuickBooks product called Stripe Fees - Acodei, mapped to an account you choose, and assigns fees to it. That product is created by the setup process, not by you, and like any other product it carries a class only if someone puts one on it. So on an account where someone has carefully built product-class items for the things they sell and never touched the fee product, the result is exactly the reported symptom: a class on the sales lines, nothing on the fee line.

The fix follows the mechanism. The fee line's class comes from whatever product the fee resolves to, so you either put a class on the fee product or give fees their own mapped products. On accounts eligible for the newer product mapping, advanced fee mapping is live, and transaction fees resolve through your mapping rules with more granularity, falling back to the legacy fee product when no rule matches. That is what makes per-class fee tracking possible at all: without it, every fee in the account shares one product and therefore at most one class.

Two limits are worth knowing before you plan around this.

Fees are never added to invoices. Putting a fee on the invoice would throw the invoice total off and break the match against the payment, so on Invoice Sync accounts fees appear as an expense, or on the bank deposit if you are on Undeposited Funds, and never as an invoice line.

A fee recorded as an expense is not a product line at all. Fee Management lets fees appear as a line on the sales receipt, as a line on the bank deposit (Undeposited Funds only), or as an expense (the default on a non-Undeposited-Funds holding account, and available under Undeposited Funds when Invoice Sync is on). The expense route is a purchase rather than a product line, so the class question for fees only arises on the routes where a fee is a line item carrying a product. If your fees are posting as expenses and you need them classed, that is a QuickBooks-side expense coding question rather than a mapping one. The guide to reconciling Stripe fees in QuickBooks is the place to settle which of the three routes you actually want.

One more, because it bites during cleanup: changing your fee method does not rewrite history. Historical transactions keep the treatment they were written with until you resync them.

What a mapping rule can actually see, and why "sales rep" usually is not on the list

Every class question eventually turns into a mapping question, and mapping can only act on properties that exist on the transaction. There are six matching techniques:

  • Stripe product, with pricing tier. Uses the product ID and the price ID, so monthly and annual prices of the same product can resolve to different QuickBooks products and therefore different classes.
  • Stripe product, without pricing tier. Everything for that product goes to one QuickBooks product regardless of price. Less granular, simpler to keep correct.
  • Description indicator. A substring match, not case-sensitive. Where the description is read from depends on the transaction: for a charge it is the charge or payment description then the PaymentIntent, for a Stripe-invoice-linked transaction it is the invoice line item description, and for a Checkout session it is the product description then the session line item description.
  • Transaction value. Compares the gross amount before fees, and the currency has to match too. Brittle by nature: a discount, a price change, or a promotion breaks the match.
  • Metadata. Read in a fixed order: charge or payment first, then PaymentIntent, then invoice, then subscription.
  • Stripe account. For accounts connecting more than one Stripe account, which is the cleanest option when your segments correspond to the accounts themselves.

Now the sales-rep question, which comes up constantly. A sales representative is not a property of a Stripe charge. It is not the product, not the price, not the amount, and not the Stripe account. So the only rule type that can reach it is metadata, and only if something is writing a rep identifier into metadata on the charge or the subscription in the first place. If your checkout does that, rep-level classes work. If it does not, no amount of configuration will produce them, because the information never arrives.

Two metadata limits shape what is buildable:

No multi-key matching. You cannot write one rule that requires metadata["region"] = "US" and metadata["productType"] = "ABC". If your class scheme needs two dimensions at once, encode both into a single key at the source.

No matching several lines of one transaction by metadata. You cannot map product_a, product_b, and product_c onto different lines with different amounts inside a single sales receipt this way.

And metadata is only as reliable as the thing writing it. Missing keys, different spellings, stray spaces, and special characters all cause a rule to miss. The broader question of which amounts on a Stripe transaction mapping can reach at all, including shipping, prorations, and discounts, is covered in the amounts product mapping cannot reach.

When nothing matches

If no rule matches, one of two things happens, depending on how the account is configured: the transaction falls back to a single catch-all default product, or it throws a sync error because the configuration does not allow uncategorized items.

For class tracking this distinction matters more than it does for plain product mapping. The catch-all is one product, so it carries at most one class. Every unmatched transaction therefore lands under the same segment label, which is worse than landing with no label at all: a blank class is visibly missing, while a wrong class quietly makes a segment report look complete. If you are running segment P&L off this data, the error behaviour is the safer setting, and the Sync Errors queue is where those transactions wait.

What changing your class setup does not do

Mapping rules are not versioned, and a change takes effect for future transactions only. Editing a rule, adding a product-class item, or putting a class on the fee product does not reach back and reclassify anything already in QuickBooks.

There is also no way to reconstruct which rule fired for an old transaction from the current rule list, because the list keeps no history. Acodei does log the rule used and the QuickBooks item ID per transaction, so the record exists at transaction level even though the configuration does not keep a timeline.

So the sequence for a cleanup is always the same, and the order is not optional:

  1. Build the product-class items in QuickBooks.
  2. Fix the mapping rules and their order.
  3. Only then repair history.

Fix the rules first, because rebuilding an old record runs it against the rule set as it stands now. Rebuild against an unfixed list and you reproduce the original mistake with a fresh timestamp. Resyncing a Stripe payout covers what the repair actually does to the QuickBooks side and the units it operates on.

The same applies to history you imported. A historical import dispatches through the standard jobs on a dedicated queue, so all mapping, fee, tax, and holding-account rules apply identically to live sync. Imported records are not second-class records, and that cuts both ways: they reflect the rules as those rules stood when the import ran, not as they stand now.

A short diagnosis when the class is wrong or missing

Work down this list. It is ordered by how often each one turns out to be the cause.

  1. Is a class on the product? Open the QuickBooks item the transaction posted to and check. This is the answer most of the time.
  2. Which product did it post to? If it landed on the catch-all or the fee product, the class question is downstream of a mapping question.
  3. Is Class Tracking on in both places? Enabled in QuickBooks (Plus or Advanced), and enabled in Acodei under Account Mapping.
  4. Per-transaction or per-row? If you expected several classes on one invoice and got one, check the QuickBooks setting before touching the mapping.
  5. Is it a fee? Then check the fee product, and check whether fees are posting as expenses rather than as lines.
  6. Did the transaction predate the change? Rules are not retroactive. If it synced before you built the item, only a resync moves it.
  7. Is it a sales receipt when you needed per-line detail? One record, one product, one class. No configuration changes that.

The short version

A class in QuickBooks is a label on a product, and your Stripe transaction reaches that label only by resolving to that product. Everything else is consequence. Invoices can carry several classes because each line resolves its own product. Sales receipts carry one because one rule match decides the whole record. Fees are blank because the product they use was created by the setup process and nobody put a class on it. Sales reps usually cannot be classed because a rep is not a property that arrives with the payment.

Get the product list right and the class list follows. Get it wrong and you will be maintaining a multiplication table by hand.

FAQ

Where in Multiple Product Mapping do I assign a QuickBooks class to a Stripe product?

You do not assign a class in the mapping screen. Mapping chooses the QuickBooks product, and the class comes from that product. To send a Stripe product to a specific class, create a QuickBooks item that combines the product and the class, then map the Stripe product to that item.

Why is the Class field blank on my Stripe fees?

Because fees post to the QuickBooks product they resolve to, and the fee product Acodei creates during onboarding, Stripe Fees - Acodei, carries no class unless someone adds one. Put a class on that product, or use advanced fee mapping to route fees to your own products. If your fees are recorded as expenses rather than as line items, they are not product lines at all and are classed on the QuickBooks side.

Can one Stripe invoice use more than one QuickBooks class?

Yes. Each line on a synced invoice uses the product returned by product mapping, so different lines can resolve to different products carrying different classes. You also need your QuickBooks file set to apply a class to each row rather than to the entire transaction.

Can I use class tracking to track different sales reps selling the same product?

Only if the rep identifier reaches Stripe as metadata on the charge or subscription. A rep is not the product, the price, the amount, or the Stripe account, so metadata is the only rule type that can see it. If nothing writes the rep into metadata, the information never arrives and no configuration can recover it.

Do I really need a separate QuickBooks product for every product and class combination?

Yes, when you want that combination to post automatically. A product carries one class, so two products and two classes need four items. This is why it pays to use the slower-changing dimension as your class axis.

Will adding a class to a product fix transactions that already synced?

No. Mapping changes apply to future transactions only and are not versioned. Existing records keep what they were written with until they are resynced, and a resync rebuilds them against your current settings, so fix the rules and the items before you repair history.

I turned on Class Tracking in Acodei and nothing changed. Is it broken?

Almost certainly not. The setting carries through the class already on your mapped products. If those products have no class, there is nothing to carry, and the visible result is no change at all.

Does turning on class tracking change which account my revenue posts to?

No. A class is a reporting label and does not move money. The income account comes from the QuickBooks product the transaction maps to, which is the same product the class rides on, so changing the mapped product can change both at once. Intuit's guide to changing the account on a product or service item covers the account side.

Getting your segments right

Class tracking on Stripe revenue is a product-list discipline wearing a reporting-feature costume. Decide the segment axis first, keep it coarse enough to maintain, build the combination items, then map to them. Do that and segmented P&L arrives without a single manual journal entry.

Acodei's class mapping works on top of the same product mapping that routes your revenue, so the class list you build is the one your Stripe sales already respect. Start a free trial and map a single product and class pair before you commit to the full grid.

Share

Automate your Stripe to QuickBooks sync

Save hours every month. Acodei automatically syncs your Stripe transactions, invoices, and payouts to QuickBooks Online.

How Acodei handles this in your stack

Stripe QuickBooks Integration

See how Acodei syncs Stripe payments, fees, refunds, invoices, and payouts into QuickBooks Online automatically.

Or go straight to a capability

Get more operational finance guides like this one

We will only send high-value product and finance content.