B2B ecommerce on Solidus: price lists, quotes, net terms and VAT

Wholesale buying works differently from retail: companies with several buyers, negotiated prices, quotes, invoices on 30 or 60 days and VAT that depends on where the goods go. In this article I map each of those onto Solidus with an invented Leeds catering wholesaler, show what Solidus ships today and what is custom code, go through UK late payment law, VAT after Brexit and the April 2029 e invoicing plan, and finish with a build order, costs and the mistakes that sink B2B shops.

Wholesale is not retail with a discount

Ask the big platforms about B2B and you tend to get one of two answers. Either it is an app that bolts a login wall and a percentage discount onto a consumer shop and calls it wholesale. Or it is the upper plan, where the features exist but the price grows with them.

Neither fits a wholesaler with a few hundred trade customers. What that business needs is a shop that understands five things: a company is not a person, a price is the result of a negotiation, an order often starts as a quote, most customers pay on invoice, and the tax treatment depends on where the goods actually go.

Take an invented business to keep this concrete. Kirkstall Catering Supply (kirkstallsupply.example) is a Leeds wholesaler of catering disposables and small kitchen equipment with about 400 trade accounts: independent restaurants, a Manchester hotel group with twelve sites, school caterers, and a handful of customers in the Netherlands and Ireland. Today its sales team works from phone calls, PDFs and a spreadsheet. I will use Kirkstall throughout.

One warning first. Solidus, the open source Rails ecommerce framework, does not have a "B2B mode". The current release line is 4.8, with 4.8.1 out on 5 November 2026.1 What it has is a set of plain models for orders, prices, users, payments and taxes, and an architecture that expects you to extend them. Every feature in this article is something built on top of those models. That is more work than ticking "enable wholesale". It is also why the result can match how your customers actually buy. If you have not read my platform comparison, the short version is that Solidus is the platform you own outright, and B2B is where owning it pays off soonest.

How trade buying differs

List what Kirkstall's sales team does in a day and the gap with a consumer shop becomes obvious.

A customer is a company with several people. The chef who places the order is not the operations manager who approves it, and neither of them pays the invoice. The hotel group has a rule that anything over £5,000 needs a second signature.

Prices are negotiated. One restaurant pays list less 12%. The hotel group pays list less 20% on disposables and list on equipment, because that is what was agreed three years ago. The school caterer has fixed unit prices for a year under a framework contract. The Dutch customer is invoiced in euros.

Orders often start as quotes. The hotel group asks for a price on two pallets of takeaway packaging delivered to its Manchester site, a rep works out the freight, sends a quote, the group gets it approved, and three weeks later it becomes an order. The quote number goes on the purchase order, and the invoice has to reference both.

Almost nobody pays at checkout. They pay on invoice, 30 or 60 days, against a credit limit someone in accounts set years ago.

Repeat orders dominate. The same fifty items every fortnight, in cartons of a fixed size, typed in by product code rather than browsed.

Delivery goes to many sites. One account, twelve kitchens, each with its own address and delivery window.

The tax treatment depends on the destination. A delivery to Leeds carries UK VAT. A delivery to Rotterdam is an export. A delivery to a customer in Northern Ireland follows its own rules. Get it wrong and the invoice is wrong.

And all of it has to talk to an ERP or accounting system, because that is where stock, prices and balances actually live. The shop is a window onto it.

The account, not the user, is the customer

The first modelling decision carries everything else, and it is the one consumer platforms get wrong by default. In a consumer shop the user is the customer. In B2B the company is the customer and the users belong to it.

In Solidus I model this as an account (some businesses call it a company or a customer group), and every user belongs to one account with a role: buyer, approver, admin, and sometimes a read only role for someone who needs order history but places no orders. Addresses belong to the account, so a new buyer at a branch sees the right delivery sites at once. Orders belong to the account, with the user recorded as the person who placed them. Price list, credit limit, payment terms, VAT number and the assigned sales rep all sit on the account.

This sounds obvious. It is the one thing I insist on before any other code, because retrofitting it onto a shop where users are customers means touching every order, every address and every price lookup later. That retrofit costs more than building the account model on day one.

