omniconva/laravel
OmniConva for Laravel is a lightweight integration package that brings OmniConva services into Laravel applications, offering simple configuration, familiar Laravel conventions, and a clean starting point to help you add OmniConva-powered functionality quickly.
This is still a young package (v1.0.x), so treat the whole surface as new — and treat patch releases as load-bearing, because v1.0.1 shipped both a security hardening pass and one breaking change. The fast path:
composer require the package, then run php artisan omniconva:install. This is the canonical entry point — it should publish config/omniconva.php, register the route prefix, and scaffold any required migration/keys.php artisan migrate. v1.0.1 adds a second migration — the idempotency key column is widened to 255 and claims gain an owner token. It's published under --tag=omniconva-migrations, so if you publish tags selectively, make sure you pick it up. Skipping this leaves you on the old schema and idempotency take-over protection won't work..env, plus OMNICONVA_WEBHOOK_URL. That URL must be https as of v1.0.1 — http:// is only accepted for localhost and 127.x, and elsewhere only if you set OMNICONVA_ALLOW_HTTP=1 (e.g. a Docker Compose service name). The X-OmniConva-Signature check runs on every route, so nothing works until the secret matches on both sides. If you change the prefix later, clear route caches (php artisan route:clear / optimize:clear).php artisan omniconva:ping to confirm outbound connectivity and signing, and php artisan omniconva:test to exercise the contract against your app. Both are the first things to reach for when something "just doesn't work".EloquentProductSource so GET {prefix}/products and /products/{id} reflect your catalog. Start by hitting those two endpoints locally with a signed request (or via omniconva:test) before wiring up the traits.Read order: config/omniconva.php → the published routes/middleware → the SyncsWithOmniConva trait → the order handling path for POST {prefix}/orders (and OmniConva\Laravel\Exceptions\OrderRefused).
Product catalogue. Everything is served from the EloquentProductSource, so model selection, eager loads, and visibility filtering live there. Keep the source query the single place that decides what is exposed — don't scatter where('published', true) through controllers. Map your attributes into OmniConva's standard shape once, in the source. As of v1.0.1 the trait layer is defensive: a mapping or encoding failure no longer aborts your save, it's reported to your handler instead, and invalid UTF-8 is substituted rather than fatal. That's a safety net, not a licence to ship sloppy mapping — keep an eye on your exception reporter for sync failures that used to be loud.
Outbound product webhooks with traits.
SyncsWithOmniConva on the primary product model: webhooks are queued after commit, so you get correct behaviour inside transactions for free — but only if a queue worker is running and the connection supports afterCommit semantics.SyncsParentWithOmniConva on variants/children: use this when a child change (price, stock, name) must invalidate the parent product payload. Configure the parent relation explicitly; the trait needs to know how to resolve it.save, delete) over bulk operations. Model::query()->update([...]) and raw upserts bypass events entirely and will silently skip webhooks — do those through model instances or fire a manual sync.Order ingest. POST {prefix}/orders carries an Idempotency-Key. Back it with a unique index on (endpoint, idempotency_key) and a stored response, so a retried request returns the original result rather than creating a second order. The key column is now 255 chars — size any custom index accordingly (watch for index length limits on older MySQL). Expect concurrent duplicates: catch the unique-constraint violation and return the cached response. v1.0.1 adds an owner token to each claim, so a stalled request whose claim was taken over cannot release or complete the claim that replaced it — don't hand-roll your own release logic around the package's claim, or you'll reintroduce the race.
Refusing an order. Throw OmniConva\Laravel\Exceptions\OrderRefused (out of stock, invalid address, closed store) with a machine-readable message. That message — and only that message — is forwarded to OmniConva. Any other exception (a QueryException containing SQL and customer data, for example) goes to your handler and the caller gets a generic 500. This is the refusal mechanism: use it deliberately and never signal a business refusal by throwing something else. Implement the test-order filter in one place (config/flag) so test traffic never touches fulfilment.
Order status and tracking. Call OmniConva::orderUpdated($order) at the point of truth: an observer on status change, and again when tracking numbers are attached. Centralise it (observer or a small service) rather than calling it from controllers, so console commands and admin actions also push updates.
Signature verification. It applies to every route, inbound and outbound. On inbound, verify against the raw body ($request->getContent()), not the parsed input — middleware like TrimStrings/ConvertEmptyStringsToNull can mutate $request->all() and break the hash. Keep the verification middleware early in the stack for OmniConva routes.
Chat widget. Drop <x-omniconva-chat /> into your layout. Signed customer identity means you must pass the authenticated user (or explicitly handle guests) — don't render it for anonymous traffic unless your config allows it, or the signature will be meaningless. The component now ignores a non-scalar customer id, so don't pass an object or array expecting it to be serialised.
Commands in CI. Add php artisan omniconva:test to your pipeline (or a dedicated integration job) and omniconva:ping to your post-deploy smoke checks. omniconva:install is safe to re-run but treat it as idempotent scaffolding, not a migration tool — it reads current values from config (correctly, even with a cached config), never blanks an existing credential, and quotes what it writes. Don't pass secrets as CLI options if you can avoid it; the command now warns you when you do, because they land in your shell history and process list.
OMNICONVA_WEBHOOK_URL is http:// and not localhost/127.x, deliveries fail. Either move to https or set OMNICONVA_ALLOW_HTTP=1 for internal/service-name setups. Also note webhook deliveries no longer follow redirects — if you were relying on an http→https 301, fix the configured URL instead.php artisan migrate on upgrade. The idempotency schema change is easy to miss in a deploy that only runs composer update. Add it to your release checklist.OrderRefused messages reach OmniConva. Wrapping an order creation in a broad try/catch that re-throws a generic RuntimeException gives merchants an opaque 500; catch and translate to OrderRefused for anything the merchant can act on, and let genuine faults hit your handler.sync hides failures; test with Redis/database driver before shipping.update(), insert(), or truncate-and-reload on products will not enqueue webhooks. Document this in your team's playbook and add a manual re-sync path.SyncsParentWithOmniConva fails quietly if the parent relation isn't configured or returns null — assert it in a test.prefix, run optimize:clear; otherwise omniconva:test and OmniConva's calls will 404 against stale routes. An empty prefix is now refused outright.null (not "inf"), and big numeric ids in order payloads stay strings. Type-hint ?float/string accordingly and don't (int)-cast ids — you'll lose precision.OrderRefused message is surfaced to merchants, so make it a clear, actionable sentence rather than a stack-trace fragment.omniconva:install, remember it reads from config — with a cached config you must config:clear (or edit the cached source) before the values you expect are picked up.EloquentProductSource is the natural seam for custom attributes, pricing rules, and multi-store scoping — extend there rather than post-processing payloads downstream.composer.json (v1.0.1 includes security fixes — don't sit on v1.0.0) and keep omniconva:test in CI so the next release's contract changes are caught before deploy.How can I help you explore Laravel packages today?