I recently open-sourced a Laravel SDK for Creem.io and wanted to write up the story behind it, because the path to building it was a bit roundabout.
Backstory
My existing project uses Omnipay, the PHP League's payment abstraction library (not a payment provider itself), to handle checkout through multiple gateways via a single interface. I originally planned to stick with a provider that already had an Omnipay driver. But mid-integration I switched to Creem. Since the project was already wired through Omnipay, I wrote a driver for it: romansh/omnipay-creem.
Omnipay is a solid choice when you need to swap gateways with one line of code. The trade-off is that it's a lowest-common-denominator abstraction: you get purchase() and completePurchase(), and everything else (webhook routing, event dispatching, config management, retry logic) you have to build yourself.
At some point I discovered Creem had a developer bounty for an official Laravel SDK. Since I was already working with their API and had a feel for what was missing, I decided to build it properly: a Laravel-native package that handles all that boilerplate out of the box. If a package like this had existed when I started, I probably would have used it instead of writing the Omnipay driver.
Disclosure: this article is also part of that bounty. That said, the packages fill a real gap and I would have written this up regardless.
The problem with typical payment integrations
Most payment integrations are built around one API key per app. That works until you need:
- Multi-tenancy: each tenant with their own billing account
- Multiple storefronts: different products or brands on separate Creem accounts
-
Staging vs production: without touching
.envper environment - Departmental billing: isolated billing within the same app
What I built
romansh/laravel-creem is a full-featured SDK with Laravel-native patterns.
What's inside:
- Complete API coverage: Products, Checkouts, Customers, Subscriptions, Transactions, Licenses, Discount Codes
-
Multi-profile config: switch API keys per request with
Creem::profile('store_b')or override inline withCreem::withConfig([...]) -
Webhooks done right: auto-registered routes, HMAC signature verification, typed Laravel events including
GrantAccess/RevokeAccess -
Artisan tooling:
php artisan creem:test-webhook checkout.completedfor local testing without hitting the real API - Laravel 10 / 11 / 12, PHP 8.1-8.4
- Well tested: unit + feature tests, PSR-12, full PHPDoc
Create a checkout
use Romansh\LaravelCreem\Facades\Creem;
$checkout = Creem::checkouts()->create([
'product_id' => 'prod_123',
'success_url' => route('dashboard'),
'customer' => ['email' => $user->email],
]);
return redirect($checkout['checkout_url']);
Multi-profile in action
// Use a different Creem account per product line
$txns = Creem::profile('product_a')->transactions()->list();
Webhook listener: grant access on payment
Event::listen(GrantAccess::class, function (GrantAccess $e) {
$user = User::where('email', $e->customer['email'])->first();
$user?->update(['plan' => 'pro', 'subscribed_at' => now()]);
});
Quick start
composer require romansh/laravel-creem
php artisan vendor:publish --tag=creem-config
Add CREEM_API_KEY and CREEM_WEBHOOK_SECRET to .env and you're good to go.
Interactive demo app
There's also romansh/laravel-creem-demo, a full working app (Laravel 12 + Livewire + Tailwind) built to explore every feature through a web UI: configure API keys in the browser, create products, trigger checkouts, manage subscriptions, and watch webhook events arrive in real time.
composer create-project romansh/laravel-creem-demo my-creem-app
cd my-creem-app && docker-compose up -d
Docker setup includes an optional Cloudflare Tunnel so webhooks work locally without any port forwarding.
Screenshots

API Setup: credentials, webhook URL, profile tabs

Webhooks and Access: live event log, GrantAccess/RevokeAccess in real time

Transactions: payment history with amounts and customer emails

Discounts: create percentage/fixed discount codes

Subscriptions: recurring plans with billing periods

One-Time Payments: product preview modal, checkout flow
Links
- Laravel SDK: github.com/romansh/laravel-creem
- Demo app: github.com/romansh/laravel-creem-demo
- Omnipay driver: github.com/romansh/omnipay-creem (framework-agnostic, for projects already using Omnipay)
Feedback and issues are welcome on GitHub or in the comments below. If you end up using one of these packages, I'd be happy to hear how it works out.
Top comments (0)