Generate Laravel OpenAPI Documentation Automatically
Published · Updated
Generate accurate OpenAPI documentation automatically from your Laravel application with Scramble. No hand-maintained PHPDoc annotations required.
Maintaining API documentation by hand creates a second version of your API: one in the application code and another in an OpenAPI file or a set of PHPDoc annotations. Eventually, the two drift apart.
Scramble takes a different approach. It automatically analyzes your Laravel routes and application code to generate an OpenAPI 3.1 document, often called Swagger documentation. Validation rules become request schemas, API resources become response schemas, and the generated documentation stays aligned with the code.
Install Scramble and generate the documentation
Install Scramble in your Laravel application:
composer require dedoc/scrambleThat is enough to get started. Scramble registers two routes:
/docs/apirenders interactive API documentation./docs/api.jsonreturns the generated OpenAPI document.
By default, Scramble documents routes whose URI starts with api. Open /docs/api and you should already see your endpoints. You do not need PHPDoc annotations or a separate specification file.

The rest of this article uses a small booking API to show what Scramble can infer and where optional documentation can make the result more useful.
The Laravel API we will document
The example API lets authenticated users browse places and manage bookings:
GET /api/placesGET /api/bookingsPOST /api/bookingsGET /api/bookings/{booking}PUT /api/bookings/{booking}DELETE /api/bookings/{booking}The routes use Laravel Sanctum:
use App\Http\Controllers\Api\BookingsController;use App\Http\Controllers\Api\PlacesController;use Illuminate\Support\Facades\Route;
Route::middleware('auth:sanctum')->group(function () { Route::get('places', PlacesController::class); Route::apiResource('bookings', BookingsController::class);});The places endpoint validates filters and returns a paginated API resource collection:
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;use App\Http\Resources\PlaceResource;use App\Models\Place;use Illuminate\Http\Request;use Illuminate\Validation\Rule;
class PlacesController extends Controller{ public function __invoke(Request $request) { $request->validate([ 'price_from' => ['integer'], 'price_to' => ['integer'], 'sorts' => ['array'], 'sorts.*.field' => [Rule::in(['price'])], 'sorts.*.direction' => [Rule::in(['asc', 'desc'])], ]);
$places = Place::query() ->when( $request->integer('price_from'), fn ($query, $price) => $query->where('price', '>=', $price), ) ->when( $request->integer('price_to'), fn ($query, $price) => $query->where('price', '<=', $price), ) ->paginate($request->integer('per_page', 15));
return PlaceResource::collection($places); }}The resource defines the response data:
namespace App\Http\Resources;
use Illuminate\Http\Request;use Illuminate\Http\Resources\Json\JsonResource;
class PlaceResource extends JsonResource{ public function toArray(Request $request): array { return [ 'id' => $this->id, 'name' => $this->name, 'price' => $this->price, ]; }}The bookings controller follows the same pattern. Validation defines the accepted input, route-model binding resolves the booking, resources define successful responses, and explicit return branches describe other outcomes:
public function store(Request $request){ $data = $request->validate([ 'place_id' => ['required', 'exists:places,id'], 'date' => ['required', 'date'], ]);
$place = Place::findOrFail($data['place_id']);
if (! $place->available($request->date('date'))) { return response()->json([ 'message' => 'Place is not available at the given date', ], 409); }
$booking = $request->user()->bookings()->create($data);
return BookingResource::make($booking);}
public function destroy(Booking $booking){ $booking->delete();
return response()->noContent();}What Scramble infers from Laravel code
Scramble builds the OpenAPI document from the same code Laravel uses to handle the request:
| Laravel code | Generated OpenAPI documentation |
|---|---|
| Routes and model bindings | Paths and typed path parameters |
| Validation rules and FormRequest classes | Query parameters and request bodies |
Request input methods such as integer() | Parameter types and default values |
JsonResource classes | Reusable response schemas |
| Resource collections and paginators | Collection, links, and meta schemas |
| Controller return statements | Status codes and response bodies |
| Validation, authorization, and model binding | Common error responses |
Request parameters from validation
Because GET /api/places uses validation rules, Scramble documents price_from, price_to, and the nested sorts structure as query parameters. The call to $request->integer('per_page', 15) adds an integer per_page parameter with a default value of 15.
For POST /api/bookings, the same validation rules become a JSON request-body schema. Required rules, formats, nested fields, enums, and other supported validation constraints are reflected in the generated OpenAPI document.
The same approach works when validation is moved into a Laravel FormRequest. See the Laravel OpenAPI request documentation for the complete behavior and available overrides.
Responses from resources and return statements
Scramble analyzes PlaceResource::toArray() to build the item schema. It also recognizes that the resource collection wraps a paginator, so the generated response includes the resource array and Laravel’s pagination links and meta objects automatically.
No @response annotation is required:
return PlaceResource::collection( Place::paginate(),);
The booking example produces several response types from ordinary Laravel code:
BookingResource::make($booking)becomes the successful resource response.response()->json(..., 409)becomes a documented conflict response.response()->noContent()becomes a204response.- validation contributes the standard
422response. - route-model binding contributes the not-found response.
You can learn more in the Laravel OpenAPI response documentation.
Add descriptions only where code cannot provide them
Static analysis describes the API’s structure, but it cannot infer all of its business meaning. PHPDoc remains useful for human-facing summaries and descriptions; it is not required to define every request and response schema.
For example:
class PlacesController extends Controller{ /** * List bookable places. * * Filter places by price and sort the results before choosing a booking. */ public function __invoke(Request $request) { // ... }}The first line becomes the operation summary and the remaining prose becomes its description.

Scramble groups operations by controller name by default. If that organization does not fit your API, add one or more tags to the controller:
/** * @tags Bookings management */class PlacesController extends Controller{ // ...}
Document Laravel Sanctum authentication
The example routes use auth:sanctum. Scramble can derive their OpenAPI security requirements directly from that middleware.
Publish the configuration if you have not done so:
php artisan vendor:publish --provider="Dedoc\Scramble\ScrambleServiceProvider" --tag="scramble-config"Then enable the middleware authentication strategy in config/scramble.php:
'security_strategy' => \Dedoc\Scramble\SecurityDocumentation\MiddlewareAuthSecurityStrategy::class,Scramble will add a bearer security scheme, mark the Sanctum routes as protected, and document their 401 Unauthenticated response. Routes without matching authentication middleware remain public in the OpenAPI document.

For API keys, custom middleware, or multiple security schemes, see the Laravel API authentication documentation.
Customize the documentation page
The published configuration also lets you customize the API title, overview, renderer, and logo. For example:
return [ // ...
'info' => [ 'version' => '1.0.0', 'description' => file_get_contents( base_path('resources/docs/api-overview.md') ), ],
'ui' => [ 'title' => 'Bookly API', ],
'renderers' => [ 'elements' => [ // Keep the other Elements options from the published config. 'logo' => '/images/logo.svg', ], ],];The overview supports Markdown, so it can explain authentication, important workflows, or links that consumers should read before using the endpoints.

Control access in production
Scramble exposes the documentation automatically in local environments. To make it available in production, define Laravel’s viewApiDocs gate.
For private documentation, restrict it to the appropriate users:
use App\Models\User;use Illuminate\Support\Facades\Gate;
public function boot(): void{ Gate::define( 'viewApiDocs', fn (User $user) => $user->is_admin, );}If the API documentation is intentionally public, the gate can return true without requiring a user. Make that choice explicitly. The generated documentation describes the surface of your API even when the API endpoints themselves remain protected.
What else Scramble can document
The booking API covers the core workflow, but Scramble also understands many common Laravel patterns:
- inline validation and FormRequest classes;
- route, query, header, cookie, and request-body parameters;
- JSON resources, conditional fields, loaded relationships, collections, and pagination;
- JSON responses, redirects, files, streams, exceptions, and error responses;
- Eloquent models, enums, and plain PHP objects;
- multiple API documents and custom route selection;
- manual attributes and extensions when application-specific behavior needs an override.
Scramble PRO adds automatic OpenAPI documentation for integrations including Spatie Laravel Data and Spatie Laravel Query Builder.
Conclusion
Automatic Laravel API documentation does not have to mean maintaining a large set of annotations. Scramble uses the routes, validation rules, resources, and return statements already present in your application to generate an OpenAPI 3.1 document.
Start with:
composer require dedoc/scrambleThen open /docs/api, review what Scramble inferred, and add human-written descriptions only where they make the API easier to understand.
Continue with the request documentation, response documentation, and authentication guide.
