75f75d8d19
BREAKING CHANGE: API authentication is now always required. The PINCHFLAT_API_TOKEN env var is no longer used. Instead, tokens are stored in the database and managed via Settings → API Access. Changes: - Add api_token column to settings table (migration) - ApiAuthPlug reads from DB; returns 401 if no token configured - Add API Access section to Settings page with generate/regenerate/revoke - Add POST /settings/generate_api_token and /settings/revoke_api_token - Remove api_token from config.exs and runtime.exs - Update all API controller tests to set auth token in setup - Update auth plug tests for mandatory authentication - 1008 tests pass, zero warnings
4.5 KiB
4.5 KiB
Pinchflat API
This fork adds a JSON REST API to Pinchflat for programmatic access, enabling MCP server integration and other automation use cases.
API Authentication
The API always requires a Bearer token — there is no open-access mode. Generate a token from the web UI under Settings → API Access:
- Navigate to Settings
- Click "Generate API Token"
- Copy the token (it won't be shown in full again)
Clients must send the token in the Authorization header:
Authorization: Bearer *** to regenerate or revoke the token at any time.
API Endpoints
All endpoints are under /api/v1.
Sources
| Method | Path | Description |
|---|---|---|
| GET | /api/v1/sources |
List all sources |
| GET | /api/v1/sources/:id |
Get a source with its pending tasks |
| POST | /api/v1/sources |
Create a new source |
| PUT | /api/v1/sources/:id |
Update a source |
| DELETE | /api/v1/sources/:id |
Delete a source (marks for deletion) |
| POST | /api/v1/sources/:source_id/force_download_pending |
Force download pending media |
| POST | /api/v1/sources/:source_id/force_redownload |
Force re-download existing media |
| POST | /api/v1/sources/:source_id/force_index |
Force re-index |
| POST | /api/v1/sources/:source_id/force_metadata_refresh |
Force metadata refresh |
| POST | /api/v1/sources/:source_id/sync_files_on_disk |
Sync files on disk |
Media Items
| Method | Path | Description |
|---|---|---|
| GET | /api/v1/media |
List all media items (optional ?source_id=X filter) |
| GET | /api/v1/media/search?q=query |
Search media items |
| GET | /api/v1/media/:id |
Get a media item |
| PUT | /api/v1/media/:id |
Update a media item |
| DELETE | /api/v1/media/:id |
Delete media files |
| POST | /api/v1/media/:media_item_id/force_download |
Force download a media item |
Media Profiles
| Method | Path | Description |
|---|---|---|
| GET | /api/v1/media_profiles |
List all media profiles |
| GET | /api/v1/media_profiles/:id |
Get a media profile |
| POST | /api/v1/media_profiles |
Create a media profile |
| PUT | /api/v1/media_profiles/:id |
Update a media profile |
| DELETE | /api/v1/media_profiles/:id |
Delete a media profile |
Settings
| Method | Path | Description |
|---|---|---|
| GET | /api/v1/settings |
Get settings (route_token excluded) |
| PUT | /api/v1/settings |
Update settings |
| GET | /api/v1/app_info |
Get app info (version, environment, etc.) |
Tasks
| Method | Path | Description |
|---|---|---|
| GET | /api/v1/tasks |
List all tasks (optional ?source_id=X filter) |
| GET | /api/v1/tasks/:id |
Get a task |
Response Format
All responses are JSON. Successful responses use:
{"data": ...}
Error responses use:
{ "errors": { "field": "error message" } }
Example: Create a Source
curl -X POST http://localhost:8945/api/v1/sources \
-H "Authorization: Bearer your-token" \
-H "Content-Type: application/json" \
-d '{
"source": {
"media_profile_id": 1,
"collection_type": "channel",
"original_url": "https://www.youtube.com/@SomeChannel"
}
}'