API Mode
API Mode
Section titled “API Mode”Laravel AutoCrud can expose the same CRUD engine through two independent interfaces:
- Web/Inertia interface: enabled by default and used by the published Vue/Inertia components.
- JSON API interface: optional and intended for mobile apps, SPAs, admin panels, or any external frontend.
Both interfaces share the same internal services, validation rules, model metadata, relationships, custom fields, file handling, forbidden actions, records, and events.
Enabling API Mode
Section titled “Enabling API Mode”Publish the package config if you have not done it yet:
php artisan vendor:publish --tag=laravel-auto-crud-config --forceThen enable the API routes in config/laravel-auto-crud.php:
return [ 'timezone' => 'Atlantic/Canary',
'web' => [ 'enabled' => true, 'prefix' => 'laravel-auto-crud', 'middleware' => ['web'], 'protected_middleware' => ['auth', 'checkForbiddenActions'], ],
'api' => [ 'enabled' => true, 'prefix' => 'api/laravel-auto-crud', 'middleware' => ['forceJsonResponse', 'api', 'auth:sanctum', 'checkForbiddenActions'], 'public_middleware' => null, ],];After changing package config in a cached application, refresh Laravel’s cache:
php artisan config:clearphp artisan route:clearConfiguration Reference
Section titled “Configuration Reference”| Option | Default | Description |
|---|---|---|
api.enabled | false | Enables or disables API routes. |
api.prefix | api/laravel-auto-crud | Prefix for all API endpoints. |
api.middleware | ['forceJsonResponse', 'api', 'auth:sanctum', 'checkForbiddenActions'] | Middleware used by protected API endpoints. |
api.public_middleware | null | Middleware used by public file/image endpoints. When null, it is derived from api.middleware without auth and forbidden-action middleware. |
The forceJsonResponse middleware sets Accept: application/json on API requests before Laravel handles validation or authentication. This prevents HTML redirects for validation failures or unauthenticated requests.
Authentication
Section titled “Authentication”The default API middleware uses auth:sanctum. This is a safe default for external frontends, but you can replace it:
'api' => [ 'enabled' => true, 'prefix' => 'api/laravel-auto-crud', 'middleware' => ['forceJsonResponse', 'api', 'auth:api', 'checkForbiddenActions'],],For a token-based client, send the bearer token with every protected request:
Authorization: Bearer <token>Accept: application/jsonThe package still forces JSON through middleware, but external clients should send Accept: application/json explicitly.
Model Names
Section titled “Model Names”The {model} route parameter is resolved with Str::studly() against App\Models.
| URL parameter | Resolved model |
|---|---|
product | App\Models\Product |
user_profile | App\Models\UserProfile |
reservation_vehicle | App\Models\ReservationVehicle |
Response Format
Section titled “Response Format”Successful API responses use this shape:
{ "success": true, "message": "Elemento creado.", "data": {}, "meta": {}}message and meta are included only when relevant.
Error responses use this shape when generated by the package:
{ "success": false, "message": "No tienes permiso para realizar esta acción.", "errors": {}}Laravel validation errors keep Laravel’s standard JSON validation format unless your application customizes the exception handler.
Schema Endpoint
Section titled “Schema Endpoint”External frontends should start by loading the schema for each model:
GET /api/laravel-auto-crud/{model}/schemaExample:
GET /api/laravel-auto-crud/product/schemaResponse:
{ "success": true, "data": { "endPoint": "/api/laravel-auto-crud/product", "endPoints": { "web": "/laravel-auto-crud/product", "api": "/api/laravel-auto-crud/product" }, "formFields": [], "tableHeaders": [], "externalRelations": [], "forbiddenActions": [], "calendarFields": [], "customFieldsEnabled": false }}Use formFields to render forms, tableHeaders to render tables, externalRelations to render related resources, and endPoint for subsequent API calls.
CRUD Endpoints
Section titled “CRUD Endpoints”| Method | Endpoint | Description |
|---|---|---|
GET | /{model}/schema | Returns model metadata for external frontends. |
POST | /{model}/load-items | Returns paginated table data. |
GET | /{model}/all | Returns all records with includes. |
GET | /{model}/{id} | Returns one record with includes and custom fields. |
POST | /{model} | Creates a record. |
PUT | /{model}/{id} | Updates a record. |
PATCH | /{model}/{id} | Updates a record. |
POST | /{model}/{id} | Updates a record, useful for multipart/form-data with _method. |
DELETE | /{model}/{id} | Soft deletes a record. |
POST | /{model}/{id}/destroy | Soft deletes a record, compatibility alternative. |
POST | /{model}/{id}/restore | Restores a soft-deleted record. |
DELETE | /{model}/{id}/force | Permanently deletes a soft-deleted record. |
POST | /{model}/{id}/permanent | Permanently deletes a soft-deleted record, compatibility alternative. |
GET | /{model}/export-excel | Returns all model items in the existing export payload. |
All endpoints in this table are relative to the configured API prefix. With the default prefix, /{model}/schema becomes /api/laravel-auto-crud/{model}/schema.
Listing Records
Section titled “Listing Records”The API uses the same server-side table engine as the Inertia components.
POST /api/laravel-auto-crud/product/load-itemsContent-Type: application/jsonPayload:
{ "page": 1, "itemsPerPage": 10, "sortBy": "[{\"key\":\"name\",\"order\":\"asc\"}]", "search": "{\"name\":\"chair\"}", "exactFilters": "{\"category_id\":2}", "deleted": false}Response:
{ "success": true, "data": { "items": [], "itemsLength": 0, "itemsPerPage": 10, "page": 1, "sortBy": [], "search": {}, "deleted": false }, "meta": { "schema": {} }}Notes:
sortBy,search, andexactFiltersare JSON-encoded strings for compatibility with the existing table engine.- Set
itemsPerPageto-1to request all matching rows. - Set
deletedtotrueto load soft-deleted rows when the model usesSoftDeletes.
Creating Records
Section titled “Creating Records”POST /api/laravel-auto-crud/productContent-Type: application/jsonPayload:
{ "name": "Chair", "price": 49, "is_active": true}Response:
{ "success": true, "message": "Elemento creado.", "data": { "id": 1, "name": "Chair", "price": "49", "is_active": true }}The same DynamicFormRequest rules used by the web interface are applied to API create requests.
Updating Records
Section titled “Updating Records”PUT /api/laravel-auto-crud/product/1Content-Type: application/jsonPayload:
{ "name": "Office chair", "price": 59, "is_active": true}For file uploads, use POST with _method=PUT and multipart/form-data:
POST /api/laravel-auto-crud/product/1Content-Type: multipart/form-dataForm fields:
_method=PUTname=Office chairimage=<binary file>Password fields are ignored during update when they are empty, matching the web behavior.
Files and Images
Section titled “Files and Images”AutoCrud supports public and private files/images defined in model fields.
| Method | Endpoint | Description |
|---|---|---|
GET | /public/images/{model}/{field}/{id} | Serves a public image. |
GET | /public/files/{model}/{field}/{id} | Serves a public file. |
GET | /private/images/{model}/{field}/{id} | Serves a private image through protected API middleware. |
GET | /private/files/{model}/{field}/{id} | Serves a private file through protected API middleware. |
These endpoints are relative to api.prefix. With the default prefix, public images are served from /api/laravel-auto-crud/public/images/{model}/{field}/{id}.
By default, public file/image endpoints use api.public_middleware. If it is null, the package derives it from api.middleware by removing auth, auth:sanctum, and checkForbiddenActions.
If you use a custom auth middleware such as auth:api, set api.public_middleware explicitly so public file/image endpoints do not require authentication unless that is your intention.
Autocomplete
Section titled “Autocomplete”Server-side autocomplete:
POST /api/laravel-auto-crud/{model}/load-autocomplete-itemsContent-Type: application/jsonPayload:
{ "search": "john", "key": "user_id"}Response:
{ "success": true, "data": []}Load all related options:
GET /api/laravel-auto-crud/{model}/allCalendar Events
Section titled “Calendar Events”POST /api/laravel-auto-crud/{model}/load-calendar-eventsContent-Type: application/jsonPayload:
{ "start": "2026-01-01", "end": "2026-01-31"}Response:
{ "success": true, "data": { "items": [] }}The model must define $calendarFields for useful calendar output.
External Relations
Section titled “External Relations”AutoCrud exposes relation actions for external relations declared in $externalRelations.
| Method | Endpoint | Description |
|---|---|---|
POST | /{model}/{id}/bind/{externalRelation}/{item} | Attaches an item to a relation. |
PUT | /{model}/{id}/pivot/{externalRelation}/{item} | Updates pivot fields. |
PATCH | /{model}/{id}/pivot/{externalRelation}/{item} | Updates pivot fields. |
POST | /{model}/{id}/pivot/{externalRelation}/{item} | Updates pivot fields, compatibility alternative. |
DELETE | /{model}/{id}/unbind/{externalRelation}/{item} | Detaches an item from a relation. |
POST | /{model}/{id}/unbind/{externalRelation}/{item} | Detaches an item from a relation, compatibility alternative. |
Bind example:
POST /api/laravel-auto-crud/reservation/1/bind/vehicles/5Content-Type: application/jsonPayload with pivot fields:
{ "driver": true, "notes": "Primary vehicle"}Pivot fields are validated with the same rules defined in the relation metadata.
Custom Fields API
Section titled “Custom Fields API”Custom fields can be managed through API endpoints when your model has custom fields enabled.
| Method | Endpoint | Description |
|---|---|---|
GET | /custom-fields-types | Returns available custom field types. |
GET | /custom-fields/{model} | Lists custom field definitions for a model. |
POST | /custom-fields/{model} | Creates a custom field definition. |
PUT | /custom-fields/{model}/{id} | Updates a custom field definition. |
PATCH | /custom-fields/{model}/{id} | Updates a custom field definition. |
DELETE | /custom-fields/{model}/{id} | Deletes a custom field definition. |
POST | /custom-fields/{model}/{id}/destroy | Deletes a custom field definition, compatibility alternative. |
POST | /custom-fields/{model}/reorder | Reorders custom field definitions. |
Custom field update, destroy, and reorder operations are scoped to the model in the URL. An ID from another model will not be accepted.
Create example:
POST /api/laravel-auto-crud/custom-fields/productContent-Type: application/jsonPayload:
{ "label": "Internal Code", "name": "internal_code", "type": "string", "show_in_table": true, "is_active": true}Reorder example:
POST /api/laravel-auto-crud/custom-fields/product/reorderContent-Type: application/jsonPayload:
{ "order": [3, 1, 2]}Forbidden Actions
Section titled “Forbidden Actions”The API uses the same checkForbiddenActions middleware as the web interface. Forbidden API actions return JSON:
{ "success": false, "message": "No tienes permiso para realizar esta acción."}The HTTP status code is 403.
Endpoint Generation in Models
Section titled “Endpoint Generation in Models”The AutoCrud trait now supports endpoint context.
Product::getEndpoint(); // "/laravel-auto-crud/product"Product::getEndpoint(null, 'web'); // "/laravel-auto-crud/product"Product::getEndpoint(null, 'api'); // "/api/laravel-auto-crud/product"
Product::getEndpoints();// [// 'web' => '/laravel-auto-crud/product',// 'api' => '/api/laravel-auto-crud/product',// ]
Product::getModel([], 'api');When the schema endpoint is requested through API, relation endpoints inside formFields and externalRelations are generated with the API prefix.
Recommended External Frontend Flow
Section titled “Recommended External Frontend Flow”- Authenticate the user and store the token or session according to your auth driver.
- Fetch
GET /api/laravel-auto-crud/{model}/schemafor each AutoCrud model used by the frontend. - Render forms from
formFieldsand tables fromtableHeaders. - Use
POST /{model}/load-itemsfor paginated tables. - Use
POST /{model}andPUT /{model}/{id}for mutations. - Use relation endpoints from the schema instead of hardcoding related model URLs.
- Handle
422,401,403, and404as JSON responses.
Using The Published Vue Components Without Inertia
Section titled “Using The Published Vue Components Without Inertia”The published Vue components can run against either Inertia or the JSON API through an adapter plugin.
In an external Vue/Vuetify frontend, install the API adapter once when bootstrapping the app:
import axios from "axios"import { createApp } from "vue"import { createApiAutoCrudAdapter, createAutoCrudPlugin,} from "./Adapters/LaravelAutoCrud"
const app = createApp(App)
app.use( createAutoCrudPlugin({ adapter: createApiAutoCrudAdapter({ baseUrl: "/api/laravel-auto-crud", axios, getAuthUser: () => auth.user, }), }),)Then load the schema and pass it to the same components used by Inertia apps:
<script setup>import { onMounted, ref } from "vue"import AutoTable from "./Components/LaravelAutoCrud/AutoTable.vue"import { useAutoCrud } from "./Adapters/LaravelAutoCrud"
const autoCrud = useAutoCrud()const model = ref(null)
onMounted(async () => { model.value = await autoCrud.loadSchema("product")})</script>
<template> <auto-table v-if="model" title="Products" :model="model" /></template>For existing Inertia apps, install the Inertia adapter:
import { createAutoCrudPlugin, createInertiaAutoCrudAdapter,} from "./Adapters/LaravelAutoCrud"
app.use( createAutoCrudPlugin({ adapter: createInertiaAutoCrudAdapter(), }),)Components no longer import @inertiajs/vue3 directly. Only inertiaAdapter.js depends on Inertia, so external frontends can use apiAdapter.js without installing Inertia.
Compatibility Notes
Section titled “Compatibility Notes”- API mode is disabled by default, so existing Inertia installations keep their current behavior.
- Web and API routes can use different prefixes and middleware stacks.
- The published Vue components require an AutoCrud adapter plugin. Use
createInertiaAutoCrudAdapter()for Inertia apps andcreateApiAutoCrudAdapter()for external frontends. - The API is designed for external frontends; it does not require Inertia.
- File updates with
multipart/form-datashould usePOSTplus_method=PUTfor maximum compatibility.