Approval chains live here too. The simplest useful version is a threshold on the account: orders above a value go into a pending approval state and the approver gets a notification. Per buyer limits and per product family sign off are possible, but I would not build them before a customer has asked twice. Most trade customers need the threshold and nothing else.

Price lists, and why promotions are the wrong tool

Solidus prices are explicit records. Each variant has prices, and each price carries a currency and, optionally, a country.2 When the shop needs a price, a price selector picks the matching one using a small pricing options object, which by default holds the currency and the country of the tax address. Both classes are configurable: the store setting variant_price_selector_class names the selector, and the selector names its pricing options class.3 That is the extension point. You give the pricing options a third attribute, the account's price list, and teach the selector to prefer a price from that list. Every price lookup in the cart, the admin and the API then resolves the contract price without further work.

So a price list is a named set of explicit prices per variant and currency. Contract tier A gets one, tier B another, and the list price is simply the price with no list attached, which is what a visitor who is not logged in sees.

Is there an extension that does this for you? I checked the Solidus organisation and the community extensions on GitHub in November 2026. There is no maintained price list extension. The nearest maintained piece is solidus_volume_pricing, which sets prices by quantity range per variant and supports Solidus 4.4 Contract price lists are custom code, roughly a few hundred lines with tests.

The alternative you see on many shops that pretend to do B2B is to leave the list price alone and apply a promotion for the customer group. Do not do this. Promotions are built to be temporary, conditional, stackable and shown as a discount. Contract prices are none of those. A chef does not want to see "list £84.00, your discount 12%". They want to see £73.92 on the product page, in search, in the export, on the quote and on the invoice, the same number every time.

Promotions also stack. Solidus now ships a reworked promotion system as its recommended one, which is better structured than the legacy system, but stacking a contract discount with a real campaign is still a business rule nobody wrote down.5 Here is the arithmetic when it goes wrong. Two percentage discounts applied one after the other multiply, as covered in percentages in the Foundations:

p=l (1−d1)(1−d2)p = l\,(1 - d_1)(1 - d_2)

where pp is the price the customer pays, ll is the list price, d1d_1 is the contract discount and d2d_2 is the campaign discount, both as fractions.

For a product listed at £84.00 with a contract discount of 12% and a free delivery weekend that marketing set up as 10% off everything:

p=84.00×0.88×0.90=66.53p = 84.00 \times 0.88 \times 0.90 = 66.53

The customer pays £66.53, so 1−p/l=0.2081 - p/l = 0.208: an effective discount of 20.8% that nobody approved, and accounts has to explain why the invoice does not match the contract.

Price lists are also what the ERP understands. Every serious ERP has customer specific prices or price groups, and mapping those onto Solidus price lists is a straightforward sync. Mapping them onto promotion rules is not.

One design rule: keep the number of lists small. One per contract tier, not one per customer. Four hundred customers with four hundred lists is unmaintainable and turns the ERP sync into a bottleneck. Five to ten tiers plus a few account level overrides on specific variants covers most wholesalers.

Pack sizes, minimums and what the warehouse needs

Trade customers buy in units the warehouse can pick: cartons of 500 cups, cases of six pans, a minimum order value per delivery. In Solidus these are variant attributes and cart validations. A variant carries its pack size and minimum, the cart rounds up or rejects quantities that do not fit, and the product page says what a pack contains. Minimum order value per delivery is an account or order rule that gates checkout. Quantity breaks, where 100 cartons cost less each than 10, are what solidus_volume_pricing already does.4

None of this is hard. It is a day of work with tests that saves the warehouse an hour a day, and it is usually missing from the first specification.

Quotes are orders that have not been placed yet

The usual approach to quotes is email. The buyer asks, the rep replies with a PDF, the buyer says yes, someone keys the order by hand. It works until the rep is on holiday, or the PDF and the order differ, or the customer disputes what was quoted.

A Solidus order has a state machine. Its checkout flow moves from cart through address, delivery, payment (only if payment is required) and confirm to complete, and the flow is defined in one block of the order model that a store can change.6 So a quote is an order held before checkout, with a quote record beside it: a quote number, an expiry date, the prices frozen at the moment of quoting, freight worked out and attached, and the rep who prepared it. The buyer sees it in their account. They accept it and it enters the normal checkout with everything filled in, or they ask for changes and it goes back to the rep. When it completes, the order references the quote number, and both appear on the invoice.

