API Keys
Generate, list, and revoke creator API keys for external integrations.
Base URLs:
- Production:
https://fangate.info/api - Development:
https://fangate.co/api
Overview
Current scope includes only:
- create key
- list keys
- revoke key
Not included for now:
- rotate key
- rename key
- expiry scheduler/cleanup job
Authentication uses bearer tokens:
Authorization: Bearer <api_key>
Generated keys are stored hashed by Sanctum and the plaintext token is shown only once at create time.
Scope matrix
Fixed behavior:
get_existing_urls-> always ONget_existing_collection_urls-> always ONview_account_settings-> always OFF (hard blocked)create_new_urls-> toggleview_transactions-> togglemanage_webhooks-> toggleupload_ai_content-> followscreate_new_urls, not a separate toggle: every key that can create content also has to classify every new file it uploads (ai_origin, see AI content). Keys created before this rule do not carry the ability until the announced cut-over.
Endpoint permission matrix
Generated API keys are whitelist-only. Abilities: urls.read and collection-urls.read are always on; urls.write = create_new_urls; transactions.read = view_transactions; webhooks.manage = manage_webhooks.
| Endpoint | Method | Required ability |
|---|---|---|
/api/products | GET | api-key:urls.read |
/api/products/collection | GET | api-key:collection-urls.read |
/api/products/{product} | GET | api-key:urls.read |
/api/products/{product}/consent-creator-tags | GET | api-key:urls.read |
/api/products | POST | api-key:urls.write (new file: ai_origin required for keys with upload_ai_content) |
/api/products/{product} | PATCH / DELETE | api-key:urls.write |
/api/products/{product}/price, /folder | PATCH | api-key:urls.write |
/api/products/{product}/price-links, /collection, /thumbnail, /trailer, /media | POST | api-key:urls.write |
/api/products/{product}/thumbnail, /trailer, /media/{media} | DELETE | api-key:urls.write |
/api/products/media/{media} | DELETE | api-key:urls.write |
/api/media | GET | api-key:urls.read |
/api/media/{media}, /api/media/{media}/consent-tags | GET | api-key:urls.read |
/api/media, /api/media/bulk, /api/media/{media}/consent-tags | POST | api-key:urls.write (POST /api/media: ai_origin required for keys with upload_ai_content) |
/api/media/{media}, /api/media/{media}/ai-origin | PATCH | api-key:urls.write |
/api/media/{media} | DELETE | api-key:urls.write |
/api/upload-sessions* | GET/POST/DELETE | api-key:urls.write |
/api/content-folders* | GET | api-key:urls.read |
/api/content-folders* | POST/PATCH/DELETE | api-key:urls.write |
/api/wallet, /api/wallet/affiliate, /api/dashboard/summary | GET | api-key:transactions.read |
/api/analytics/sales-by-country, /api/analytics/top-buyers | GET | api-key:transactions.read |
/api/consent-tags, /api/consent-tag-relationships, /api/consent-tag-permissions | GET | api-key:urls.read (the relationship lists withhold other creators' email unless ?q= names 4+ characters of their address, name or stage name, see Consents) |
/api/consent-tags/{consentCreatorTag}, /api/consent-tags/{consentCreatorTag}/rescind | PATCH | api-key:urls.write (accepting, declining or rescinding is a declaration in the creator's name) |
/api/consent-tag-permissions/{ownerUserId} | PATCH | api-key:urls.write |
/api/creators/search | GET | api-key:urls.write |
/api/consents/store-or-send | POST | api-key:urls.write |
/api/webhooks, /api/webhooks/{id} | GET/POST/PATCH/DELETE | api-key:webhooks.manage |
Any other route returns 403 with errors_message: "This API key cannot access this endpoint."; a whitelisted route without the ability returns 403 with "This API key does not have permission for this action.".
Deliberately closed for keys. Account settings answer 403 with "Account settings are not available for generated API keys.": everything under /api/user - profile, password, sessions, linked accounts, Telegram, personal-message settings, fan messages, push tokens and key management itself (/api/user/api-keys) - plus video chat. Not on the whitelist, 403 with "This API key cannot access this endpoint.": payouts (/api/wallet/cashout), the analytics CSV export and PDF report (they carry buyer email addresses), the affiliate endpoints, the collection profile routes (/api/collection/profile* - the collection list GET /api/products/collection is open) and the text pre-check POST /api/moderation/check (the same word filter runs on every product create and update anyway). Keys are created and revoked with a creator login token only.
Rate limits
API key management endpoints use combined limits:
- Per token (fallback user) + IP
- Per IP guardrail
Current limits:
| Endpoint | Per token/user + IP | Per IP |
|---|---|---|
POST /api/user/api-keys | 10/min | 30/min |
GET /api/user/api-keys | 30/min | 60/min |
DELETE /api/user/api-keys/{tokenId} | 30/min | 60/min |
GET /api/user/api-keys
List generated API keys for the authenticated creator.
- Auth required: Yes
Example response
{
"success": true,
"errors_message": null,
"data": [
{
"id": 14,
"name": "fangate-api-key:zapier",
"last_used_at": "2026-04-25T08:30:00Z",
"expires_at": null,
"created_at": "2026-04-25T08:00:00Z",
"abilities": [
"api-key:urls.read",
"api-key:collection-urls.read",
"api-key:urls.write",
"api-key:ai.write"
],
"created_by_agency": null
}
]
}Keys created by an agency
An agency that operates your account (agency accounts, since 2026-09) can create API keys on it. Such keys are labelled so you can tell them from your own:
| Field | Type | Notes |
|---|---|---|
created_by_agency | object or null | null for keys you created yourself |
created_by_agency.id | integer | Agency id |
created_by_agency.name | string | Agency trading name, or legal name if none |
created_by_agency.link_id | integer | The agency relationship the key belongs to |
created_by_agency.link_active | boolean | false once the relationship has ended |
When the agency relationship ends (by you, the agency, or Fangate), every key the agency created on your account is deleted immediately. Your own keys are not affected. The revocation appears in your agency activity log.
POST /api/user/api-keys
Create a generated API key.
- Auth required: Yes
- Content type:
application/json
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
name | string | Yes | Label used for token name prefix fangate-api-key: |
can_create_new_urls | boolean | No | Enables api-key:urls.write and api-key:ai.write (the key must classify every new file, see AI content) |
can_view_transactions | boolean | No | Enables api-key:transactions.read |
can_manage_webhooks | boolean | No | Enables api-key:webhooks.manage |
expires_in_days | integer | No | Optional explicit expiry |
A generated key cannot create, list or revoke keys - use the creator's login token (POST /api/login) for this call.
Example request
curl -X POST https://fangate.info/api/user/api-keys \
-H "Authorization: Bearer <creator-token>" \
-H "Content-Type: application/json" \
-d '{
"name": "zapier",
"can_create_new_urls": true,
"can_view_transactions": false,
"expires_in_days": 90
}'Example response
{
"success": true,
"errors_message": null,
"data": {
"token": "1|plain-text-token",
"name": "fangate-api-key:zapier",
"expires_at": "2026-07-24T08:00:00Z",
"permissions": {
"get_existing_urls": true,
"get_existing_collection_urls": true,
"create_new_urls": true,
"view_transactions": false,
"manage_webhooks": false,
"upload_ai_content": true,
"view_account_settings": false
}
}
}upload_ai_content mirrors create_new_urls. In the key list, such keys carry api-key:ai.write in abilities (as in the example above); keys created before the AI release do not, until a cut-over date that will be announced in the changelog.
DELETE /api/user/api-keys/
Revoke a generated API key by token id.
- Auth required: Yes
Example response
{
"success": true,
"errors_message": null,
"data": "API key revoked"
}Security notes
- API key plaintext is returned once on creation only.
- Hashed storage + one-time display is considered acceptable for current phase.
last_used_atfrom Sanctum is used as minimal audit trail for now.- Single auth format is used for API keys:
Authorization: Bearer <api_key>. - No key-expiry scheduler is configured for now.