Stripe's website is the gold standard for developer-focused marketing. Clean typography, interactive code examples, smooth animations, and information density that respects the reader's intelligence. When we built 0fee.dev's marketing website, we studied Stripe's approach and adapted it for a payment orchestrator targeting Africa.
This article covers the marketing website's major sections -- the hero with live stats, interactive code examples in five languages, the features grid, the interactive country map, the pricing calculator, and the supporting pages. Everything is built in SolidJS with TailwindCSS, using Intersection Observer for scroll-triggered animations and glassmorphism for depth.
The Home Page Structure
The marketing home page (Home.tsx) assembles eight sections in order:
tsxexport default function Home() {
return (
<div>
<Hero />
<Features />
<Providers />
<CodeExamples />
<Countries />
<Pricing />
<Testimonials />
<CTA />
</div>
);
}Each section is a self-contained component with its own data, animations, and responsive layout.
Hero Section with Stats
The hero combines a headline, subtitle, and real-time statistics:
tsxfunction Hero() {
const stats = [
{ value: "53+", label: "Payment Providers" },
{ value: "200+", label: "Countries Covered" },
{ value: "40+", label: "Currencies" },
{ value: "99.9%", label: "Uptime" },
];
return (
<section class="hero-gradient min-h-screen flex items-center">
<div class="container mx-auto px-6 text-center">
<div class="inline-block px-4 py-1 bg-emerald-500/10 rounded-full
text-emerald-400 text-sm mb-6">
Payment Orchestration for Developers
</div>
<h1 class="text-5xl md:text-7xl font-bold text-white mb-6">
One API.
<span class="gradient-text"> Every Payment.</span>
<br />Everywhere.
</h1>
<p class="text-xl text-gray-400 max-w-2xl mx-auto mb-10">
Accept cards, mobile money, and wallets across 200+ countries
with a single integration. Africa-first, globally ready.
</p>
<div class="flex gap-4 justify-center mb-16">
<a href="/register" class="btn-primary">Start Building</a>
<a href="/docs" class="btn-secondary">Read the Docs</a>
</div>
<div class="grid grid-cols-2 md:grid-cols-4 gap-8">
<For each={stats}>
{(stat) => (
<div class="text-center">
<div class="text-3xl font-bold text-white">{stat.value}</div>
<div class="text-gray-400 text-sm">{stat.label}</div>
</div>
)}
</For>
</div>
</div>
</section>
);
}The hero uses a dark gradient background (hero-gradient) with decorative gradient orbs that float with a CSS animation. The stats row provides social proof immediately.
Interactive Code Examples
The code examples section is the most Stripe-inspired component. It shows integration code in five programming languages with syntax highlighting, line numbers, and a copy button:
tsxfunction CodeExamples() {
const [activeTab, setActiveTab] = createSignal("typescript");
const examples = {
typescript: {
label: "TypeScript",
install: "npm install zerofee",
code: `import { ZeroFee } from 'zerofee';
const zf = new ZeroFee({ apiKey: 'zf_live_...' });
const payment = await zf.payments.create({
amount: 5000,
currency: 'XOF',
country: 'CI',
method: 'PAYIN_ORANGE_CI',
customer: { phone: '+2250700000000' },
returnUrl: 'https://yourapp.com/thanks'
});
// Redirect customer to checkout
window.location.href = payment.checkoutUrl;`,
},
python: {
label: "Python",
install: "pip install zerofee",
code: `from zerofee import ZeroFee
zf = ZeroFee(api_key="zf_live_...")
payment = zf.payments.create(
amount=5000,
currency="XOF",
country="CI",
method="PAYIN_ORANGE_CI",
customer={"phone": "+2250700000000"},
return_url="https://yourapp.com/thanks"
)
# Redirect customer to checkout
print(payment.checkout_url)`,
},
curl: {
label: "cURL",
install: "",
code: `curl -X POST https://api.0fee.dev/v1/payments \\
-H "Authorization: Bearer zf_live_..." \\
-H "Content-Type: application/json" \\
-d '{
"amount": 5000,
"currency": "XOF",
"country": "CI",
"payment_method": "PAYIN_ORANGE_CI",
"customer": {"phone": "+2250700000000"},
"return_url": "https://yourapp.com/thanks"
}'`,
},
go: {
label: "Go",
install: "go get github.com/zerosuite/zerofee-go",
code: `package main
import "github.com/zerosuite/zerofee-go"
func main() {
zf := zerofee.New("zf_live_...")
payment, _ := zf.Payments.Create(&zerofee.PaymentParams{
Amount: 5000,
Currency: "XOF",
Country: "CI",
Method: "PAYIN_ORANGE_CI",
Customer: &zerofee.Customer{
Phone: "+2250700000000",
},
ReturnURL: "https://yourapp.com/thanks",
})
fmt.Println(payment.CheckoutURL)
}`,
},
php: {
label: "PHP",
install: "composer require zerosuite/zerofee-php",
code: `<?php
use ZeroFee\\ZeroFee;
$zf = new ZeroFee('zf_live_...');
$payment = $zf->payments->create([
'amount' => 5000,
'currency' => 'XOF',
'country' => 'CI',
'method' => 'PAYIN_ORANGE_CI',
'customer' => ['phone' => '+2250700000000'],
'return_url' => 'https://yourapp.com/thanks',
]);
header('Location: ' . $payment->checkout_url);`,
},
};
return (
<section class="py-24 bg-gray-950">
<div class="container mx-auto px-6">
<h2 class="text-3xl font-bold text-white text-center mb-4">
Five Lines of Code
</h2>
<p class="text-gray-400 text-center mb-12 max-w-xl mx-auto">
Accept payments worldwide with a single API call.
Choose your language.
</p>
{/* Language tabs */}
<div class="flex gap-2 justify-center mb-8">
<For each={Object.entries(examples)}>
{([key, lang]) => (
<button
class={`px-4 py-2 rounded-lg text-sm ${
activeTab() === key
? "bg-emerald-500 text-white"
: "text-gray-400 hover:text-white"
}`}
onClick={() => setActiveTab(key)}
>
{lang.label}
</button>
)}
</For>
</div>
{/* Code block with syntax highlighting */}
<div class="max-w-3xl mx-auto">
<SyntaxHighlighter
code={examples[activeTab()].code}
language={activeTab()}
/>
</div>
</div>
</section>
);
}The tab switching is instant -- all five code blocks are pre-rendered and toggled with CSS. No loading, no API calls.
Features Grid
The features section presents eight capabilities in a responsive grid:
tsxconst features = [
{
title: "Smart Routing",
description: "Automatically route payments to the best provider based on country, method, and availability.",
icon: RouteIcon,
},
{
title: "Mobile Money First",
description: "Orange Money, MTN, Wave, M-Pesa, and 40+ operators across Africa.",
icon: PhoneIcon,
},
{
title: "One Integration",
description: "Single API, single SDK, single webhook format. Cover 200+ countries.",
icon: CodeIcon,
},
{
title: "Real-Time Dashboard",
description: "Monitor transactions, manage providers, and track revenue in one place.",
icon: ChartIcon,
},
// ... 4 more features
];Each feature card uses Intersection Observer for scroll-triggered fade-in animation:
tsxfunction FeatureCard(props) {
let ref;
onMount(() => {
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
ref.classList.add("animate-fade-in");
observer.disconnect();
}
},
{ threshold: 0.1 }
);
observer.observe(ref);
});
return (
<div ref={ref} class="opacity-0 p-6 rounded-xl bg-gray-900 border border-gray-800">
<props.icon class="w-8 h-8 text-emerald-400 mb-4" />
<h3 class="text-lg font-semibold text-white mb-2">{props.title}</h3>
<p class="text-gray-400 text-sm">{props.description}</p>
</div>
);
}Interactive Country Map
The Countries component displays 30+ countries with region filtering:
tsxfunction Countries() {
const [activeRegion, setActiveRegion] = createSignal("all");
const regions = [
{ id: "all", label: "All" },
{ id: "west", label: "West Africa" },
{ id: "east", label: "East Africa" },
{ id: "central", label: "Central" },
{ id: "south", label: "Southern" },
{ id: "global", label: "Global" },
];
const countries = [
{ code: "CI", name: "Ivory Coast", region: "west",
methods: ["Orange", "MTN", "Wave", "Moov"] },
{ code: "KE", name: "Kenya", region: "east",
methods: ["M-Pesa", "Airtel"] },
{ code: "NG", name: "Nigeria", region: "west",
methods: ["MTN", "Airtel", "Cards"] },
// ... 27+ more countries
];
const filtered = () =>
activeRegion() === "all"
? countries
: countries.filter(c => c.region === activeRegion());
return (
<section class="py-24">
<div class="container mx-auto px-6">
<h2 class="text-3xl font-bold text-center mb-12">
Coverage Across 200+ Countries
</h2>
{/* Region tabs */}
<div class="flex gap-2 justify-center mb-8">
<For each={regions}>
{(region) => (
<button
class={`px-4 py-2 rounded-full text-sm ${
activeRegion() === region.id
? "bg-emerald-500 text-white"
: "bg-gray-800 text-gray-400"
}`}
onClick={() => setActiveRegion(region.id)}
>
{region.label}
</button>
)}
</For>
</div>
{/* Country grid */}
<div class="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-6 gap-4">
<For each={filtered()}>
{(country) => (
<div class="p-4 rounded-xl bg-gray-900 border border-gray-800
hover:border-emerald-500 transition-colors group">
<div class="text-2xl mb-2">{country.flag}</div>
<div class="text-white font-medium">{country.name}</div>
<div class="text-xs text-gray-500 mt-1">
{country.methods.join(", ")}
</div>
</div>
)}
</For>
</div>
</div>
</section>
);
}Hovering over a country card reveals the available payment methods -- Orange Money, MTN, Wave, etc.
Pricing with Calculator
The pricing section features an interactive fee calculator:
tsxfunction PricingCalculator() {
const [volume, setVolume] = createSignal(1000);
const [avgAmount, setAvgAmount] = createSignal(50);
const monthlyRevenue = () => volume() * avgAmount();
const zerofeeTotal = () => monthlyRevenue() * 0.0099; // 0.99%
return (
<div class="bg-gray-900 rounded-xl p-8">
<h3 class="text-xl font-bold text-white mb-6">Fee Calculator</h3>
<div class="space-y-6">
<div>
<label class="text-gray-400 text-sm">
Monthly Transactions: {volume().toLocaleString()}
</label>
<input
type="range"
min="100" max="100000" step="100"
value={volume()}
onInput={(e) => setVolume(parseInt(e.target.value))}
class="w-full"
/>
</div>
<div>
<label class="text-gray-400 text-sm">
Average Amount: ${avgAmount()}
</label>
<input
type="range"
min="1" max="500" step="1"
value={avgAmount()}
onInput={(e) => setAvgAmount(parseInt(e.target.value))}
class="w-full"
/>
</div>
<div class="border-t border-gray-800 pt-4">
<div class="flex justify-between text-gray-400">
<span>Monthly Volume</span>
<span>${monthlyRevenue().toLocaleString()}</span>
</div>
<div class="flex justify-between text-white text-lg font-bold mt-2">
<span>0fee Cost (0.99%)</span>
<span>${zerofeeTotal().toLocaleString()}</span>
</div>
</div>
</div>
</div>
);
}The calculator uses SolidJS signals for instant reactivity -- moving the slider updates the fee estimate without any re-rendering of the surrounding DOM.
Glassmorphism Effects
Throughout the marketing site, we use glassmorphism for visual depth:
css.glass {
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border: 1px solid rgba(255, 255, 255, 0.1);
}
.glass-hover:hover {
background: rgba(255, 255, 255, 0.08);
border-color: rgba(255, 255, 255, 0.15);
}These effects are used on cards, modals, and decorative elements. They create a sense of layering without solid backgrounds.
Additional Pages
Beyond the home page, the marketing site includes:
| Page | Route | Content |
|---|---|---|
| Products | /products | Product overview (Payments, Checkout, Routing) |
| Pricing | /pricing | Detailed pricing with FAQ accordion |
| About | /about | Team, mission, ZeroSuite ecosystem |
| Contact | /contact | Contact form with office info |
| Docs | /docs | Getting started guide with SDK examples |
| Status | /status | Provider health status indicators |
| How It Works | /how-it-works | Step-by-step payment flow explanation |
| Coverage | /coverage | Detailed country and method coverage |
| Providers | /providers | All 53+ payment providers |
Intersection Observer Animations
Every section uses Intersection Observer for scroll-triggered entrance animations:
typescriptfunction useScrollAnimation() {
return (el: HTMLElement) => {
el.classList.add("opacity-0", "translate-y-4");
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
el.classList.remove("opacity-0", "translate-y-4");
el.classList.add("opacity-100", "translate-y-0", "transition-all", "duration-700");
observer.disconnect();
}
},
{ threshold: 0.1 }
);
observer.observe(el);
};
}Elements start invisible and translated 16px down. When they scroll into view, they fade in and slide up. The observer disconnects after triggering to avoid unnecessary processing.
What We Learned
Building the marketing website taught us three things:
- Interactive elements convert better than static text. The code examples with tab switching, the pricing calculator with sliders, and the country map with region filters all invite interaction. Each interaction reinforces the product's capabilities.
- Dark themes work for developer-focused products. The dark gradient backgrounds with emerald accents create a premium feel while reducing eye strain for developers who spend hours reading documentation.
- Performance matters for first impressions. The marketing site loads in under 2 seconds. Every section is visible without waiting for data fetches (all content is static). Animations are CSS-based, not JavaScript-driven, so they run at 60fps even on mobile devices.
The marketing website was built in Session 003 with a complete redesign in Session 014. It draws direct inspiration from Stripe's approach -- information-dense, developer-focused, and visually polished -- while adapting the content for a pan-African payment orchestrator.
This article is part of the "How We Built 0fee.dev" series. 0fee.dev is a payment orchestrator covering 53+ providers across 200+ countries, built by Juste A. GNIMAVO and Claude from Abidjan with zero human engineers. Follow the series for the complete build story.