A new application has no routes/api.php. Run php artisan install:api to add it. On 13.33 the command installs Sanctum 4.3.3 2,988 , publishes config/sanctum.php, migrates the personal_access_tokens table, adds api: to withRouting(), and asks you to add HasApiTokens to User. Its routes get the /api prefix and the stateless api group (Global and Group Middleware). Put the version in the URL and freeze it; a breaking change goes into v2, beside v1:
Route::prefix('v1')->name('v1.')->group(function () {
Route::get('/products', fn () => new ProductCollection(
Product::with('category')->orderBy('id')->paginate(2)))->name('products.index');
Route::get('/products/{product}', fn (Product $product) =>
new ProductResource($product->load('category')))->name('products.show');
// ... tokens and orders, Section 5.20.5
});
Route::prefix('v2')->group(function () {
Route::get('/products/{product}', fn (Product $product) => new V2\ProductResource($product));
});Larger APIs move the closures into Api\V1 controllers (Resource Controllers). The api group has no rate limit until $middleware->throttleApi() in bootstrap/app.php adds throttle:api. The bookshop's limiter, Limit::perMinute(60)->by($request->user()?->id ?: $request->ip()), is registered in AppServiceProvider exactly as in Rate Limiting Routes:
$ curl -si $B/api/v1/products/2 | grep -E '^(HTTP|X-RateLimit|Retry-After)|message' HTTP/1.1 429 Too Many Requests X-RateLimit-Limit: 60 X-RateLimit-Remaining: 0 Retry-After: 59
The first call carried X-RateLimit-Remaining: 59; the 61st in the minute got the 429.