Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Omise Webhooks Laravel Package

soap/laravel-omise-webhooks

Laravel package for receiving and handling Omise payment webhooks. It registers a webhook endpoint, verifies incoming events, and dispatches them to your handlers so you can react to charges, refunds, and other Omise events without writing boilerplate.

View on GitHub
Deep Wiki
Context7

Getting Started

The v1.2.0 release adds Laravel 13 support. If you're on Laravel 10–12 nothing changes; if you're planning a Laravel 13 upgrade this package will no longer block you. The remaining diffs are Dependabot bumps to fetch-metadata (CI only, no runtime impact).

Minimal setup:

composer require soap/laravel-omise-webhooks
php artisan vendor:publish --tag="omise-webhooks-config"

Then:

  1. Put your Omise keys in .env (OMISE_PUBLIC_KEY, OMISE_SECRET_KEY, and the webhook secret if the config exposes one). Never commit these — the config should read from env() only.
  2. Run php artisan route:list --path=omise to confirm the webhook endpoint the package auto-registers. Paste that full URL into the Omise dashboard (Settings → Webhooks), test mode first.
  3. Run migrations if the package ships a webhooks table (php artisan vendor:publish --tag="omise-webhooks-migrations" then php artisan migrate).
  4. Point your local dev at it with ngrok/expose and trigger a test event from the Omise dashboard.

First real use case: listen for charge.complete (or charge.create) and flip an order to paid. Start by dumping the event payload in a throwaway listener to see exactly what Omise sends before writing business logic.

Implementation Patterns

Listen to the package event, don't parse the request yourself. The value of this package is that it normalises the payload and dispatches a Laravel event. Register a listener in EventServiceProvider (or use Event::listen) and keep the controller thin:

Event::listen(OmiseWebhookReceived::class, MarkOrderPaid::class);

Resolve your domain object via metadata. When creating the charge, stash your own identifier in the Omise metadata array (['order_id' => $order->id]). On the webhook, read it back rather than trying to match on amount or email — both are unreliable for reconciliation.

Always queue the listener. Implement ShouldQueue and return 200 from the endpoint immediately. Omise retries on non-2xx and on timeouts; a slow listener turns one event into five.

Store every webhook before acting on it. Persist the raw payload (or use the package's built-in model if it has one) in the same transaction that guards idempotency:

$record = OmiseWebhook::firstOrCreate(['omise_event_id' => $payload['id']]);
if (! $record->wasRecentlyCreated) return;

This gives you replay capability and a forensic trail when something goes wrong at 2am.

Disable auto-routes when you need control. If the config allows it, turn off the package's route registration and define your own, so you can attach throttle, IP allow-listing, or a tenant-scoped prefix. Keep the package's verification middleware in the chain regardless.

Test with fixtures, not the network. Grab a real payload from the Omise dashboard, drop it in tests/Fixtures/, and POST it at your route in a feature test. Use Event::fake() to assert the package event was dispatched, and Queue::fake() to assert your job was pushed — two separate tests, so a broken listener doesn't hide a broken endpoint.

Gotchas and Tips

  • The race condition is real. The user often returns from the Omise redirect before the webhook lands. Create the order in pending before redirecting, treat the webhook as the source of truth, and never mark paid from the return URL alone.
  • Amounts are integers in the smallest currency unit. Dividing by 100 is wrong for zero-decimal currencies (JPY). Check currency before formatting, and store the raw amount.
  • Signature verification, if present, must run before anything else. Read the signature header from the raw request body — not from the parsed array — since re-encoding will invalidate it. Do this in middleware, not in your listener. If the package verifies by re-fetching the event from the Omise API instead, move that call into the queued job so the HTTP response isn't blocked by an outbound request.
  • CSRF. If you hand-roll the route, it must live in the api middleware group or be excluded from VerifyCsrfToken, otherwise Omise gets a 419 and retries forever.
  • Retries are not ordered. Omise may deliver charge.complete before charge.create. Make your listener tolerant of a missing parent record — upsert rather than findOrFail.
  • Verify the Laravel 13 constraint actually applies to you. v1.2.0 widens the illuminate/* requirement; if your app pins laravel/framework to ^11.0, composer update is a no-op. Run composer why-not soap/laravel-omise-webhooks if the upgrade doesn't take. Laravel 13 also raises the PHP floor, so check php -v before bumping.
  • Debugging tip: log the raw payload and the Omise-Webhook-Signature header at debug level behind a config flag. Webhook bugs are almost always "the payload wasn't what I assumed," and you can't reproduce without the original body.
  • Local dev without a tunnel: write an artisan command that POSTs a saved fixture at your own route. Faster than ngrok and works offline.
  • Extension point: if you need custom behaviour (extra verification, multi-account routing), subclass or decorate the package's handler rather than editing published files — published files drift from upstream and you'll lose fixes on the next bump.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console