From quote to paid orderA buyer asks for a price and the rep builds a quote with frozen prices, freight and an expiry. If the buyer asks for changes, the quote goes back to the rep. If the buyer accepts before expiry, checkout runs with pay on invoice. The credit check asks whether the open balance plus this order stays within the credit limit. If yes, the order completes and goes to the ERP, which issues the invoice with order and quote number. If no, the order is held and accounts decide.yesasks for changesyesnoBuyer asks for a priceRep builds the quote: lines,frozen prices, freight, expiryBuyer accepts beforeexpiry?Checkout with address,delivery and pay on invoiceOpen balance plus thisorder within the creditlimit?Order completes and goesto the ERPOrder held, accounts decideERP issues the invoice withorder and quote number

The rep builds quotes in the admin: pick an account, add lines, override a price with a reason, add freight, set the expiry, send. That quote builder is the largest single piece of a B2B build, and it is worth the time because the sales team lives in it.

Two details matter. Frozen prices: the quote stores its own prices, so a price list change before acceptance does not alter what was promised. Expiry: quotes lapse automatically, with a reminder a few days before, because an old quote accepted at old prices is how margins quietly disappear.

Net terms are a payment method with a credit limit behind it

At checkout a trade customer does not enter a card. They pick "invoice, 30 days" and expect the order to go through. In Solidus a payment method is a class with a defined interface. The core even ships a minimal one for cheques, which needs no card or other payment source and simply records capture, void and credit as successful.7 A pay on invoice method starts from that idea and adds the one thing a cheque method lacks: a credit check.

The account carries the credit limit and the terms, 30 or 60 days, sometimes 14 for new customers. The payment method compares the open balance plus this order with the limit. If it fits, the payment is authorised and the order completes. If not, the order is held and accounts get a notification. The customer sees a polite message, not a decline.

Solidus also ships store credit as a payment method in its own right.8 That is useful for credit notes and prepayments: a refund as store credit is spent at the next checkout without anyone keying it by hand.

Open balance means the shop must know what has been invoiced and what has been paid. The reliable pattern is that the ERP or accounting system is the source of truth for balances, and the shop syncs them on a schedule and once more at checkout. Making the shop the ledger is a mistake. It is not an accounting system.

Chasing overdue invoices belongs in the accounting system too. What the shop needs is the outcome: an account on hold for overdue invoices cannot place orders on terms until it is cleared. That is a flag on the account and a check in the payment method.

For how buyers in Germany and Austria expect to pay, including pay on invoice for consumers, see my piece on DACH payments in Solidus.

What UK law gives you when an invoice is paid late

Terms are only half the story. The other half is what happens when they are broken, and in the UK the Late Payment of Commercial Debts (Interest) Act 1998 sets the defaults. If you agree a payment date between businesses, it should usually be within 60 days. You can agree longer, but it must be fair to both sides. If no date is agreed, payment is late 30 days after the customer receives the invoice or you deliver, whichever is later.9

Once a payment is late you may charge statutory interest at 8% plus the Bank of England base rate, unless the contract sets a different rate.10 You can also claim a fixed sum for recovery costs: £40 for a debt under £1,000, £70 from £1,000 to £9,999.99, and £100 from £10,000.11 Daily interest is simple interest, a rate applied pro rata (see ratios and rates):

I=D (b+0.08) t365I = D\,(b + 0.08)\,\frac{t}{365}

where II is the interest owed, DD is the debt, bb is the base rate as a fraction and tt is the number of days late.

The hotel group owes Kirkstall £12,400 and pays 45 days late. If the base rate were 4%:

I=12,400×0.12×45365=183.45I = 12{,}400 \times 0.12 \times \frac{45}{365} = 183.45

So II is £183.45 of interest, plus the £100 fixed sum because DD is above £10,000. Whether Kirkstall actually claims it from a twelve site customer is a commercial decision. The shop's job is to put the terms on every invoice so the option exists.

VAT, decided by where the goods go

Now the part that makes tax advisers nervous. The rules below are the general position for a UK VAT registered seller of goods. Have your adviser confirm them for your products before launch.

