bagisto/bagisto-api
Comprehensive REST and GraphQL APIs for Bagisto e-commerce, exposing shop and admin endpoints via API Platform. Requires PHP 8.3+ and Bagisto 2.4.7. Quick Composer install plus an artisan command gets API docs, GraphiQL playgrounds, and storefront rate limiting running fast.
Prerequisites — check these before composer require, not after. The package is pinned to Bagisto v2.4.7 in CI, requires PHP 8.3+, and pulls in api-platform/laravel / api-platform/graphql ~4.3.8. If your Bagisto install has drifted off 2.4.7, you will hit Composer resolution failures on the first install. Run composer show bagisto/bagisto and confirm the version first; upgrading Bagisto later means re-validating this package.
composer require bagisto/bagisto-api
php artisan bagisto-api-platform:install
php artisan bagisto-api-platform:optimize # per the changelog; run after deploy
The install command registers the service provider in bootstrap/providers.php and publishes vendor config. If you use the manual route (packages/Webkul/BagistoApi/), remember to add the PSR-4 entry and re-run composer dump-autoload — otherwise you'll get a silent "routes exist but resources 404" situation.
Where to look first: open /api/shop/docs (OpenAPI UI) and /api/graphiql. Do not start from the README URLs on your own domain and assume they work — your first hour should be spent confirming the landing page at /api renders and both doc surfaces load. Those two pages are the real documentation; the README is orientation only.
First use case: the highest-leverage entry point is the read path for a headless storefront — products, categories, locale, channel, currency. Write one GraphQL query against /api/graphiql that fetches a product list with prices in a chosen currency and translations in a chosen locale. That single query tells you whether key management, headers, and serialization are wired correctly, and it's the query your frontend will make on every page.
Two auth realms exist and they are not interchangeable:
STOREFRONT_KEY_PREFIX, STOREFRONT_PLAYGROUND_KEY), rate-limited via STOREFRONT_DEFAULT_RATE_LIMIT.Authorization: Bearer id|token) generated in Settings → Integration. The Integration menu is hidden until you enable Configuration → API → Integration → Module Settings, which is the single most common "the feature doesn't exist" moment. The plaintext token is shown once; store it in your secret manager immediately.Treat REST and GraphQL as two different clients, not two transports for one client. In practice the split that holds up:
Give each surface its own HTTP client class, its own retry policy, and its own credential. Never let the storefront key and the admin token live in the same client instance or the same .env group — a leak boundary is worth the small duplication.
Schema-driven client generation is the real payoff. Run php artisan bagisto-api-platform:export-schema and commit schema/generated/ to your repo. Then:
php artisan bagisto-api-platform:export-schema --path=./build --transport=graphql
Feed openapi-shop.json into openapi-typescript and the .graphql SDL into graphql-codegen to produce typed clients. The command intentionally refuses to emit a spec that leaks admin paths into the storefront surface or contains a storefront key, so a successful export is also a cheap correctness gate. Make it a CI step and diff the generated files on every dependency bump — that diff is your upgrade changelog.
Token lifecycle as code. Each admin token is scoped to one admin user and inherits that user's role permissions; one active token per admin. Model this in your deploy docs as: token per environment per persona (e.g. a dedicated "integrations" admin for CI, another for the ops dashboard). Rotation is Regenerate on the Integration page plus a secret update — script the second half, because the first half invalidates the old token instantly.
Cart token flow. Guest carts are addressed by token; on login you merge the guest cart into the customer cart (there's a merge-cart API with configurable-product support). Persist the cart token client-side as the source of truth for checkout state rather than reconstructing cart contents from your own DB. Checkout is multi-step (cart → address → shipping → payment) so make your orchestration idempotent and re-read the cart between steps.
Extend by composition, not by editing. The package is built from API Platform providers, processors, and input/output DTOs (*Provider, *Processor, *Input/*Output). Add your own resources in a separate packages/Webkul/YourApi/ package that reuses the same conventions. Because the manual install path is literally packages/Webkul/BagistoApi/, the temptation to patch in place is strong — resist it, or you lose the ability to git diff upstream on the next release.
Test with their patterns. The package ships extensive Pest feature coverage; mirror its structure for your own smoke tests rather than hand-rolling. The Postman collections in bagisto-api-collection are a fast way to confirm an environment is sane before you trust your own client code.
The version pin is the biggest risk. Bagisto v2.4.7 is what CI tests; the package's release cadence tracks Bagisto's. Pin bagisto/bagisto, bagisto/bagisto-api, and both api-platform/* packages to exact versions in composer.json, and treat any one of them moving as a three-way upgrade. Do not bump api-platform/laravel independently — the changelog shows tight coupling and a FixedSerializerContextBuilder that patches API Platform's own context handling.
Nine stars, zero dependents. This is young, fast-moving infrastructure. Read the BagistoApiServiceProvider and the Coming.md changelog before committing. The practical mitigations: exact version pins, a fork under your org if you need a hotfix, and an upgrade cadence tied to Bagisto releases rather than continuous.
Performance is opt-in. The changelog cites GraphQL list queries going ~1.5s → ~0.3s, but only after running bagisto-api-platform:optimize and setting APP_DEBUG=false. If the API feels slow on first deploy, check those two before profiling anything. optimize now caches events and warns loudly when debug mode is on; note that it fails hard if route caching fails, which on a large install usually means a closure route somewhere — read the message, don't retry blindly.
Cache TTL vs. correctness. STOREFRONT_CACHE_TTL=60 is sensible for catalog and CMS pages; it is wrong for cart, customer, and stock-sensitive reads. When you see a stale price or an "in stock" item that isn't, confirm the cache key includes currency, locale, and — critically — whether it excludes authenticated/customer-scoped responses.
Rate limits are per key, not per client. STOREFRONT_DEFAULT_RATE_LIMIT partitions by key. Sharing one key across web, mobile, and an internal job means one noisy consumer starves the others. Issue a key per consumer.
Don't ship the playground. /api/graphiql and /api/admin/graphiql with API_PLAYGROUND_AUTO_INJECT_STOREFRONT_KEY=true are dev conveniences. Gate both behind non-production environments and leave auto-inject off in staging/prod.
Pagination and sorting are inconsistent across endpoints. Cursor-aware pagination exists, and the changelog shows sort/order being retrofitted onto wishlist and customer addresses — which implies it isn't universal. Verify per endpoint against the exported OpenAPI spec rather than assuming ?sort=created_at&order=desc works everywhere.
Error shapes differ by transport. REST returns API Platform Problem+JSON (application/problem+json) — hydrate validation errors from violations, not from a message field. GraphQL returns HTTP 200 with an errors array, so a naive response.ok check will silently swallow failures. Write one unwrapper per transport.
File responses need real URLs. Invoice PDF downloads, downloadable-product files, and product media all generate absolute URLs. A wrong APP_URL, a missing storage:link, or a proxy that rewrites X-Forwarded-* will produce URLs that resolve on the server and 404 in the browser.
Debug order for a 403 on admin endpoints: (1) is the Integration module enabled, (2) is the token the current generation after a Regenerate, (3) does the owning admin's role actually grant that permission — the token can never exceed its owner. There have been permission-mapping bugs on specific resources (Admin Users, per Coming.md), so isolate whether the failure is "all admin endpoints" or "this resource" before filing an issue.
How can I help you explore Laravel packages today?