DEV Community

Cover image for Building a Laravel SDK for Creem.io: multi-profile billing, webhook events, and an interactive demo
Roman Shalabanov
Roman Shalabanov

Posted on • Edited on

Building a Laravel SDK for Creem.io: multi-profile billing, webhook events, and an interactive demo

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 .env per 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 with Creem::withConfig([...])
  • Webhooks done right: auto-registered routes, HMAC signature verification, typed Laravel events including GrantAccess / RevokeAccess
  • Artisan tooling: php artisan creem:test-webhook checkout.completed for 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']);
Enter fullscreen mode Exit fullscreen mode

Multi-profile in action

// Use a different Creem account per product line
$txns = Creem::profile('product_a')->transactions()->list();
Enter fullscreen mode Exit fullscreen mode

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()]);
});
Enter fullscreen mode Exit fullscreen mode

Quick start

composer require romansh/laravel-creem
php artisan vendor:publish --tag=creem-config
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Docker setup includes an optional Cloudflare Tunnel so webhooks work locally without any port forwarding.

Screenshots

API Setup: credentials, webhook URL, profile tabs
API Setup: credentials, webhook URL, profile tabs

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

Transactions: payment history with amounts and customer emails
Transactions: payment history with amounts and customer emails

Discounts: create percentage/fixed discount codes
Discounts: create percentage/fixed discount codes

Subscriptions: recurring plans with billing periods
Subscriptions: recurring plans with billing periods

One-Time Payments: product preview modal, checkout flow
One-Time Payments: product preview modal, checkout flow

Links

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)