Overview
The Content API is an optional first-party panel plugin that exposes a JSON write surface (/api/v1) for the Filament resources on a panel. It is not part of the published template; an operator adds it only when a script, agent, or third party needs to push content in over HTTP. The same model policies that gate the panel gate the API.
Install
composer require mamenein/filament-content-api
php artisan filament-content-api:install
The install command runs migrations and prints the panel snippet. Add it to the panel provider:
->plugin(\Mamenein\FilamentContentApi\FilamentContentApiPlugin::make())
No second registration call is needed for normal resources.
Authentication
Three Bearer paths, in order:
- Hashed panel key — minted on the API settings page. Plaintext is
agk_…, shown once; only the SHA-256 hash is stored. Per-key abilities scope what the key may do. - Passport personal-access token — resolved by the
apiguard. Unscoped at the key layer; the model policy still applies. - Env
API_KEY— a shared secret in.env, matched withhash_equals. Acts as the configuredcontent-api.key_user.
Key abilities and panel policies both apply. A key with posts:create still 403s if the user's policy forbids creating.
Discovery
At boot the plugin reads $panel->getResources(). Each resource's model gains:
- abilities
{prefix}:create|read|update|deletefor API keys, - REST routes at
/api/v1/{prefix}(index, store, show, update, destroy), - webhook events
{singular}.created,.updated,.deleted, plus.publishedwhen the model has apublished_atconcern.
Add a Post resource → Posts show up on keys, REST, and webhooks. Add Orders later → Orders appear. No per-model REST controller to copy.
Opt-out is built in: UserResource, RoleResource, MediaResource, and any Authenticatable model are skipped by default. A resource can return false from shouldRegisterWithContentApi(), or the panel can pass ->except([SomeResource::class]). ContentApi::resource($model, $prefix) is only for a model that has no Filament resource of its own.
Flow
sequenceDiagram
participant Op as Operator
participant Key as API key (agk_…)
participant API as /api/v1
participant Policy as Model policy
participant Model as Resource CRUD
participant Hook as Webhook
participant Log as Delivery log
Op->>Key: Mints key with abilities
Op->>API: Bearer request
API->>Key: Verify hash + ability
API->>Policy: Gate::authorize
Policy->>Model: Allowed CRUD
Model->>Hook: {singular}.created/updated/deleted
Hook->>Log: Signed POST + attempt row