aimeos/aimeos-headless
Aimeos Headless is a Laravel package that provides a fast, scalable JSON REST API for e-commerce, covering product catalogs, categories, carts, checkout, orders, customers, and admin endpoints so you can build custom storefronts with any frontend.
Scaffold the project with Composer and you get a full Laravel app with the Aimeos e-commerce engine wired in:
composer create-project aimeos/aimeos-headless shop
cd shop
cp .env.example .env
php artisan key:generate
# set DB_* in .env
php artisan aimeos:setup --option=setup/default.sql
php artisan serve
The aimeos:setup step is the one people forget — it creates the Aimeos schema and loads demo products, categories, and a default site. Without it the API returns empty payloads and you'll waste an hour blaming your HTTP client.
Where to look first:
config/shop.php — the master config (sites, locales, routes, DB mapping). This is not config/app.php; Aimeos reads its own tree.routes/ and the /jsonapi prefix — every resource is exposed there.ext/ — where your custom Aimeos extensions live.vendor/aimeos/aimeos-core/ — the engine; read-only, but you'll grep it constantly.First use case: hit the product endpoint.
curl "http://localhost:8000/jsonapi/product?page[limit]=5&include=price,media"
You'll get a JSON:API document with data, included, links, and meta. To build a cart you first need a token:
curl -X POST http://localhost:8000/jsonapi/login \
-H "Content-Type: application/json" \
-d '{"data":{"type":"session","attributes":{"username":"[email protected]","password":"secret"}}}'
Use the returned token as Authorization: Bearer <token> for basket, order, and customer resources.
Treat it as a JSON:API backend, not a Laravel resource collection. Every endpoint follows the jsonapi.org spec: filter[...], sort[...], include=, page[offset]/page[limit], sparse fieldsets via fields[...]. If you're used to Laravel API Resources, this feels verbose but is consistent and lets a frontend SDK (Vue/Nuxt/React) do the heavy lifting generically.
Typical frontend workflow (SPA / SSR):
GET /jsonapi/product?filter[catid]=...&include=price,media,textGET /jsonapi/product/{code}?include=...POST /jsonapi/basket with a order/product line item, PATCH to update quantities, DELETE to remove. Baskets are stored server-side and keyed by the token — guests get a transient session basket.POST /jsonapi/order after adding address and payment/shipping service line items to the basket.GET /jsonapi/customer, GET /jsonapi/order (scoped to the authenticated user).Multi-site and locale. Aimeos supports several shops/sites in one install. The active site is resolved by hostname (config/shop.php → sites → */mapping), and the locale (language, currency) is derived from the request. If you're serving multiple storefronts, this is the feature that saves you from spinning up N Laravel apps.
Auth pattern. The /jsonapi/login endpoint returns a bearer token stored in the users-equivalent table. There's also JWT support if you enable aimeos/jwt. Protect the frontend with your own SPA auth only when you have non-Aimeos routes; otherwise let Aimeos own it.
Customization lives in Aimeos extensions, not in app/. When you need a custom field, a new endpoint, or to shape the payload, create an extension under ext/ (php artisan aimeos:setup:extension yourname) with its own setup/ schema and src/ managers. The Laravel-side service providers just register them. Fighting this — e.g. hacking vendor/ — will break on the next composer update.
Frontend integration tip: generate an OpenAPI/JSON:API TypeScript client once and share it across web and mobile. The schema is stable enough that this pays off.
Testing: use php artisan test for your extension-level unit tests, but for API contract tests spin up a seeded SQLite DB (DB_CONNECTION=sqlite in a .env.testing) and run aimeos:setup in CI. It's fast and catches schema/payload drift.
php artisan aimeos:setup after every schema or config change. The setup command migrates and re-seeds; running it on a populated DB with the default SQL will add demo data. Use --option=setup/default.sql --skip flags or a custom setup file in production.config/shop.php is cached like any Laravel config — php artisan config:clear after edits. But Aimeos also has its own cache layer; use php artisan aimeos:clear when product data or category trees look stale.type and attributes/relationships. Validation errors come back as 422 with errors[], not Laravel's message shape. Wrap this in a frontend error handler early.config/cors.php). A Nuxt/Next dev server on :3000 will fail until you add it — obvious in hindsight, opaque in the browser.aimeos/ai-payments-*). Don't expect checkout to hit a live PSP out of the box.\Aimeos\MShop::create($context, 'product')) and run the query directly in tinker — the filters behave differently from Eloquent and the error messages are terse.product.index.* in config/shop.php) and warm the catalog caches. This is the single biggest "why is my shop slow" culprit.X-Aimeos-Site-style hint in multi-tenant setups, either via hostname mapping or a query parameter — don't try to guess the tenant in PHP middleware; it's resolved earlier than Laravel middleware runs.composer.json, read the changelog, and always run aimeos:setup after composer update. Laravel upgrades (upgrade.md shipped with the distribution) also touch the Aimeos integration layer.How can I help you explore Laravel packages today?