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}). An agency's key working inside its accounts has a higher ceiling per IP - see Rate limits.
| Parameter | Type | Meaning |
|---|---|---|
page, limit | integer | Pagination (limit up to 100). |
status[] | pending, approved, rejected | Moderation state. Scalars work too (status=approved). |
media_type[] | image, video | Kind of file. |
consent[] | required, pending, provided | Consent 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_id | integer | Vault folder (folders with scope=vault, see Content Folders). |
unlinked | boolean | Only files that belong to no product. |
live | boolean | Approved by moderation and consent cleared - the files a product can be built from. |
standard_only / ai_only | boolean | Only non-AI files / only AI files. |
sort | newest, oldest | |
search | string | Title 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
POST /api/upload-sessions-session_type: device_multipart,file_name,file_size_bytes,mime_type, and the AI answerai_origin(+ai_attestedfor AI values). See AI content for the four values.- Upload the bytes as instructed (
initial_uploadfor single-part,POST /api/upload-sessions/{id}/partsfor multipart), thenPOST /api/upload-sessions/{id}/complete. From your server this works without further setup; a browser on your own domain needs its origin on the storage allow-list first - see Uploading from your server or from a browser. - Poll
GET /api/upload-sessions/{id}untilstatusisready. Presigned URLs are valid for 15 minutes, a session for 24 hours. POST /api/mediawithupload_session_id, optionaltitle,description,folder_id,is_should_consent, andai_origin/ai_attestedif 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.
3. Consent per file
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-tagswithdate(the consent date) andtagged_creator_ids[](or a singletagged_creator_id). Find ids withGET /api/creators/search?q=. - Tag or invite by email: same call with
email. A registered address is tagged directly; an unknown address needstag_invite: true(and an optionalmessage) - Fangate emails an invitation and the file waits for their answer. An unknown address withouttag_inviteis refused with400. The call answers200with an emptydata; read the state back withGET. - Mark now, tag later:
PATCH /api/media/{media}withis_should_consent: trueblocks the file until a person is tagged and has accepted. - Read the state:
GET /api/media/{media}/consent-tags, or theconsentobject 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). For the product, a webhook tells you: product.sellable is sent once when the product can be bought (moderation, consent and, above the threshold, price approval are through), product.blocked when it cannot be sold, with the reason. There is no event per file: to follow single vault files before you build a product, 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. Payment events (payment.successful, payment.failed, payment.pending, payment.cancelled) are described on the same page.
5. Build a product from vault files
POST /api/products with
| Field | Notes |
|---|---|
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. |
price | Cents, at least 500. |
title | Optional. |
is_downloadable | Send it explicitly. Absent means false on this call. |
is_adult_content | Ignored - every product is AVS+ and answers true. |
is_verif_age | Default from the account's upload defaults. |
per_media_consent, media_consents[], consent_date | Declare 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. With an API key its files stay in the vault unless you ask for them to go - send delete_media=1, and they are deleted as long as no other product uses them:
DELETE /api/products/123?delete_media=1DELETE /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_accessible | purchase_block_code | Meaning |
|---|---|---|
true | null | Buyers can purchase. |
false | moderation_not_approved | No 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. |
false | manual_review_pending | Waiting for a manual review (high-risk accounts). |
false | consent_recipient_missing, consent_pending, consent_declined, consent_rescinded | Consent workflow open or negative. |
false | price_review_pending | The price is above the threshold and awaits approval by Fangate. |
false | media_unavailable | A file is not available in storage. |
false | ai_rail_unavailable | AI product while Fangate's platform-wide AI switch is off. |
8. Running many accounts from your own servers
A vault or CRM that every client connects with their own API key runs all of those keys from a few fixed servers. Two things can be arranged for that by mail to info@fangate.app:
- Registered server addresses. The ceilings per IP are meant for one caller's address; behind your server every connected creator's key shares them. Send us the egress addresses of your servers (single IPs or CIDR ranges) and calls with a generated key from there are counted on a ceiling of their own - see Rate limits. The limit per key and account stays.
- Fangate in a window inside your product. What a creator does in person - changing payout details or the password, managing keys - happens in the Fangate dashboard (signing up and identity verification can also run from screens of your own). Opening it in a pop-up window from your product needs nothing from us; the creator signs in there once per browser. Showing it inside a frame of your page is possible in individual cases only, after you have registered the page's domain with us, and is not something we promise for every integration: browsers restrict what a page inside a foreign frame may store, so the sign-in may not persist.