REST APIs with Laravel Sanctum and OpenAPI in 2026
A pragmatic template for Laravel REST APIs: versioning, Sanctum vs Passport, idempotency, rate limiting and OpenAPI docs your mobile team can trust.
Sanctum won, mostly
For every REST API I ship on Laravel in 2026 the default is Sanctum. Passport is still fine if you need full OAuth2 flows for third parties, but for most mobile and SPA clients Sanctum is faster to set up, easier to audit and cheaper to run.
The template I start from
- Versioning: URL-based (
/api/v1/…). Header-based versioning is elegant but nobody debugs it well. - Auth: Sanctum personal access tokens for mobile, Sanctum SPA cookies for the web dashboard.
- Idempotency:
Idempotency-Keyheader on every write endpoint mobile calls with retries. - Rate limiting: per user, per IP, per route. RateLimiter facade, custom limiters per tier.
- Docs: Scramble or L5-Swagger generating OpenAPI 3 from PHP attributes.
- Contract tests: Pest tests that assert response shape matches the OpenAPI schema.
Idempotency is not optional
Mobile networks are hostile. Any write endpoint the mobile client calls will be retried, sometimes days later when the app returns to the foreground. Without idempotency you get duplicate orders, duplicate charges and support tickets you cannot explain.
The pattern:
- Client generates a UUID per logical action, sends it as
Idempotency-Key. - Server stores
{key, response_hash, response_body, created_at}for 24 hours. - On a duplicate key, return the cached response verbatim. Do not re-execute the handler.
Ten lines of middleware. Saves you a support conversation a week.
OpenAPI as the source of truth
The moment you have a second consumer of your API (say, iOS and Android) the OpenAPI document is your source of truth, not your Postman collection. Two rules:
- The document is generated from the code, not hand-written. Scramble does this from route + FormRequest attributes.
- The document is checked in CI. If the generated spec differs from the committed one, CI fails.
Bonus: point your mobile team at an OpenAPI generator for TypeScript / Swift / Kotlin clients and stop debating field names.
Rate limiting per tier
Free tier, paid tier and internal tools should not share a rate bucket. Laravel's RateLimiter facade takes a closure — use it to key by user, tier, endpoint. Add a Retry-After header on 429s so the client backs off intelligently.
Observability
Every request should carry a request ID (either the incoming header or generated). Log it, propagate it into jobs, return it on 5xx responses. When a customer opens a support ticket with "it failed at 3:14 pm" you want to grep, not guess.
In summary
Laravel + Sanctum + OpenAPI + a tiny idempotency layer is a boringly effective REST API stack in 2026. Nothing on that list is exotic; the win is in choosing it deliberately and not adding what you do not need.