Inside the UK. Domestic sales between businesses carry VAT at the normal rate, 20% for most goods, whether or not the buyer is VAT registered.12 The buyer's VAT number does not change the rate. It goes on the account for their records and yours, and you can check it with HMRC's online service, which also lets you prove when you checked.13

From Great Britain to a business in the EU. Since Brexit this is an export, not an intra community supply. The sale is zero rated if the goods leave the UK within the time limits and you hold valid evidence of export, as set out in VAT Notice 703.14 The customer's EU VAT number is not what zero rates the sale. The export evidence is. The customer then deals with import VAT and duty in their own country, unless you sell on delivered duty paid terms, in which case you are the importer and usually need a VAT registration there. Checking the customer's EU VAT number in VIES, the European Commission's validation service, is still worth doing at account creation: it confirms you are dealing with a registered business and their customs broker will need it.15

Northern Ireland. Under the Windsor Framework, goods moving between Northern Ireland and the EU still follow EU style VAT rules, and HMRC's VAT Notice 725 explains how to charge and account for them.16 If Kirkstall ships from Leeds to a customer in Belfast, that is a domestic UK sale with UK VAT. A business that holds stock in Northern Ireland and ships to Dublin is in Notice 725 territory, with its own invoice wording and reporting. If that is you, the shop needs a separate tax zone for it and your adviser needs to sign off the rules.

Buying stock in from the EU. The other direction matters for the wholesaler's own costs. Postponed VAT accounting lets a UK VAT registered importer declare and recover import VAT on the same VAT return, instead of paying it at the border and reclaiming it later.17 That is a cash flow point for the accounts team rather than a shop feature, but it belongs on the same checklist.

The shop logic follows from this. Tax is decided per order by the delivery address, never by the country on the account. If the Dutch customer asks for a delivery to its partner's kitchen in London, the goods never leave the UK, and UK VAT applies.

Which VAT treatment an order gets, UK sellerThe shop decides VAT per order by the delivery address. A UK delivery carries UK VAT at the normal rate. A delivery that leaves the UK is an export, zero rated only with valid evidence of export, unless the stock is held in Northern Ireland and shipped to the EU: then Notice 725 rules apply, with a separate tax zone and an adviser signing off. In every case the invoice records the treatment and the reason.yesnoyesnoOrder from a trade accountDelivery address in theUK?UK VAT at the normal rate,buyer VAT number on theaccountStock held in NorthernIreland and shipped to theEU?Notice 725 rules, separatetax zone, adviser signs offExport: zero rated withevidence of exportInvoice records thetreatment and the reason

In Solidus, tax comes from tax rates attached to zones (sets of countries or regions) and tax categories, and the class that applies taxes to an order is configurable through the tax_adjuster_class setting.3 The pattern I use is a UK zone at the normal rates, an export zone at zero that also adds the export note to the invoice, and a separate zone only if the business really moves goods through Northern Ireland. Each case is a written specification with tests, so the owner can read in plain English which order gets which treatment.

Invoices an accounts department will accept

A consumer shop can get by with an order confirmation. A B2B shop cannot. HMRC lists what a full VAT invoice must show, including a unique sequential number, the time of supply, your VAT number, the customer's name and address, a description of the goods, the quantity, the price excluding VAT, the rate and the VAT payable.18 An invoice that falls short is a problem for the buyer reclaiming input tax, and a buyer who cannot reclaim will send it back.

Sequential numbering means the shop cannot reuse the order number, because orders get cancelled and numbers get skipped. Invoices are their own model with their own sequence, generated when the order ships, never changed afterwards. Corrections are credit notes with their own sequence.

Then there is e invoicing. HMRC published the measure on 28 October 2026: e invoicing requirements for VAT invoices from April 2029, with Peppol as the core interoperability framework and HMRC as the UK Peppol Authority. The detailed scope, technical rules and exemptions will follow in regulations.19 German customers are ahead of that. Since 1 January 2025 an e invoice in Germany means a structured electronic format, and German businesses have had to be able to receive one.20 A Kirkstall customer in Germany may well ask for XRechnung or ZUGFeRD files.

