Skip to content

Vault for integrations

The vault is the creator's media library: every file the creator has, whether it is part of a product or not. This guide walks a CRM or automation through the whole cycle with a generated API key - list and filter, upload, classify, declare consent, wait for moderation, build products from vault files, and take products apart again - so the creator does not have to open the Fangate dashboard for day-to-day work.

Prerequisites: a generated API key with Manage content (see API Keys). Read-only keys can do the reads on this page, nothing else.


1. List and filter

GET /api/media - paginated, newest first by default. Rate limit: 60 requests per minute per key and IP, plus 120 per minute per IP across all keys behind it (shared with GET /api/media/{media}).

ParameterTypeMeaning
page, limitintegerPagination (limit up to 100).
status[]pending, approved, rejectedModeration state. Scalars work too (status=approved).
media_type[]image, videoKind of file.
consent[]required, pending, providedConsent bucket: required = the owner has to act (nobody tagged yet, or declined, or rescinded); pending = requested, no answer yet; provided = nothing to clear (not_required) or consent given. Read consent.status per file for the exact state.
folder_idintegerVault folder (folders with scope=vault, see Content Folders).
unlinkedbooleanOnly files that belong to no product.
livebooleanApproved by moderation and consent cleared - the files a product can be built from.
standard_only / ai_onlybooleanOnly non-AI files / only AI files.
sortnewest, oldest
searchstringTitle search, up to 120 characters.

The response is a page: data[], total, per_page, current_page, pages_total. Each file carries status, ai_origin, ai_label, is_should_consent, consent { status, required, fulfilled }, product_ids, is_linked, thumbnail, preview, preview_blurred. source (the full-size file) is only returned by GET /api/media/{media}.

live=1 is necessary, not sufficient, for a sale: a product built from live files can still be blocked by a pending manual review, an open price review or a switched-off AI domain. Always read is_accessible and purchase_block_code on the product.


2. Upload into the vault

  1. POST /api/upload-sessions - session_type: device_multipart, file_name, file_size_bytes, mime_type, and the AI answer ai_origin (+ ai_attested for AI values). See AI content for the four values.
  2. Upload the bytes as instructed (initial_upload for single-part, POST /api/upload-sessions/{id}/parts for multipart), then POST /api/upload-sessions/{id}/complete.
  3. Poll GET /api/upload-sessions/{id} until status is ready. Presigned URLs are valid for 15 minutes, a session for 24 hours.
  4. POST /api/media with upload_session_id, optional title, description, folder_id, is_should_consent, and ai_origin / ai_attested if you did not send them on the session.

Several files at once: POST /api/media/bulk opens up to 50 sessions with shared defaults (including defaults.ai_origin and defaults.ai_attested); then run steps 2-4 per session.

The AI answer is mandatory for keys created since the AI release and for all content keys after the announced cut-over: without it, step 4 is refused with 422 and errors_code: ai_origin_required. The session stays ready - repeat the call with the value within the session's 24 hours; an asset that is never attached is cleaned up after 7 days.


A file that shows another person needs that person's consent before it can be sold. Declare it on the file, not on the product:

  • Tag registered creators: POST /api/media/{media}/consent-tags with date (the consent date) and tagged_creator_ids[] (or a single tagged_creator_id). Find ids with GET /api/creators/search?q=.
  • Tag or invite by email: same call with email. A registered address is tagged directly; an unknown address needs tag_invite: true (and an optional message) - Fangate emails an invitation and the file waits for their answer. An unknown address without tag_invite is refused with 400. The call answers 200 with an empty data; read the state back with GET.
  • Mark now, tag later: PATCH /api/media/{media} with is_should_consent: true blocks the file until a person is tagged and has accepted.
  • Read the state: GET /api/media/{media}/consent-tags, or the consent object on every listing.

consent.status is one of not_required, review_open, consent_requested, consent_provided, declined, consent_rescinded; the list filter consent[] groups them into required (review_open, declined, consent_rescinded - the owner has to act), pending (consent_requested) and provided (not_required and consent_provided).

An AI file of another person (ai_origin: real_person_other) is marked as needing consent automatically.


4. Wait for moderation

Moderation runs after step 4 and takes seconds to minutes (videos longer; a first upload of a high-risk account waits for a manual review). There is no webhook for moderation or consent events today - poll the list (GET /api/media?status[]=pending) with a backoff of at least 30 seconds rather than polling every file; the list and the single-file endpoint share a limit of 60 requests per minute per key. Outbound webhooks exist for payments only (payment.successful, payment.failed, payment.pending).


5. Build a product from vault files

POST /api/products with

FieldNotes
media_ids[]Vault files of the creator. Mixing AI and non-AI files makes the product an AI product (see AI content). A file with ai_classified: false (not classified yet, reported as none) counts as non-AI until it is classified; the product flag follows then.
priceCents, at least 500.
titleOptional.
is_downloadableSend it explicitly. Absent means false on this call.
is_adult_content, is_verif_ageDefault from the account's upload defaults.
per_media_consent, media_consents[], consent_dateDeclare consent for specific files in the same call: "per_media_consent": true, "consent_date": "2026-09-12", "media_consents": [{ "media_id": 101, "tagged_creator_ids": [55] }]. Without per_media_consent: true the media_consents list is silently ignored.

No ai_origin here: the files are classified already. The response is the full product resource (201), with link, is_accessible and purchase_block_code.

Add or remove files later with POST /api/products/{product}/media (media_ids[], optionally with the consent fields above) and DELETE /api/products/{product}/media/{media}. Removing the last file deletes the product; in that case data is the string "deleted" instead of the product object.


6. Take a product apart

DELETE /api/products/{product} removes the product and, by default, its files from the vault as long as no other product uses them. To keep the files, send delete_media=0:

DELETE /api/products/123?delete_media=0

DELETE /api/media/{media} deletes a vault file; products that only had this file are deleted with it, other products lose the file.


7. Is it sellable?

Read GET /api/products/{product}:

is_accessiblepurchase_block_codeMeaning
truenullBuyers can purchase.
falsemoderation_not_approvedNo file of the product is approved yet. One approved file is enough for the sale; a rejected file next to it does not block - check status per file in GET /api/media if every file must be through.
falsemanual_review_pendingWaiting for a manual review (high-risk accounts).
falseconsent_recipient_missing, consent_pending, consent_declined, consent_rescindedConsent workflow open or negative.
falseprice_review_pendingThe price is above the threshold and awaits approval by Fangate.
falsemedia_unavailableA file is not available in storage.
falseai_rail_unavailableAI product while Fangate's platform-wide AI switch is off.

Fangate backend developer documentation