Add or update `stacktrace/inspec` documentation attributes in Laravel APIs by annotating controller actions with `#[StackTrace\\Inspec\\Route(...)]`, mapping request/query/response shapes into the Inspec property DSL, and keeping Fractal transformer `#[Schema]`, `#[ExpandItem]`, and `#[ExpandCollection]` metadata in sync. Use to document endpoints, add OpenAPI annotations, migrate manual docs into Inspec attributes, or fix generated spec gaps in a Laravel project that uses Inspec.
Document endpoints with Inspec attributes, not hand-written YAML. Work from the real Laravel route and the current request/response behavior, then express that behavior with #[Route(...)] on the controller action and transformer metadata where needed.
__invoke.use StackTrace\Inspec\Route; and place #[Route(...)] directly on the action method.route for path parametersquery for query parametersrequest for request bodiesresponse for standard success bodiespaginatedResponse or cursorPaginatedResponse for transformer-backed collectionsoperation: new Operation(...) when a manual route should be authored or customized as a reusable objecttransform() method has #[Schema(...)]. If the transformer exposes includes, annotate include* methods with #[ExpandItem] or #[ExpandCollection].php artisan inspec:generate --stdout when available. Prefer narrowing to the routes you touched with --api, --path, --route, and --method so you can inspect the generated YAML without rewriting files.summary and tags. Use tags as a string or array.responseCode explicitly for non-200 success responses, especially 201 for create endpoints.additionalResponses for route-specific extra statuses or inferred-error overrides. Values may be null, plain strings, Response instances, or Response class strings.deprecated: true for deprecated endpoints.multipart: true when the endpoint is multipart even if no field uses the file type.description yet. The attribute accepts it, but the generator does not emit it currently.references/inspec-annotation-reference.md before writing non-trivial request or response bodies.name[?][!]:type[,typeArg...][|modifier:arg[,arg...]].? and ! change meaning by context:
request, response, and paginator meta objects, ? means optional and ! means non-nullable.route parameters, ? controls requiredness. Path parameters are usually not optional.query parameters, ! controls requiredness.#[Schema(...)] objects, ? makes the field nullable; Inspec does not currently emit a required array for schema objects.array,<itemType> for primitive arrays, or use 'data:array' => UserTransformer::class for arrays of transformer-backed objects.|enum:a,b,c or |enum:App\\Enums\\BackedEnum.file for uploads; it becomes type: string with format: binary.'@description' => '...' as the first key to give the object a description. Do not leave nested objects without a description.#[Schema(object: [...])] on the transformer's transform() method.Transformer; override with name: only when needed.include* methods are considered for expands. Other methods (transform, helpers, etc.) are skipped.snake_case after stripping include: includeTeam() → team, includeCoAuthors() → co_authors.#[Schema(...)]; keep schema entries written directly in the attribute.type: object with a nested data property:
#[ExpandItem(Transformer::class)] — data is a $ref to the transformer schema.#[ExpandItem([A::class, B::class])] — data is an allOf list of $ref entries.#[ExpandCollection(Transformer::class)] — data is a type: array whose items is a $ref to the transformer schema.ExpandCollection only accepts a single transformer class. Use ExpandItem([...]) for multi-transformer unions.#/components/schemas/ entries.Api enables Sanctum and broadcasting integrations by default. Use withoutSanctum() or withoutBroadcasting() when the generated spec should opt out.auth:sanctum automatically receive bearerAuth; do not model that in the attribute.withBroadcasting(fn (Operation $operation, Route $route) => ...) can customize those auto-documented broadcasting operations or return null to skip one.422 validation response unless additionalResponses[422] or API-level error-response configuration overrides it.throttle middleware automatically add a 429 response unless additionalResponses[429] or API-level error-response configuration overrides it.Api::withValidationErrorResponse(), Api::withoutValidationErrorResponse(), Api::withTooManyRequestsResponse(), and Api::withoutTooManyRequestsResponse().response: [...]. Use Api::withSuccessResponse() when that payload should be wrapped or when the default success description, headers, or content type should change API-wide.paginatedResponse and cursorPaginatedResponse currently work with transformer class strings, not inline object arrays.Api::withPagination() and Api::withCursorPagination().required arrays yet, so keep the DSL truthful to app behavior but expect that limitation.Api::prefix('api') when Laravel routes live under /api but generated paths should omit that prefix.prefix(...), match generated paths in --path filters, for example ^/users instead of ^/api/users.Use references/inspec-annotation-reference.md for the full #[Route] argument guide, DSL syntax, context-specific marker semantics, transformer patterns, and current caveats.
php artisan inspec:generate --api=App\\OpenApi\\WebhookDocumentation --stdoutphp artisan inspec:generate --api=webhooks --stdout --path='^/webhooks' --method=POSTphp artisan inspec:generate --api=webhooks --stdout --route=webhooks.receive