Skip to content

API Keys ​

Generate, list, and revoke creator API keys for external integrations.

Base URLs:

  • Production: https://fangate.info/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.

Where to create a key. Creators create, list and revoke keys in the Fangate dashboard under Settings → API keys (app.fangate.info): pick the permissions, the key is shown once with a copy button, and the list shows last_used_at and a revoke button. No password has to leave the app for that. The POST /api/user/api-keys route below does the same for tools that manage keys programmatically - it takes the creator's login token, never a generated key. Agency accounts do not have this page: they operate the creator accounts they are connected to and create keys there.


Scope matrix ​

Fixed behavior:

  • get_existing_urls -> always ON
  • get_existing_collection_urls -> always ON
  • view_account_settings -> always OFF (hard blocked)
  • create_new_urls -> toggle
  • view_transactions -> toggle
  • manage_webhooks -> toggle
  • upload_ai_content -> follows create_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.

EndpointMethodRequired ability
/api/productsGETapi-key:urls.read
/api/products/collectionGETapi-key:collection-urls.read
/api/products/{product}GETapi-key:urls.read
/api/products/{product}/consent-creator-tagsGETapi-key:urls.read
/api/products/{product}/telegram-cardGETapi-key:urls.read
/api/productsPOSTapi-key:urls.write (new file: ai_origin required for keys with upload_ai_content)
/api/products/{product}PATCH / DELETEapi-key:urls.write
/api/products/{product}/price, /folderPATCHapi-key:urls.write
/api/products/{product}/price-links, /collection, /thumbnail, /trailer, /mediaPOSTapi-key:urls.write
/api/products/{product}/thumbnail, /trailer, /media/{media}DELETEapi-key:urls.write
/api/products/media/{media}DELETEapi-key:urls.write
/api/mediaGETapi-key:urls.read
/api/media/{media}, /api/media/{media}/consent-tagsGETapi-key:urls.read
/api/media, /api/media/bulk, /api/media/{media}/consent-tagsPOSTapi-key:urls.write (POST /api/media: ai_origin required for keys with upload_ai_content)
/api/media/{media}, /api/media/{media}/ai-originPATCHapi-key:urls.write
/api/media/{media}DELETEapi-key:urls.write
/api/upload-sessions*GET/POST/DELETEapi-key:urls.write
/api/content-folders*GETapi-key:urls.read
/api/content-folders*POST/PATCH/DELETEapi-key:urls.write
/api/wallet, /api/wallet/affiliate, /api/dashboard/summaryGETapi-key:transactions.read
/api/analytics/sales-by-country, /api/analytics/top-buyersGETapi-key:transactions.read
/api/consent-tags, /api/consent-tag-relationships, /api/consent-tag-permissionsGETapi-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}/rescindPATCHapi-key:urls.write (accepting, declining or rescinding is a declaration in the creator's name)
/api/consent-tag-permissions/{ownerUserId}PATCHapi-key:urls.write
/api/creators/searchGETapi-key:urls.write
/api/consents/store-or-sendPOSTapi-key:urls.write
/api/veriff/decisionPOSTany key (api-key:urls.read; a read_only key cannot, it may not POST) - see Verification
/api/veriff/createGETapi-key:urls.write, and only after a final negative verdict - see Verification
/api/moderation/checkPOSTapi-key:urls.write (word-filter pre-check of title and public_description - the filter every product create and update runs; no images or videos)
/api/webhooks, /api/webhooks/{id}, /api/webhooks/{id}/secretGET/POST/PATCH/DELETEapi-key:webhooks.manage

Any other route returns 403 with errors_code: api_key_endpoint_not_allowed ("This API key cannot access this endpoint."); a whitelisted route without the ability returns 403 with errors_code: api_key_permission_missing ("This API key does not have permission for this action."). Branch on the code - see Error codes.

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). 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:

EndpointPer token/user + IPPer IP
POST /api/user/api-keys10/min30/min
GET /api/user/api-keys30/min60/min
DELETE /api/user/api-keys/{tokenId}30/min60/min

GET /api/user/api-keys ​

List generated API keys for the authenticated creator.

  • Auth required: Yes

Example response ​

json
{
  "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"
      ],
      "read_only": false,
      "account_keys": null,
      "created_by_agency": null
    }
  ]
}

read_only is true for a key created with read_only. account_keys is the list of accounts an agency key is held to, or null when it reaches every account (always null on a creator account).

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:

FieldTypeNotes
created_by_agencyobject or nullnull for keys you created yourself
created_by_agency.idintegerAgency id
created_by_agency.namestringAgency trading name, or legal name if none
created_by_agency.link_idintegerThe agency relationship the key belongs to
created_by_agency.link_activebooleanfalse 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 ​

