Most payment platforms take months to build their SDK ecosystem. Stripe's first SDK (Ruby) was maintained by a team. PayPal's SDKs are maintained by dozens of engineers. We built 8 SDKs in 7 programming languages plus 3 platform plugins, all generated by Claude, all following an identical resource pattern, with zero runtime dependencies in most cases.
The SDK timeline spans the entire 0fee.dev build history -- from Session 002 to Session 080 -- because SDKs are never "done." They evolve with the API.
The SDK Timeline
| Session | Date | SDKs | Version | Coverage |
|---|---|---|---|---|
| 002 | Dec 11, 2025 | TypeScript, Python | v1.0 | ~21% |
| 003 | Dec 11, 2025 | Go, Ruby, PHP, Java, C# | v1.0 | ~21% |
| 065 | Dec 25, 2025 | TypeScript, Python (rewrite) | v2.0 | ~45% |
| 079 | Feb 14, 2026 | PHP, Go | v3.0 | ~65% |
| 080 | Feb 15, 2026 | Rust, Java, Flutter, React Native | v3.0 | ~79% |
API coverage went from 21% (basic CRUD for payments) to 79% (payments, transactions, apps, providers, webhooks, invoices, feature requests, analytics). The remaining 21% covers admin-only endpoints that SDKs do not need to expose.
The Identical Resource Pattern
Every SDK follows the same architectural pattern regardless of language. This makes the SDKs predictable: if you know how to use one, you know how to use all of them.
Client
|
+-- payments (create, get, list, cancel)
+-- transactions (get, list, export)
+-- apps (create, get, list, update, delete)
+-- providers (list, get)
+-- webhooks (create, get, list, delete, verify)
+-- invoices (get, list, download)
+-- paymentLinks (create, get, list, delete)
+-- paymentMethods (list)Each resource is a namespace on the client object. Each namespace exposes the same CRUD methods (where applicable). Here is how the same operation looks across all 8 SDKs:
Create a Payment
TypeScript:
``typescript
const zerofee = new ZeroFee({ apiKey: 'sk_live_...' });
const payment = await zerofee.payments.create({
amount: 10.00,
currency: 'USD',
reference: 'order-123',
});
``
Python:
``python
client = ZeroFee(api_key="sk_live_...")
payment = client.payments.create(
amount=10.00,
currency="USD",
reference="order-123",
)
``
Go:
``go
client := zerofee.New("sk_live_...")
payment, err := client.Payments.Create(&zerofee.PaymentParams{
Amount: 10.00,
Currency: "USD",
Reference: "order-123",
})
``
Rust:
``rust
let client = ZeroFee::new("sk_live_...");
let payment = client.payments().create(PaymentParams {
amount: 10.00,
currency: "USD".to_string(),
reference: "order-123".to_string(),
..Default::default()
}).await?;
``
PHP:
``php
$client = new ZeroFee('sk_live_...');
$payment = $client->payments->create([
'amount' => 10.00,
'currency' => 'USD',
'reference' => 'order-123',
]);
``
Java:
``java
ZeroFee client = new ZeroFee("sk_live_...");
Payment payment = client.payments().create(
PaymentParams.builder()
.amount(10.00)
.currency("USD")
.reference("order-123")
.build()
);
``
Flutter (Dart):
``dart
final client = ZeroFee(apiKey: 'sk_live_...');
final payment = await client.payments.create(
amount: 10.00,
currency: 'USD',
reference: 'order-123',
);
``
React Native:
``typescript
// Uses the TypeScript SDK
import { ZeroFee } from '@0fee/react-native';
BLANK
const zerofee = new ZeroFee({ apiKey: 'sk_live_...' });
const payment = await zerofee.payments.create({
amount: 10.00,
currency: 'USD',
reference: 'order-123',
});
``
The Zero Runtime Dependencies Philosophy
Most SDKs are dependency-free or near-dependency-free:
| SDK | Language | Runtime Dependencies |
|---|---|---|
| TypeScript | Node.js | 0 (uses native fetch) |
| Python | Python 3.8+ | httpx only |
| Go | Go 1.21+ | 0 (uses net/http) |
| Rust | Rust | reqwest, serde |
| PHP | PHP 8.1+ | 0 (uses curl extension) |
| Java | Java 11+ | 0 (uses java.net.http.HttpClient) |
| Flutter | Dart | http package |
| React Native | JS/TS | 0 (wraps TypeScript SDK) |
Zero dependencies means:
- No version conflicts with the developer's existing packages
- No supply chain attack surface from transitive dependencies
- Faster installation (npm install does not download a tree of packages)
- Smaller bundle size for frontend SDKs
The TypeScript SDK in particular benefits from zero dependencies. Many developers are frustrated by SDKs that pull in axios, node-fetch, or other HTTP libraries when the platform already provides fetch natively.
SDK v1 to v2: The Rewrite (Session 065)
The v1 SDKs from Sessions 002-003 were generated quickly and had limitations:
| Issue | v1 | v2 |
|---|---|---|
| HTTP client | axios / requests | Native fetch / httpx |
| Type safety | Partial types | Full request/response types |
| Error handling | Generic exceptions | Typed error classes |
| Retries | None | Exponential backoff |
| Webhook verification | Missing | Built-in |
| Pagination | Manual | Iterator helpers |
The v2 rewrite focused on TypeScript and Python (the two most popular SDKs by download count). The pattern established in v2 became the template for all v3 SDKs.
Typed Error Handling
typescript// v1: Generic error
try {
await zerofee.payments.create({...});
} catch (e) {
console.error(e.message); // "Request failed"
}
// v2: Typed errors
try {
await zerofee.payments.create({...});
} catch (e) {
if (e instanceof ZeroFeeValidationError) {
console.error('Validation:', e.errors);
} else if (e instanceof ZeroFeeAuthError) {
console.error('Invalid API key');
} else if (e instanceof ZeroFeeRateLimitError) {
console.error(`Retry after ${e.retryAfter} seconds`);
}
}Automatic Retry
typescript// Built into the HTTP client
class ZeroFeeHttpClient {
private maxRetries = 3;
private retryDelay = 1000; // ms
async request(method: string, path: string, data?: any): Promise<any> {
let lastError: Error | null = null;
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
try {
const response = await fetch(`${this.baseUrl}${path}`, {
method,
headers: this.headers,
body: data ? JSON.stringify(data) : undefined,
});
if (response.status === 429) {
// Rate limited: respect Retry-After header
const retryAfter = parseInt(response.headers.get('Retry-After') || '1');
await this.sleep(retryAfter * 1000);
continue;
}
if (response.status >= 500 && attempt < this.maxRetries) {
// Server error: retry with exponential backoff
await this.sleep(this.retryDelay * Math.pow(2, attempt));
continue;
}
return await this.handleResponse(response);
} catch (error) {
lastError = error as Error;
if (attempt < this.maxRetries) {
await this.sleep(this.retryDelay * Math.pow(2, attempt));
}
}
}
throw lastError;
}
}SDK v3: The Expansion (Sessions 079-080)
v3 added four new SDKs and upgraded PHP and Go:
Rust SDK: Async by default using tokio and reqwest. Full type system with Rust enums for payment statuses and methods.
Java SDK: Uses java.net.http.HttpClient (Java 11+). Builder pattern for all request objects. CompletableFuture for async operations.
Flutter SDK: Dart-native with http package. Designed for mobile payment flows -- includes a pre-built checkout widget component.
React Native SDK: Wraps the TypeScript SDK with React Native-specific components. Includes a PaymentSheet component that renders the checkout flow in a modal.
The 3 Platform Plugins
Beyond SDKs, Session 084 produced three platform plugins:
WHMCS Plugin
php// modules/gateways/zerofee.php
function zerofee_capture($params) {
$client = new ZeroFee($params['apiKey']);
$payment = $client->payments->create([
'amount' => $params['amount'],
'currency' => $params['currency'],
'reference' => 'whmcs-' . $params['invoiceid'],
'customer_email' => $params['clientdetails']['email'],
]);
if ($payment->status === 'completed') {
return ['status' => 'success', 'transid' => $payment->id];
}
return ['status' => 'declined', 'rawdata' => $payment->toArray()];
}WordPress Plugin
A WordPress payment gateway plugin that adds 0fee.dev as a payment option on any WordPress site using WooCommerce or a custom form.
WooCommerce Plugin
Extends the WordPress plugin specifically for WooCommerce:
phpclass WC_Gateway_ZeroFee extends WC_Payment_Gateway {
public function process_payment($order_id) {
$order = wc_get_order($order_id);
$client = new ZeroFee($this->api_key);
$payment = $client->payments->create([
'amount' => $order->get_total(),
'currency' => $order->get_currency(),
'reference' => 'woo-' . $order_id,
]);
return [
'result' => 'success',
'redirect' => $payment->checkout_url,
];
}
}API Coverage Evolution
Session 002: ████░░░░░░░░░░░░░░░░ 21% (payments CRUD)
Session 003: ████░░░░░░░░░░░░░░░░ 21% (same coverage, more languages)
Session 065: █████████░░░░░░░░░░░ 45% (+transactions, apps, webhooks)
Session 079: █████████████░░░░░░░ 65% (+invoices, payment links, providers)
Session 080: ████████████████░░░░ 79% (+feature requests, analytics, methods)The remaining 21% covers admin endpoints (user management, platform stats, audit logs) that are not exposed through SDKs.
What We Learned
Generate all SDKs from the same template. The identical resource pattern across all 8 SDKs was only possible because we used the API specification as the source of truth. Each SDK is a language-specific implementation of the same abstract interface.
Zero dependencies is a competitive advantage. Developers notice and appreciate SDKs that do not pull in transitive dependencies. It eliminates version conflicts and reduces security audit surface.
Platform plugins reach developers where they are. Not every developer builds from scratch. WooCommerce alone powers 29% of e-commerce sites. The WHMCS plugin reaches hosting companies. Platform plugins are high-leverage for adoption.
SDK maintenance is ongoing. The timeline from v1 to v3 over 78 sessions shows that SDKs are never "done." Every API change, every new feature, every bug fix propagates to 8 SDK packages and 3 plugins. This is the hidden cost of a broad SDK ecosystem.
AI-generated SDKs are consistent. Claude generates each SDK with the same patterns, same error handling, same retry logic. There is no "this SDK was written by a Go expert and that one was written by a Java intern" quality variation. Consistency across languages is a direct benefit of AI generation.
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.