The practical consequence is the same everywhere. Store the invoice as structured data from day one, with every required field held explicitly, so that a PDF, a Peppol message or a German format is a rendering choice and not a rebuild. If the ERP already generates invoices, the shop should not create a second set. It hands the completed order to the ERP and shows the ERP's invoice to the customer. Two invoice sequences for one business is a mess.

Quick order, file upload and reorder

Trade buyers do not browse. Three features cover most of what they do.

A quick order form: a grid where the buyer types or pastes product codes and quantities, the shop checks each line against the catalogue and the account's price list, flags anything unknown or out of stock, and adds the lot to the cart in one go. It belongs on the first page after login.

File upload: the same thing from a CSV file, because some buyers export requirements from their own system. Accept the customer's own product codes as well as yours, with a mapping table on the account, because large accounts will not renumber for you.

Reorder: one click to put a past order's lines in the cart at today's prices, with a clear note on anything that changed in price or availability. With saved lists, this is most of what a fortnightly customer ever does in the shop.

All three are ordinary Rails features on top of the Solidus cart. None comes out of the box, and all three belong in the first phase.

Reps ordering on behalf of customers

A B2B shop does not replace the sales team. It gives them a better tool. Reps need to see their accounts, prepare quotes, place orders for a customer who phoned, and see what is open. That is an admin role scoped to assigned accounts, with an "act as" capability that records which rep placed which order.

The audit trail matters. When a rep places an order for a customer, the order records the rep, the customer contact who authorised it and how (a call, a message reference). When the invoice is disputed six weeks later, that record settles it.

Catalogue visibility, and the SEO mistake that costs the most

The most expensive mistake in B2B shops is a policy decision, not a technical one: hiding the whole catalogue behind a login.

The reasoning is understandable. Trade prices are confidential and the business does not want consumers ordering. So the whole shop disappears behind a login and becomes invisible to search engines, to prospects, and to the buyer at a new restaurant group researching suppliers at nine in the evening.

The fix is to separate visibility from price. The catalogue is public: products, specifications, images, availability, everything a prospect needs to decide you are worth a call. Prices show only to logged in accounts, or a list price shows publicly with a note that trade prices are available on application. Ordering needs an account. Every product page stays indexable, the inbound enquiries keep coming, and negotiated prices stay private.

Account specific catalogue restrictions, where a customer only sees the product families in their contract, are a separate and legitimate feature: a per account visibility rule on top of a public catalogue, not a reason to hide everything. What I wrote about B2B buying in Germany, with procurement doing its homework before the first call, applies to catering supplies as much as to software.

ERP integration and who owns what

The integration with the ERP or accounting system is often the biggest single part of a B2B project. What keeps it sane is deciding, for each kind of data, which system is the source of truth.

Products and stock: the ERP, almost always. The shop imports catalogue and stock on a schedule and on webhook where the ERP supports it, and never edits them.

Prices: the ERP, if it has customer specific pricing. The shop imports price lists. If the ERP's pricing is too crude, the shop owns prices and pushes them back, which needs more care.

Accounts: usually the ERP for the account record, credit limit and terms, with the shop owning users, roles and addresses that the ERP does not model.

Orders: created in the shop, pushed to the ERP on completion, with the ERP's order number written back. Fulfilment, invoices and payments flow back for display.

The integration is ordinary Rails background jobs: idempotent, logged, with an admin page that shows every failure and lets someone retry. I wrote about that kind of plumbing in my piece on background workers. Whether the ERP offers a modern API or a CSV file on a server overnight, the pattern is the same and only the transport differs.

Punchout, where a large customer's procurement system opens your shop inside itself and pulls the cart back as a purchase order, comes up with enterprise customers. It uses defined protocols (cXML, or OCI in German speaking markets) and is a well bounded feature to add once a customer asks. Do not build it speculatively.

What to build first

For a wholesaler like Kirkstall, this is the order.

Phase one, the foundation: account model with users, roles and addresses, public catalogue with prices behind login, price lists, pack sizes and minimums, quick order and reorder, pay on invoice with a credit check, the VAT zones, structured invoices, and a one way ERP sync for products, stock and price lists with orders pushed out. That is a shop existing customers can move onto.

