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

Larahook Laravel Package

coinvestor/larahook

LaraHook brings WordPress-style actions and filters to Laravel. Register and run hooks anywhere in your app or packages, prioritize callbacks, and extend behavior without editing core code. A lightweight, familiar API for clean, decoupled customization.

View on GitHub
Deep Wiki
Context7

Getting Started

Larahook is CoInvestor's webhook layer for Laravel: it hangs off Eloquent model events so you can notify external systems (or internal services) when a record is created, updated, or deleted without writing dispatch code at every call site.

Minimal path to a first webhook:

  1. composer require co-investor/larahook (1.4.3 is the current release; it is the first line to declare Laravel 13 support).
  2. Publish the package assets — php artisan vendor:publish with the Larahook provider/tag from the README — so you get the config file and any webhook delivery table/migrations. Run php artisan migrate.
  3. Add the package's HasWebhooks trait to the model you want to emit for.
  4. Declare the endpoints (and the events they care about) using the array/method the trait exposes, then hit the model in tinker and confirm a job lands on the queue and a row lands in the delivery log.

Where to look first, in order:

  • config/larahook.php — the single source of truth for the queue connection/queue name, retry and backoff policy, HTTP timeout, and signing secret. Read this before writing any webhook definitions; most "why isn't it firing / why is it slow" questions are answered here.
  • The trait itself (vendor/co-investor/larahook/src/...) — it registers the model event listeners, so it tells you exactly which events are hooked and what gets serialized.
  • The dispatch job class — this is where retries, signing, and failure handling live, and it's the class you'll end up faking in tests and overriding in config when you need different behaviour.

First use case worth wiring: an outbound "order.created" to a partner or an internal event bus. Keep it on a dedicated queue (see gotchas) rather than default, because webhook traffic is bursty and you don't want it competing with mail and notifications.

Implementation Patterns

Model-event driven (the default). Declare endpoints alongside the model so ownership sits with the domain object. This is the pattern to prefer for CRUD-shaped resources: create/update/delete map cleanly to order.created, order.updated, order.deleted, and the package handles the dispatch plumbing.

Explicit dispatch for domain events. Model events are a poor fit for things that aren't 1:1 with a row change — a payment captured, a refund settled, a state machine transition. Call the package's dispatch entry point from an event listener or a domain action class instead, so the webhook fires once per business event rather than once per save().

Payload shaping via API Resources. Do not let the model serialize itself. Wrap it in a JsonResource (or an explicit array) before it goes on the queue. Two reasons: you control the wire contract independently of schema changes, and you avoid leaking columns you forgot about. Keep a version field (v, or a dated event name) in the payload so consumers can evolve with you.

Queue everything, always. A synchronous webhook delivery inside a request is a latency bug and a timeout bug. Put deliveries on the queue, configure retries with exponential backoff in config/larahook.php, and set a hard HTTP timeout (5–10s is usually right). Treat "delivered" as best-effort with retries, not as a transaction.

Signing and verification. Set a per-environment secret and sign the payload (HMAC over the raw body, header-based, timestamped). Document the verification snippet for consumers — this is the part integrators get wrong most often. Rotate secrets by accepting two keys during a window rather than cutting over instantly.

Idempotency for consumers. Because retries and at-least-once delivery are inherent, include a stable delivery/event ID in the payload and headers so consumers can dedupe. Cheap to add now, painful to retrofit.

Testing. Queue::fake() (or Bus::fake()) plus an assertion that the job was pushed for the right model and event; Http::fake() plus Queue::fake() released to run the job for payload/signature assertions. Keep one contract test per webhook type asserting the exact JSON shape — that's your regression net when a Resource changes.

Local development. Point endpoints at a tunnel (ngrok/Expose) or at a local sink route that logs the request. If the package verifies TLS on outbound calls, be aware self-signed local endpoints will fail — use a real tunnel host rather than disabling verification.

Gotchas and Tips

  • Mass updates bypass everything. Order::query()->update([...]), upsert, and raw DB writes fire no model events, so no webhooks. If a bulk operation must notify, dispatch explicitly after it commits.
  • Quiet saves skip webhooks too. saveQuietly(), withoutEvents(), and deleteQuietly() are deliberate event suppressors. Useful for seeding, dangerous if it creeps into production code paths.
  • Fire after commit. If your queue connection is not sync and you use after_commit = false, a worker can pick the job up before the transaction commits and read stale/missing data. Either set after_commit on the queue connection or dispatch from an DB::afterCommit callback. Related: on deleted, capture relations before the delete, since cascades may already have removed them by the time the job runs.
  • Serialization goes stale. If the job stores the model and re-fetches it, a later update can change the payload between dispatch and delivery. If the payload must reflect the moment of the event, snapshot it to an array/resource at dispatch time.
  • Dedicated queue. Give webhooks their own queue name in config and run a worker for it. Otherwise a slow partner endpoint stalls your mail queue and a deploy's worth of jobs pile up behind it.
  • Config caching. After editing config/larahook.php, run php artisan config:cache on deploy (and config:clear locally). A surprising number of "my config change did nothing" reports are stale cached config.
  • Upgrading to 1.4.3. The release is additive only — Laravel 13 support, no API or behavioural changes, no deprecations. Upgrade is low risk on 1.4.2. Two things to actually check: the new illuminate/* constraint may have bumped the minimum PHP version, and if you're on an older Laravel you should confirm 1.4.3 still satisfies your pin (it should — the constraint is usually widened, not swapped). Run your webhook contract tests after the bump; a framework major can change queued-job serialization and Http client defaults even when the package itself is unchanged.
  • Watch the framework-tracking cadence. A package that ships a Laravel-major compatibility release this quickly is well maintained, which is a good signal — but it also means the maintainers' supported-version matrix moves. Pin the package and read the constraints before every Laravel major.
  • Failure visibility. Wire the job's failed() handler (or the package's failure hook) to your logging/alerting. Silent webhook death is the classic failure mode: retries exhaust, nobody notices, downstream data drifts for a week. The delivery log table is only useful if something is watching it.
  • Extension points to know: the config file (queue, retries, timeout, secret), the job class (subclass/rebind via container if you need custom signing or headers), and the payload resource. Prefer these over forking — forking a small package to change one header is how you end up maintaining it.
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.
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
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource