Building the CREEM Laravel Package: Accept Global Payments in Minutes

Published: (February 20, 2026 at 01:52 AM EST)
3 min read
Source: Dev.to

Source: Dev.to

I recently built a full‑featured Laravel package for CREEM, the developer‑first Merchant of Record platform. It lets you accept global payments in under five minutes.

Why it matters

If you sell SaaS, digital products, or software licenses, you have to deal with:

  • VAT/GST/sales tax in 190+ countries
  • Payment processor integration
  • Subscription lifecycle management
  • License key distribution
  • Refunds and disputes

CREEM handles all of this as a Merchant of Record at 3.9 % + 30 ¢ with zero monthly fees, taking legal responsibility for tax compliance so you can focus on building your product. The missing piece was a native Laravel package.

Package overview

creem/laravel wraps the entire CREEM API with Laravel‑native patterns.

 route('checkout.success'),
    'customer' => ['email' => $user->email],
]);

return redirect($checkout['checkout_url']);

All API endpoints are covered: Products, Checkouts, Subscriptions, Customers, Transactions, Licenses, and Discounts.

Billable trait

Attach the Billable trait to your User model to expose billing methods directly:

checkout('prod_abc123', ['success_url' => '/thanks']);
$user->creemSubscriptions();
$user->cancelSubscription('sub_xyz', 'scheduled');
$user->billingPortalUrl();

Webhooks & events

The package auto‑registers a webhook endpoint at POST /creem/webhook with HMAC‑SHA256 signature verification. Each webhook type maps to a typed Laravel event.

// EventServiceProvider example
protected $listen = [
    CheckoutCompleted::class => [
        GrantAccessListener::class,
    ],
    SubscriptionCanceled::class => [
        RevokeAccessListener::class,
    ],
];

Convenience events AccessGranted and AccessRevoked fire automatically for the appropriate webhook combinations:

Event::listen(AccessGranted::class, function ($event) {
    // Fires on: checkout.completed, subscription.active, subscription.paid
    $user = User::where('email', $event->payload['customer']['email'])->first();
    $user->update(['has_access' => true]);
});

Test & CI

  • 73 tests, 137 assertions covering every API method, webhook verification, and event dispatch.
  • CI matrix runs on PHP 8.1–8.4 and Laravel 10, 11, 12.

Installation

  1. Require the package

    composer require creem/laravel
  2. Publish config & migrations

    php artisan vendor:publish --tag=creem-config
    php artisan vendor:publish --tag=creem-migrations
    php artisan migrate
  3. Configure environment variables

    CREEM_API_KEY=creem_test_your_key
    CREEM_WEBHOOK_SECRET=whsec_your_secret
  4. Add the Billable trait to User (see above).

  5. Create a checkout route

    user()->checkout('prod_your_product', [
            'success_url' => url('/thanks'),
        ]);
        return redirect($checkout['checkout_url']);
    });
  6. Handle webhooks

    payload['customer']['email'] ?? null;
            User::where('email', $email)->update(['is_premium' => true]);
        }
    }

That’s it—CREEM takes care of the payment page, tax calculation, and receipt. Your webhook listener grants access when payment succeeds.

Demo & resources

Feature summary

FeatureDetails
API Methods26 (full CREEM coverage)
Webhook Events15 typed Laravel events
Tests73 tests, 137 assertions
PHP Support8.1, 8.2, 8.3, 8.4
Laravel Support10, 11, 12
Code StyleLaravel Pint enforced
CI/CDGitHub Actions matrix
Artisan Commandscreem:webhook-secret, creem:sync-products
Error Handling4 typed exception classes with trace IDs

Built by Hani Amin (Discord: xh90) for the CREEM Scoops Laravel integration bounty.

0 views
Back to Blog

Related posts

Read more »