FieldTypeRequiredNotes
namestringYesLabel used for token name prefix fangate-api-key:
can_create_new_urlsbooleanNoEnables api-key:urls.write and api-key:ai.write (the key must classify every new file, see AI content)
can_view_transactionsbooleanNoEnables api-key:transactions.read
can_manage_webhooksbooleanNoEnables api-key:webhooks.manage
can_manage_ai_modelsbooleanNoAgency and creator accounts (ignored on an AI model's own account). Enables api-key:agency.ai-models: list, create, rename and deactivate the account's AI models - an agency's under /api/agencies/me/ai-models, plus its model accounts; a creator's under /api/user/ai-models (since 2026-10-12)
can_access_connected_creatorsbooleanNoAgency accounts only (ignored elsewhere). Enables api-key:agency.creators: work inside connected creators with X-Fangate-Account and invite creators. Without it the key reaches the agency's AI models and model accounts only
read_onlybooleanNoA key that only reads: minted with api-key:read-only and without any write ability (can_create_new_urls and can_manage_webhooks are ignored). Every method but GET answers 403 api_key_read_only. See Account-scoped and read-only keys
account_keysarray of strings or nullNoAgency accounts only (ignored elsewhere). Holds the key to these accounts: account_key values from GET /api/agencies/me/accounts (invited or active relationships, max 100). Absent or null: the key reaches every account of the agency, as before. A value that is not one of your relationships answers 422 validation_failed with errors_field: account_keys, and no key is created
expires_in_daysintegerNoOptional explicit expiry

A generated key cannot create, list or revoke keys - use the dashboard (Settings → API keys) or the creator's login token (POST /api/login) for this call.

An agency account holds at most 100 generated keys at once; the next one answers 422 api_key_limit_reached. Revoked and expired keys do not count - revoke one to free its place.

Agencies. An agency creates its key on the agency account and names the account it works in with the X-Fangate-Account header - see Agency accounts. The permissions above say what the key may do inside every account it reaches.

Creators with AI models (since 2026-10-12). A creator's key names one of the creator's own AI models the same way: X-Fangate-Account: aim_<id>, the account_key from GET /api/user/ai-models. The call then runs as the model, within the key's permissions.

E-mail addresses. A generated key is handed no e-mail address of a third person: email is null in GET /api/creators/search, in the tagged and tagging person of the consent reads (GET /api/media/{media}/consent-tags, GET /api/products/{product}/consent-creator-tags, GET /api/consent-tags) and for the Fangate staff named there, and no display name falls back to an address. Searching by a full address still finds the account. invited_email stays - the account entered it itself.

Example request ​

bash
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 ​

json
{
  "success": true,
  "errors_message": null,
  "data": {
    "token": "1|plain-text-token",
    "name": "fangate-api-key:zapier",
    "expires_at": "2026-07-24T08:00:00Z",
    "read_only": false,
    "account_keys": null,
    "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.


Account-scoped and read-only keys ​

Since 2026-09-23 an agency can hand a partner a key that reaches some of its accounts instead of all of them, and any account can create a key that only reads. Both are decided when the key is created; the account list can be changed later.

Account list (account_keys). The key works only in the listed accounts:

  • X-Fangate-Account naming an account off the list answers 404 agency_account_not_found - exactly like an account the agency does not run.
  • GET /api/agencies/me/accounts and GET /api/agencies/me/ai-models list the key's accounts only; PATCH/DELETE on an AI model off the list answer 404.
  • An AI model or model account the key creates, and a creator it invites, are added to its list automatically.
  • The agency's own money views add up every account, listed or not: GET /api/wallet, GET /api/wallet/affiliate, GET /api/dashboard/summary and GET /api/analytics/* answer 403 api_key_scope_requires_account unless the key names one of its accounts with X-Fangate-Account - the account's own wallet is fine.
  • Agency webhooks: a scoped key registers one only with an account_keys list inside its own list (Agency-wide webhooks); it sees, changes, removes, redelivers and rotates only those. A webhook without a list hears every account of its scopes and is closed to the key (422 on register, 403 api_key_scope_requires_account otherwise). Or register the webhook on the account itself, with the header.
  • PATCH replaces the list with the accounts you name. Invitations the key holds to an address that has not registered yet have no account_key, so they cannot be named - they stay on the list; withdrawing the invitation removes them. A declined invitation leaves every list.
  • When a relationship ends, the account drops out of every key's list. A key whose list ran empty reaches no account until the list is changed.
  • Taking accounts off a key's list takes them off the webhooks that key registered: they drop out of its agency webhooks (a webhook left with no account is switched off; one without a list keeps to the key's new list), and webhooks it registered inside a removed account are switched off. Ended accounts stay on a webhook's list, so a refund of an earlier sale still arrives.
  • A key created without account_keys reaches every account of the agency, as every key did before this date.

Read-only (read_only: true). The key carries api-key:read-only and no write ability. Every method but GET answers 403 api_key_read_only, on every route - including inviting creators and registering webhooks. What it may read is still decided by the other permissions (can_view_transactions for wallet and analytics, can_access_connected_creators for reaching connected creators) and by its account list.


PATCH /api/user/api-keys/ ​

Change the account list of an agency key. Agency accounts only; like every call on this page it takes a login token, never a generated key.

  • Auth required: Yes
  • Content type: application/json
FieldTypeRequiredNotes
account_keysarray of strings or nullYesThe new list (1-100 account_key values of invited or active relationships), or null to let the key reach every account again
json
{
  "success": true,
  "errors_message": null,
  "data": {
    "id": 14,
    "account_keys": ["conn_418_90211", "conn_419_90212"]
  }
}

404 for a key that is not yours or not a generated key; 403 on a creator account; 422 validation_failed (errors_field: account_keys) for a value that is not one of your relationships - the list is then left unchanged.


DELETE /api/user/api-keys/ ​

Revoke a generated API key by token id. For a key of an agency account, and for a key an agency created on your account, the webhooks the key registered are switched off with it (is_active: false), not deleted: they stay listed under GET /api/webhooks, where you can switch one back on or remove it. A creator's own key takes nothing with it - its webhooks keep running. A delivery that was queued before a webhook was switched off is not sent; it can be sent again once the webhook is back on.

  • Auth required: Yes

Example response ​

json
{
  "success": true,
  "errors_message": null,
  "data": "API key revoked"
}

Security notes ​

  • Keep the key on your server. A key placed in browser or app code can be read by every user of your application; only presigned upload URLs belong in a browser (see Upload sessions).
  • API key plaintext is returned once on creation only.
  • Hashed storage + one-time display is considered acceptable for current phase.
  • last_used_at from 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.

Fangate backend developer documentation