Phase two, the sales team: quote builder and quote to order flow, rep views and act as, approval thresholds, saved lists, file upload with customer product codes, and the sync extended to bring invoices and balances back.

Phase three, when customers ask: per account catalogue restrictions, quantity breaks, punchout, Peppol or German e invoice output if the ERP does not already do it, more currencies, and whatever the first six months of real orders reveal.

Phase one is the part to build carefully and test exhaustively, because it handles money and tax. Every rule in it gets an executable specification the owner can read. Phase three stays vague on purpose, because real customers should drive it.

What it costs

My published rate for development is £175 an hour.21 What a B2B build costs depends on its scope: how many price lists and how they sync, whether quotes are in the first phase, how net terms and credit checks connect to the ERP, and which VAT cases the shop has to handle. A messy ERP pushes every part up. So I do not publish a fixed figure. I scope it with you and quote it at that hourly rate, and the free workshop plus the first two weeks of work is where that scoping happens.

Compare that honestly with the alternatives. Shopify now offers B2B on its Basic, Grow and Advanced plans too, with net payment terms and quantity rules on all of them. But those plans allow at most three active catalogues across B2B markets, and assigning a catalogue directly to a specific company, which is what contract pricing needs, is only on Plus.22 Plus starts at £1,800 a month on a one or three year term, £108,000 over five years before any build work.23 Shopware puts its B2B components, such as quotes and purchasing approvals, in its Evolve plan, from €2,400 a month before VAT.24

The money on Solidus goes into your own features, tested and documented, on infrastructure you control, and the bespoke code I write becomes yours on full payment. It is rarely the lowest figure in year one. It is often the lowest by year three, and it is the option where the quote builder works the way your sales team works.

A word on demos: I am building a set of Solidus demo shops, and a trade and wholesale one is planned. They are a work in progress and not open to visitors yet.

The mistakes, collected

Hiding the whole catalogue behind a login. It kills search visibility and inbound enquiries.

One price list per customer. Unmaintainable. Use tiers and account level overrides.

Contract prices as promotions. They stack with real campaigns, confuse the invoice and break the ERP sync.

Quotes as emails. Nobody can find them, prices drift, disputes cannot be settled.

VAT by the account's country instead of the delivery address. It produces wrong invoices the day a customer has a site in another country.

Invoice numbers reused from order numbers. Gaps in the sequence when orders are cancelled.

Invoices as PDF templates instead of structured data. Fine until the first customer asks for an e invoice.

The shop as the ledger. Balances and overdue invoices live in the accounting system, the shop reads them.

Building punchout, quantity breaks and elaborate approval flows before anyone asks. Speculative B2B features are usually wrong in the details, and the details are the whole point.

Card only checkout. The buyer does not have a company card. They have a purchasing process with an invoice in it.

Why Solidus fits this work

All of this could be built on any framework. Solidus fits B2B because it does not fight you. The checkout flow is designed to be changed. The price selector is a named extension point. Payment methods are classes with a defined interface. Tax application is a configurable class. Users, roles and permissions are ordinary Rails. Each feature in this article slots into a place the framework left for it, with tests, without working around a vendor's assumptions about how people shop.

That is what owning the platform means in practice: the shop matches the business instead of the business matching the shop. In B2B, where every customer has their own terms and every order is a small negotiation, that is the difference between a shop the sales team uses and one they work around.

If you would like to go through your price lists, terms and invoicing with me, I run a free workshop, and the first two weeks of work are on me.

