Filament Studio can auto-generate a RESTful API for all your dynamic collections. The API supports full CRUD operations with API key authentication, per-collection permissions, and rate limiting.
Enable the API in your plugin registration:
FilamentStudioPlugin::make()
->enableApi();
Or via environment variables:
STUDIO_API_ENABLED=true
STUDIO_API_PREFIX=api/studio
STUDIO_API_RATE_LIMIT=60
All API requests require an X-Api-Key header:
curl -H "X-Api-Key: your-api-key-here" \
https://your-app.com/api/studio/posts
API keys are managed through the Filament admin panel under Studio > API Settings.
| Property | Description |
|---|---|
name |
Descriptive name for the key |
key |
The API key (shown once at creation, stored as SHA256 hash) |
permissions |
Per-collection action permissions |
is_active |
Whether the key is enabled |
expires_at |
Optional expiration date |
tenant_id |
Tenant scope (optional) |
API keys use granular permissions structured as collection-action pairs:
{
"posts": ["index", "show", "store"],
"products": ["index", "show", "store", "update", "destroy"],
"*": ["index", "show"]
}
The wildcard * grants the specified actions on all collections. Per-collection entries override the wildcard for that collection.
Available actions: index, show, store, update, destroy.
All routes are prefixed with the configured API prefix (default: /api/studio).
GET /api/studio/{collection_slug}
Query Parameters:
| Parameter | Default | Description |
|---|---|---|
per_page |
25 |
Records per page (max 100) |
page |
1 |
Page number |
Response: Paginated collection with metadata.
{
"data": [
{
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"data": {
"title": "My Post",
"status": "published"
},
"created_by": 1,
"updated_by": null,
"created_at": "2025-01-15T10:30:00.000000Z",
"updated_at": "2025-01-15T10:30:00.000000Z"
}
],
"links": { "first": "...", "last": "...", "prev": null, "next": "..." },
"meta": { "current_page": 1, "last_page": 3, "per_page": 25, "total": 72 }
}
GET /api/studio/{collection_slug}/{uuid}
Response:
{
"data": {
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"data": {
"title": "My Post",
"status": "published"
},
"created_by": 1,
"updated_by": null,
"created_at": "2025-01-15T10:30:00.000000Z",
"updated_at": "2025-01-15T10:30:00.000000Z"
}
}
POST /api/studio/{collection_slug}
Request Body:
{
"data": {
"title": "New Post",
"status": "draft",
"priority": 3
}
}
Response: 201 Created with the new record.
Validation:
PUT /api/studio/{collection_slug}/{uuid}
Request Body: Same structure as create. Fields use sometimes validation — only include fields you want to update.
{
"data": {
"status": "published"
}
}
Response: 200 OK with the updated record.
DELETE /api/studio/{collection_slug}/{uuid}
Response: 204 No Content.
If soft deletes are enabled on the collection, the record is soft-deleted rather than permanently removed.
When multilingual content is enabled, all endpoints accept locale selection via query parameter or header.
# Via query parameter
curl -H "X-Api-Key: your-key" \
"https://your-app.com/api/studio/posts?locale=fr"
# Via header
curl -H "X-Api-Key: your-key" \
-H "X-Locale: fr" \
"https://your-app.com/api/studio/posts/550e8400"
The query parameter takes precedence over the header. If neither is provided, the collection's default locale is used.
When a locale is active, responses include a _meta object:
{
"data": { "..." : "..." },
"_meta": {
"locale": "fr",
"fallbacks": ["slug"]
}
}
The fallbacks array lists field names that had no value in the requested locale and fell back to the default locale.
Retrieve all translations in a single request:
GET /api/studio/{collection_slug}/{uuid}?all_locales=true
Translatable fields are returned as nested locale objects:
{
"data": {
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"data": {
"title": {"en": "My Title", "fr": "Mon Titre"},
"price": 29.99
},
"created_by": 1,
"updated_by": null,
"created_at": "2025-01-15T10:30:00.000000Z",
"updated_at": "2025-01-15T10:30:00.000000Z"
}
}
Pass locale when creating or updating records to write values for that locale:
curl -X POST -H "X-Api-Key: your-key" \
-H "Content-Type: application/json" \
"https://your-app.com/api/studio/posts?locale=fr" \
-d '{"data": {"title": "Mon Titre"}}'
API requests are rate-limited per API key (or per IP if no key). The default is 60 requests per minute, configurable via:
// config/filament-studio.php
'api' => [
'rate_limit' => env('STUDIO_API_RATE_LIMIT', 120),
],
When the API is enabled and Scramble is installed, Filament Studio auto-generates OpenAPI documentation with:
X-Api-Key header)locale, X-Locale, all_locales) with enum dropdowns when multilingual is enabled_meta response schemas with locale and fallback information| Status | Description |
|---|---|
401 Unauthorized |
Missing or invalid API key |
403 Forbidden |
API key lacks permission for this collection/action |
404 Not Found |
Collection or record not found |
422 Unprocessable Entity |
Validation errors |
429 Too Many Requests |
Rate limit exceeded |
How can I help you explore Laravel packages today?