International e-commerce platform with 30 locales, product configurators, AI chatbot, and fully automated order flow: Stripe โ Zoho CRM โ Airtable โ Mailgun โ
i18n B2B e-commerce platform for waterless urinal products across 32 European countries with automated VAT handling, PDF invoicing, and CRM integration.
Key Results

Pi-pi.ee sells waterless urinal systems to businesses across Europe โ maintenance companies, venue operators, facility managers. The product nearly sells itself: lower operating costs, no water connection, less maintenance. The sales process was the bottleneck.
B2B buyers in Europe have specific expectations that consumer e-commerce platforms treat as edge cases. A German buyer expects their VAT number to be validated against the VIES registry, the MwSt to be removed automatically from the invoice, and the correct reverse charge notation to appear on the document. A Portuguese buyer needs Multibanco as a payment option. A Finnish buyer expects the invoice in Finnish. Shopify Plus could handle portions of this โ at โฌ60,000+/year, plus bespoke development for everything it could not do natively. The business needed a platform built around B2B compliance from the ground up, not a consumer checkout with VAT bolted on.
I built a headless B2B e-commerce platform where EU VAT compliance is a first-class architectural concern, not an afterthought. VAT rates for all 32 countries are stored as static JSON, updated by a script before each build. Calculation happens at checkout with no external API call in the critical path โ no latency, no third-party failures, no dependency on a service that can go down during checkout.
VIES integration validates EU VAT numbers in real time and auto-fills the company's registered address directly from the EU registry. Six payment methods โ cards, PayPal, Revolut, SEPA Direct Debit, bank transfer, and Multibanco โ cover every major European B2B payment preference without requiring multiple Stripe accounts or separate integrations. Server-rendered PDF invoices with correct reverse charge notation are generated and emailed automatically on payment confirmation, with Cyrillic character support for Eastern European markets. Orders and customer records sync to Notion automatically, keeping the operations team in a tool they already know.
Professional buyers can now self-serve completely: validate their VAT number, see accurate country-specific pricing, pay via their preferred method, and receive a compliant invoice โ without a sales call.
| Metric | Value |
|---|---|
| Languages | 28 fully localized |
| Markets | 32 European countries |
| Payment methods | 6 (Cards, PayPal, Revolut, SEPA, Bank Transfer, Multibanco) |
| VAT calculation | 0 runtime dependencies (static JSON) |
| PDF invoices | Server-rendered with Cyrillic support |
| SEO | 100% server-rendered (Next.js App Router) |
Selling B2B across 32 European markets in 28 languages means organic discovery has to work in every one of them โ not just English. Technical SEO was part of the build from day one, not a phase that gets postponed until "after launch":
hreflang declarations for all 28 languages ร 32 markets โ every locale points to the correct regional alternates so a Polish buyer searching in Polish lands on pl-PL, not the English fallbackProduct schema with correct currency, B2B pricing, and availability โ the structured data survives localization, which is the most common place schema silently breaks on multilingual sitesOrganization, BreadcrumbList, and FAQ schema for the long-tail B2B queries that drive most of this marketFor the technically curious, here is how the core pieces are built.
Price calculation without API requests โ data loaded statically, types guarantee correctness:
// src/lib/pricing/utils.ts
export interface PriceResult {
basePrice: number; // Net price in EUR
vatRate: number; // 0.22 = 22%
vatAmount: number; // VAT amount in EUR
totalPrice: number; // Net + VAT
isEU: boolean; // EU country flag
formattedTotal: string; // "โฌ365.78"
}
export function calculatePrice(countryCode: string): PriceResult {
const vatRate = getVatRate(countryCode); // From static JSON
const basePrice = 299; // EUR
const vatAmount = Math.round(basePrice * vatRate * 100) / 100;
const totalPrice = Math.round((basePrice + vatAmount) * 100) / 100;
return {
basePrice,
vatRate,
vatAmount,
totalPrice,
isEU: isEuCountry(countryCode),
formattedTotal: new Intl.NumberFormat("de-DE", {
style: "currency",
currency: "EUR",
}).format(totalPrice),
};
}Unified handler for all payment types โ instant (cards) and async (SEPA, bank transfers):
// src/app/api/webhooks/stripe/route.ts
const ASYNC_PAYMENT_METHODS = ["sepa_debit", "customer_balance", "multibanco"];
export async function POST(request: NextRequest) {
const event = stripe.webhooks.constructEvent(body, signature, webhookSecret);
switch (event.type) {
case "payment_intent.succeeded": {
const orderData = parseOrderData(paymentIntent);
await sendOrderNotification(orderData); // Warehouse
await sendInvoiceEmail(orderData); // Customer
await upsertOrder({ ...orderData, status: "Paid" }); // CRM
break;
}
case "payment_intent.requires_action": {
// Bank transfer โ send instructions
if (nextActionType === "display_bank_transfer_instructions") {
const bankTransfer = getBankTransferDetails(paymentIntent);
await sendOrderConfirmationEmail(orderData, bankTransfer);
}
break;
}
}
}Invoices generated on server with Cyrillic support, reverse charge for B2B, and payment-specific instructions:
// src/lib/pdf/invoice-pdf.tsx
Font.register({
family: "Roboto",
fonts: [
{ src: "https://fonts.gstatic.com/.../Roboto.ttf", fontWeight: 400 },
{ src: "https://fonts.gstatic.com/.../Roboto-Bold.ttf", fontWeight: 700 },
],
});
export function InvoicePDF({ order, status, bankTransfer }: InvoicePDFProps) {
return (
<Document>
<Page size="A4" style={styles.page}>
{/* Header with logo and company info */}
<View style={styles.header}>...</View>
{/* Status badge: PAID / PENDING / PROCESSING */}
<View style={[styles.statusBadge, statusStyle]}>
<Text>{statusText}</Text>
</View>
{/* Line items table */}
{order.items.map((item) => (
<View style={styles.tableRow}>
<Text>{productNames[item.productId]}</Text>
<Text>{item.quantity}</Text>
<Text>{formatCurrency(item.price * item.quantity)}</Text>
</View>
))}
{/* Bank transfer instructions (if applicable) */}
{bankTransfer && (
<View style={styles.bankTransferBox}>
<Text>IBAN: {bankTransfer.iban}</Text>
<Text>Reference: {bankTransfer.reference}</Text>
</View>
)}
{/* Reverse charge note for B2B */}
{order.isReverseCharge && (
<Text>VAT reverse charge per Article 196 Directive 2006/112/EC</Text>
)}
</Page>
</Document>
);
}Internationalization via next-intl with SEO and server-side rendering support:
// src/i18n/config.ts
export const locales = [
"bg",
"cs",
"da",
"de",
"el",
"en",
"es",
"et",
"fi",
"fr",
"hr",
"hu",
"it",
"lt",
"lv",
"nl",
"no",
"pl",
"pt",
"ro",
"ru",
"sk",
"sl",
"sv",
"tr",
"uk",
"vi",
"zh",
] as const;
export const countries = [
"AT",
"AX",
"BE",
"BG",
"CH",
"CY",
"CZ",
"DE",
"DK",
"EE",
"ES",
"FI",
"FR",
"GB",
"GR",
"HR",
"HU",
"IE",
"IT",
"LT",
"LU",
"LV",
"MT",
"NL",
"NO",
"PL",
"PT",
"RO",
"SE",
"SI",
"SK",
] as const;
// Each country has VAT pattern, example, phone format
export const countryInfo: Record<Country, CountryConfig> = {
DE: {
vatPrefix: "DE",
vatPattern: /^DE\d{9}$/,
vatExample: "DE123456789",
phoneCode: "+49",
},
// ... 31 more countries
};Iurii built our entire B2B platform from scratch in a remarkably short time โ a fully multilingual webshop covering 32 European markets in 28 languages, with automated VAT calculation, VIES validation, Stripe payments across 6 methods including SEPA and bank transfers, server-generated PDF invoices, and Notion as our CRM. Everything was integrated and working end-to-end, not just a prototype. As someone responsible for both sales and operations, I especially valued that he understood the business side โ compliance requirements, B2B buyer expectations, different payment preferences across markets. He asked the right questions upfront, kept things transparent throughout, and delivered without dragging it out. Highly recommend.
Mark Tamm ๐ช๐ช
Account Manager, pi-pi.ee
AvailableNeed something similar?
I build custom solutions โ from APIs to full products. Let's talk about your project.
International e-commerce platform with 30 locales, product configurators, AI chatbot, and fully automated order flow: Stripe โ Zoho CRM โ Airtable โ Mailgun โ
Internal sales portal that turns a wholesale deal into a full set of trade paperwork โ pro forma, contract, commercial invoice, packing list, CMR and more โ
Gated B2B pricing in Next.js: per-account price lists, server-side access control so prices never leak to crawlers, and a deal-record data model where every
Production transactional emails with React Email and Resend: PDF invoice generation via react-pdf, Vercel Blob temporary storage, and BullMQ Stripe webhook