Footnotes

  1. Solidus, Releases on GitHub, v4.8.1 published 5 November 2026, https://github.com/solidusio/solidus/releases ↩

  2. Solidus source, Spree::Variant::PricingOptions (currency and country_iso), https://github.com/solidusio/solidus/blob/main/core/app/models/spree/variant/pricing_options.rb ↩

  3. Solidus source, Spree::AppConfiguration (settings variant_price_selector_class and tax_adjuster_class), https://github.com/solidusio/solidus/blob/main/core/lib/spree/app_configuration.rb, and Spree::Variant::PriceSelector, https://github.com/solidusio/solidus/blob/main/core/app/models/spree/variant/price_selector.rb ↩ ↩2

  4. solidusio-contrib, solidus_volume_pricing, README and gemspec (requires solidus_core 4.x), https://github.com/solidusio-contrib/solidus_volume_pricing ↩ ↩2

  5. Solidus, Solidus Promotions README (recommended promotion system, slated to replace legacy promotions), https://github.com/solidusio/solidus/blob/main/promotions/README.md ↩

  6. Solidus source, Spree::Order checkout_flow (address, delivery, payment if required, confirm), https://github.com/solidusio/solidus/blob/main/core/app/models/spree/order.rb ↩

  7. Solidus source, Spree::PaymentMethod::Check (no payment source required, simulated successful capture, void and credit), https://github.com/solidusio/solidus/blob/main/core/app/models/spree/payment_method/check.rb ↩

  8. Solidus source, Spree::PaymentMethod::StoreCredit, https://github.com/solidusio/solidus/blob/main/core/app/models/spree/payment_method/store_credit.rb ↩

  9. GOV.UK, Late commercial payments: charging interest and debt recovery, https://www.gov.uk/late-commercial-payments-interest-debt-recovery ↩

  10. GOV.UK, Late commercial payments: interest on late commercial payments, https://www.gov.uk/late-commercial-payments-interest-debt-recovery/charging-interest-commercial-debt ↩

  11. GOV.UK, Late commercial payments: claim debt recovery costs on late payments, https://www.gov.uk/late-commercial-payments-interest-debt-recovery/claim-debt-recovery-costs ↩

  12. GOV.UK, VAT rates, https://www.gov.uk/vat-rates ↩

  13. GOV.UK, Check a UK VAT number, https://www.gov.uk/check-uk-vat-number ↩

  14. HMRC, VAT on goods exported from the UK (VAT Notice 703), updated 4 March 2026, https://www.gov.uk/guidance/vat-on-goods-exported-from-the-uk-notice-703 ↩

  15. European Commission, VIES VAT number validation, https://ec.europa.eu/taxation_customs/vies/ ↩

  16. HMRC, VAT on movements of goods between Northern Ireland and the EU (VAT Notice 725), updated 1 October 2026, https://www.gov.uk/guidance/vat-on-movements-of-goods-between-northern-ireland-and-the-eu ↩

  17. HMRC, Check when you can account for import VAT on your VAT Return (postponed VAT accounting), https://www.gov.uk/guidance/check-when-you-can-account-for-import-vat-on-your-vat-return ↩

  18. HMRC, VAT guide (VAT Notice 700), section 16 on VAT invoices, https://www.gov.uk/guidance/vat-guide-notice-700 ↩

  19. HMRC, VAT: electronic invoicing, tax information and impact note, 28 October 2026, https://www.gov.uk/government/publications/vat-electronic-invoicing ↩

  20. Bundesministerium der Finanzen, FAQ on the introduction of electronic invoices (E Rechnung), https://www.bundesfinanzministerium.de/Content/DE/FAQ/e-rechnung.html ↩

  21. Keferboeck, Pricing, hourly rates for ad hoc work, https://keferboeck.com/en-gb/pricing/transparency#hourly-rates ↩

  22. Shopify Help Center, Shopify B2B features by plan, accessed 11 November 2026, https://help.shopify.com/en/manual/b2b/getting-started/plan-features ↩

  23. Shopify, Pricing (United Kingdom), accessed 10 November 2026, https://www.shopify.com/uk/pricing ↩

  24. Shopware, Pricing (Evolve plan and B2B components), accessed 11 November 2026, https://www.shopware.com/en/pricing/ ↩

If you sell to trade customers and your shop still treats them like consumers with a coupon, bring your price lists, terms and invoices to a free workshop. The first two weeks of work are on me, and you leave knowing what a B2B build on Solidus would look like.

1%of every invoice goes to a UK charity you pick.

A donation, never sponsorship. You choose the cause at onboarding.

The story behind the pledge →

Stay ahead of your competition.

The latest innovative products and services, straight to your inbox before your competitors hear about them.

Get up to 5% off your first six months: 1% per topic you pick, the full 5% when you take everything. Limited offer · ends 31 December 2026.

New clients only. Terms apply.

* Up to 5% off your first six monthly invoices, new clients only. Full terms.

Questions about pricing, contracts or how we work together?

Read the FAQ