{
  "openapi": "3.0.3",
  "info": {
    "title": "FileSpin Public API",
    "version": "1.0.0",
    "description": "Public REST API for FileSpin, the AI DAM: upload and manage assets and their metadata, search, collections, schemas, processing and transcoding, addons (auto-tagging, background removal, face recognition), jobs, CDN and usage stats.\n\n**Authentication.** Send an API key in the `X-FileSpin-Api-Key` header (recommended for server-to-server connectors), or a JWT from `POST /api/v1/login` as `Authorization: Bearer <token>`.\n\nFull documentation, guides, rate limits and response codes: https://developers.filespin.io\n\nThis file is generated from the per-area specs that power the developer portal; it contains exactly the operations published there.",
    "contact": {
      "name": "FileSpin Support",
      "url": "https://www.filespin.io",
      "email": "support@filespin.io"
    }
  },
  "servers": [
    {
      "url": "https://app.filespin.io",
      "description": "Production"
    }
  ],
  "security": [
    {
      "ApiKeyAuth": []
    },
    {
      "BearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Authentication",
      "description": ""
    },
    {
      "name": "Assets - Content",
      "description": "Upload, download, delete, replace, and manage asset files. Each uploaded file creates a new asset with a unique 32-character alphanumeric UUID.\n\n**Key concepts:**\n- Deleting an `original` is a soft-delete (asset is hidden, can be restored)\n- Purging permanently removes the asset and all conversions\n- Public access can be set per-file or per-conversion"
    },
    {
      "name": "Assets - Data",
      "description": "Get and update asset metadata including core metadata (name, size, type) and custom metadata (user-defined JSON data).\n\nAll asset data follows the standard **[Asset Data Format](https://developers.filespin.io/api/asset-data-format)** - a JSON structure containing `id`, `status`, `name`, `size`, `content_type`, `metadata`, `data`, `conversions`, and `addons_info` fields.\n\n> **Important:** Asset status must be `OK` before accessing or updating. Check status after upload, especially for large files."
    },
    {
      "name": "Assets - Conversions",
      "description": "Manage custom conversion files for assets. Conversions are derivative files (e.g., edited copies, custom formats) stored alongside the original asset in cloud storage."
    },
    {
      "name": "Assets - Content Links",
      "description": "Use this API to retrieve links for Asset original content file and asset conversions. You can use this API to get a content link that can be presented as a downloadable link in a web page or an app.\n\n> **Tip:** For displaying images and videos, instead of `/get_link` API, we suggest you use the [On-demand Image Transformations](https://developers.filespin.io/image-transformations/) and [Video Streaming](https://developers.filespin.io/video-streaming/) delivered by FileSpin CDN.\n\n**Link types:**\n- `cdn` — Served via FileSpin CDN, cached at edge locations. Best for distributing files globally. FileSpin pre-fetches these links for quick delivery. There may be a few seconds delay before the file is cached. MAX expiry is 19 January 2038.\n- `object_storage` — Served directly from Object Storage. Best for one-time file access. MAX expiry is 7 days (604800 seconds).\n\n**Delivery modes:**\n- `display` — Returns a link suitable for embedding/displaying in a browser\n- `download` — Returns a link that triggers a file download when clicked (default)\n\n**Notes:**\n- For POST request, the maximum number of asset IDs that can be sent is 100\n- Use the special expiry value `MAX` to set expiry to the maximum possible for the chosen `link_type`"
    },
    {
      "name": "Search",
      "description": "Full-text search with faceted navigation across all assets.\n\n**Two-step search flow:**\n1. `POST /api/v1/assets/search` - Run search, get first page of results\n2. `GET /api/v1/assets/search/{search_result_id}/{page}` - Get additional pages\n\n**Features:** keyword search, file name/type filters, date/size ranges, custom schema field search, sort by multiple fields, extended results with full asset data.\n\n> **Note:** Result pages are limited to 10,000 assets. Use additional filters to narrow large result sets."
    },
    {
      "name": "Asset Processing",
      "description": "Trigger image conversions, video transcodes, and addon processing for assets.\n\n**Built-in image keys:** `smart_imaging`\n\n**Built-in video keys:** `360p-video`, `480p-video`, `720p-video`, `1080p-video`, `hls-video` (and watermarked variants with `-wm-`)\n\n**Special keys:** `clip_preview`, `storyboard`"
    },
    {
      "name": "Asset Schemas",
      "description": "Manage JSON Schema definitions for structured asset metadata. Schemas enable field-based search and data validation.\n\nFileSpin uses [JSON Schema 2020-12](https://json-schema.org/specification.html) with a FileSpin envelope. Each schema has `filespin_properties` for UI rendering, searchability, and keyword indexing.\n\n**Default Schema ID 0 contains a single `filespin_search_txt` searchable text field. This cannot be modified. Assets that do not have an assigned schema will default to Schema 0.**"
    },
    {
      "name": "Collections",
      "description": "Asset Collections provide a way to group assets and collaborate with other users. Collections can be private or shared within a user group.\n\n**Limits:** Maximum 300 assets per collection.\n\n**Basket:** A special default collection named `SELECTED_ASSETS` that cannot be renamed or have its privacy changed."
    },
    {
      "name": "Users & Settings",
      "description": "User account management, settings, and preferences"
    },
    {
      "name": "Jobs",
      "description": "Track the status of background processing jobs (video transcodes, batch operations, etc.).\n\nJob statuses: `QUEUED`, `IN_PROGRESS`, `COMPLETED`, `ERROR`.\n\nVideo transcode jobs include detailed step tracking with `preprocess`, `transcodes`, `addons`, and `postprocess` stages."
    },
    {
      "name": "CDN",
      "description": "Manage CDN caching for asset delivery. Pre-cache (prefetch) assets for faster delivery, or purge cached assets when content changes.\n\nSupports video transcodes, image conversions, and signed URLs. Requests are throttled to prevent abuse - batch multiple URLs in a single API call."
    },
    {
      "name": "Usage Stats",
      "description": "Retrieve API usage statistics, CDN traffic, video transcode usage, addon usage, and storage metrics.\n\nStats can be retrieved for all users in a group (consolidated) or filtered by specific user ID. Default period is 24 hours. Time series stats support custom date ranges up to 364 days."
    },
    {
      "name": "Addons - Face Recognition",
      "description": "Face detection, recognition, and search capabilities"
    },
    {
      "name": "Addons - Image Analysis",
      "description": "Automatic image tagging, content analysis, and OCR text extraction.\n\nFileSpin's Image Analysis addon runs vision analysis on uploaded images using Google Vision AI and extracts structured metadata that's stored alongside the asset and indexed for search:\n\n- **Auto-tagging** — labels with confidence scores describing the contents of the image (objects, scenes, concepts).\n- **Best-guess labels** — a short summary describing the image as a whole.\n- **OCR (text extraction)** — reads text inside images (screenshots, signs, product labels, documents) and indexes it for keyword search. Words shorter than 3 characters are excluded; up to 500 words are indexed per image.\n\nAll extracted data is searchable through the standard search API. The addon can be triggered on-demand via the API below, or run automatically as part of the Automated Media Pipeline.\n\nFor the conceptual overview and end-user feature description, see [Image Analysis (AI)](https://developers.filespin.io/intro/ai/image-analysis). For automating this addon on upload or metadata change, see [Automated Media Pipeline](https://developers.filespin.io/automated-media-pipeline)."
    },
    {
      "name": "Addons - Background Removal",
      "description": "Remove image backgrounds"
    },
    {
      "name": "Addons - Video Storyboard",
      "description": "Generate video storyboards and thumbnails"
    },
    {
      "name": "Webhooks",
      "description": "Manage webhook callbacks for asset events. Configure webhook URLs in account settings to receive automatic callback notifications.\n\n**Supported events:** `file-saved`, `file-processed`, `file-data-updated`, `file-deleted`, `file-undeleted`, `addon-processed`\n\n| Event             | Description                                                                                                              |\n| :---------------- | :----------------------------------------------------------------------------------------------------------------------- |\n| file-saved        | When a file is stored in your storage after user uploads through File Picker or Upload API                               |\n| file-processed    | When image and video conversions are processed (upload workflow or Image/Video Conversion API)                          |\n| file-data-updated | When custom data is attached via FileSpin.update or Update File Data API                                                  |\n| file-deleted      | When conversions, transcodes or original file is deleted via Delete API                                                   |\n| file-undeleted    | When original file is undeleted via Undelete API                                                                        |\n| addon-processed   | An addon has completed processing                                                                                        |\n\n**Retry behavior:** Webhook callbacks are attempted up to 8 times if the endpoint does not respond with HTTP 20x (200, 201, 202). Retries follow a back-off algorithm over 8 hours.\n\n**Data format:** For `file-saved`, `file-processed`, `file-data-updated`, `addon-processed` — payload is [Asset Data Format](https://developers.filespin.io/api/asset-data-format). For `file-deleted` and `file-undeleted` — payload includes `id`, `event`, `keys`, `status`, `message`, `errors` (see callback endpoint description)."
    }
  ],
  "x-tagGroups": [
    {
      "name": "Authentication API",
      "tags": [
        "Authentication"
      ]
    },
    {
      "name": "Asset API",
      "tags": [
        "Assets - Content",
        "Assets - Data",
        "Assets - Conversions",
        "Assets - Content Links"
      ]
    },
    {
      "name": "Asset Search API",
      "tags": [
        "Search"
      ]
    },
    {
      "name": "Asset Processing API",
      "tags": [
        "Asset Processing"
      ]
    },
    {
      "name": "Asset Schema API",
      "tags": [
        "Asset Schemas"
      ]
    },
    {
      "name": "Asset Collection API",
      "tags": [
        "Collections"
      ]
    },
    {
      "name": "User API",
      "tags": [
        "Users & Settings"
      ]
    },
    {
      "name": "Jobs API",
      "tags": [
        "Jobs"
      ]
    },
    {
      "name": "CDN API",
      "tags": [
        "CDN"
      ]
    },
    {
      "name": "Usage Stats API",
      "tags": [
        "Usage Stats"
      ]
    },
    {
      "name": "Addons API",
      "tags": [
        "Addons - Face Recognition",
        "Addons - Image Analysis",
        "Addons - Background Removal",
        "Addons - Video Storyboard"
      ]
    },
    {
      "name": "Tools & Integration API",
      "tags": [
        "Webhooks"
      ]
    }
  ],
  "paths": {
    "/api/v1/login": {
      "post": {
        "summary": "Retrieve JWT using Login",
        "operationId": "get_JWT_and_basic_user_info_post",
        "description": "Web applications should use this API to retrieve JWT and user profile. Subsequent API calls can then use the JWT obtained.\n\n#### Request JSON\n\n| Parameter  | Type   | Description    |\n| ---------- | ------ | -------------- |\n| `email`    | string | Login email ID |\n| `password` | string | Login password |\n\n#### API RESPONSE\n\nA JSON with JWT and other user details.\n\n> Response with JWT\n\n```json\n{\n  \"user_id\": 42,\n  \"user_email\": \"user@example.org\",\n  \"username\": \"John Doe\",\n  \"jwt\": \"JWT\",\n  \"role_id\": 1,\n  \"role_name\": \"ADMIN\",\n  \"permissions\": [\"CREATE_ASSET\", \"READ_ASSET\", \"EDIT_ASSET\"],\n  \"uploadkey\": \"ec5139a372f6478d97365ec0df9c9a814\",\n  \"accessID\": \"IZJTAMBQGAYDAMBQGAYDAMBQGAYDANKT\",\n  \"preferences\": {},\n  \"notifications\": [\"Notification message 1\"]\n}\n```\n\n| Parameter       | Type    | Description                                                              |\n| --------------- | ------- | ------------------------------------------------------------------------ |\n| `jwt`           | string  | JSON Web Token. Use this in subsequent API calls as `Authorization: Bearer <jwt>`. |\n| `user_id`       | integer | Unique user identifier                                                   |\n| `user_email`    | string  | User's email address                                                     |\n| `username`      | string  | User name as `Firstname Lastname`                                        |\n| `role_id`       | integer | User role ID (1=ADMIN, 2=MANAGER, 3=USER, 4=CREATOR)                    |\n| `role_name`     | string  | User role name                                                           |\n| `permissions`   | array   | List of permission tokens for this user's role                           |\n| `uploadkey`     | string  | File upload key for use in Picker widget                                 |\n| `accessID`      | string  | Access identifier for signed URL generation                              |\n| `preferences`   | object  | User preferences                                                         |\n| `notifications` | array   | List of notification messages since last login                           |",
        "tags": [
          "Authentication"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Successful login",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LoginResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad request - Missing or invalid request parameters"
          },
          "401": {
            "description": "Unauthorized - Invalid email or password"
          },
          "403": {
            "description": "Forbidden - Account disabled or access denied"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "requestBody": {
          "$ref": "#/components/requestBodies/get_jwt_and_basic_user_info"
        }
      }
    },
    "/api/v1/assets/new/content/original/upload": {
      "post": {
        "summary": "Upload Asset",
        "operationId": "uploadAsset_post",
        "description": "Use this API to upload one or more files and create assets within FileSpin. For uploads from websites, use the [File Picker Web Widget](https://developers.filespin.io/file-picker-widget).\n\n> **Info:** This endpoint is served on `https://upload.filespin.io` — not the standard `https://app.filespin.io` host used by the rest of the API. Make sure your client targets the upload host for this request.\n\n**Note:**\n\n* To upload a single file, use `file` as multipart-form field name for file.\n* To upload multiple files in a single request, use `file1`, `file2`, `file3`, etc. as multipart-form field names for files.\n* Each uploaded file will result in a new asset being created.\n* `file` , `file1`, `file2`, `file3`, etc. are conventional names for multipart-form field names. You can use any name for the field names.\n\n### Adding metadata to the asset\n\nThere are two ways to add custom metadata to the asset.\n\n1. Update the asset with custom metadata once the upload completes. See Update Data API to do this.\n2. Send custom metadata with the upload. To send custom asset metadata with the upload, include JSON metadata as string in `custom_metadata` form-data field, like below. Custom metadata sent as below will be added to the asset.\n\n```bash\ncurl --request POST \\\n  --url https://app.filespin.io/api/v1/assets/new/content/original/upload \\\n  --header 'X-FileSpin-Api-Key: YOUR_API_KEY' \\\n  --header 'content-type: multipart/form-data' \\\n  --form file=@sample.jpg \\\n  --form 'custom_metadata={\"data\":{\"foo\":\"bar\"}, \"data_schema_id\":1}'\n```\n\nThe `custom_metadata` field JSON value follows the same format and rules as the Update Data API payload.\n\n**Note**: Since data being sent as `multipart/form-data`, `custom_metadata` JSON should be sent as string as shown above.\n\n### HTTP RESPONSE\n\nStandard HTTP Status Code (200 or 202)\n\n| Key            | Value   | Description                                                                                                                                                                                                            |\n| -------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `files`        | JSON    | List of files                                                                                                                                                                                                          |\n| `id`           | string  | Asset ID, 32 character alphanumeric UUID                                                                                                                                                                               |\n| `name`         | string  | File name                                                                                                                                                                                                              |\n| `size`         | integer | Size of file in bytes                                                                                                                                                                                                  |\n| `checksum`     | string  | MD5 checksum                                                                                                                                                                                                           |\n| `content_type` | string  | MIME type                                                                                                                                                                                                              |\n| `provider`     | string  | Always \"local\" to indicate local upload                                                                                                                                                                                |\n| `success`      | boolean | `true` if upload completed, `false` otherwise                                                                                                                                                                          |\n| `metadata`     | JSON    | Only returned for custom plans. Applies to image uploads. Where available, Exiftool tag values for 'ColorMode', 'ColorSpace', 'Orientation', 'Make' and 'Model' are returned. 'Width' and 'Height' are always returned |\n\n### Response JSON\n\n```json\n{\n  \"files\": [\n    {\n      \"id\": \"99d819953914402babbdeb68337ea6a3\",\n      \"name\": \"sample.jpg\",\n      \"size\": 8836363,\n      \"checksum\": \"5f5f26bd7c0f62c6e02e44c73d09734e\",\n      \"content_type\": \"image/jpeg\",\n      \"metadata\": {\n        \"Make\": \"Apple\",\n        \"ColorSpace\": \"sRGB\",\n        \"Model\": \"iPhone 3G\",\n        \"Orientation\": \"Horizontal (normal)\",\n        \"width\": 1200,\n        \"height\": 800\n      }\n    }\n  ],\n  \"success\": true,\n  \"provider\": \"local\"\n}\n```",
        "tags": [
          "Assets - Content"
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/upload"
        },
        "responses": {
          "200": {
            "description": "Asset uploaded successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UploadResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid upload request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/assets/new/content/original/external": {
      "post": {
        "summary": "Ingest from URI",
        "operationId": "Ingest_from_URI_post",
        "description": "Use of this API to request FileSpin to retrieve a file from external HTTP URL or a S3 Bucket and create an asset.\n\n> **Info:** This endpoint is served on `https://upload.filespin.io` — not the standard `https://app.filespin.io` host used by the rest of the API. Make sure your client targets the upload host for this request.\n\n### Note\n\n* If S3 source is provided, the S3 Bucket must have S3 Access policy to authorize FileSpin access (see `Asset Storage` section for policy details)\n* If HTTP URL is provided, the URL must supply downloadable content and should not require authentication. Downloads from external websites will be rate-limited.\n* Adding custom metadata as part of this request is not supported at this time\n\n### Example request JSON payload\n\n**Request to pull a S3 file**\n\n```\n{\n  \"name\": \"test.jpg\",\n  \"key\": \"s3://my-bucket/test.jpg\"\n}\n```\n\n**Request to pull a file from a https URL**\n\n```\n{\n  \"name\": \"test.jpg\",\n  \"key\": \"https://example.com/test.jpg\"\n}\n```\n\n### HTTP RESPONSE\n\nStandard HTTP Status code (202 or 200).\n\n| Key       | Value  | Description                                                                               |\n| --------- | ------ | ----------------------------------------------------------------------------------------- |\n| `id`      | string | Asset ID, 32 character alphanumeric UUID                                                  |\n| `status`  | string | `\"QUEUED\"` if request was successfully received, `\"ERROR\"` if request cannot be processed |\n| `message` | string | Additional details about status                                                           |\n\n### Response JSON\n\n```json\n{\n  \"id\": \"ceace459cd2a4d2c904e38e9ab352ebb\",\n  \"status\": \"QUEUED\",\n  \"message\": \"Queued for processing\"\n}\n```",
        "tags": [
          "Assets - Content"
        ],
        "responses": {
          "200": {
            "description": "Successful operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IngestResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IngestFromUriRequest"
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/assets/{asset_id}/content/original/replace": {
      "post": {
        "summary": "Replace Asset Content",
        "operationId": "replaceAssetContent_post",
        "description": "API to replace the original content file of an asset while keeping the Asset ID unchanged.\n\n> **Info:** This endpoint is served on `https://upload.filespin.io` — not the standard `https://app.filespin.io` host used by the rest of the API. Make sure your client targets the upload host for this request.\n\n> **Note:** For replacing files from within web pages, use the [File Picker in Replace mode](https://developers.filespin.io/file-picker-widget/picker-replace-mode). To add or update custom metadata for the asset during replace, see [Adding metadata to the asset](https://developers.filespin.io/api-reference/assets/update-data-post).\n\n### HTTP RESPONSE\n\n| Key            | Value   | Description                                                                                                                                                                                                            |\n| -------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `files`        | JSON    | List of files                                                                                                                                                                                                          |\n| `id`           | string  | Asset ID, 32 character alphanumeric UUID                                                                                                                                                                               |\n| `name`         | string  | File name                                                                                                                                                                                                              |\n| `size`         | integer | Size of file in bytes                                                                                                                                                                                                  |\n| `checksum`     | string  | MD5 checksum                                                                                                                                                                                                           |\n| `content_type` | string  | MIME type                                                                                                                                                                                                              |\n| `provider`     | string  | always \"local\" to indicate local upload                                                                                                                                                                                |\n| `success`      | boolean | true if upload completed, false otherwise                                                                                                                                                                              |\n| `metadata`     | JSON    | Only returned for custom plans. Applies to image uploads. Where available, Exiftool tag values for 'ColorMode', 'ColorSpace', 'Orientation', 'Make' and 'Model' are returned. 'Width' and 'Height' are always returned |\n\n### Response JSON\n\n```json\n{\n  \"files\": [\n    {\n      \"id\": \"99d819953914402babbdeb68337ea6a3\",\n      \"name\": \"sample.jpg\",\n      \"size\": 8836363,\n      \"checksum\": \"5f5f26bd7c0f62c6e02e44c73d09734e\",\n      \"content_type\": \"image/jpeg\",\n      \"metadata\": {\n        \"Make\": \"Apple\",\n        \"ColorSpace\": \"sRGB\",\n        \"Model\": \"iPhone 3G\",\n        \"Orientation\": \"Horizontal (normal)\",\n        \"width\": 1200,\n        \"height\": 800\n      }\n    }\n  ],\n  \"success\": true,\n  \"provider\": \"local\"\n}\n```",
        "tags": [
          "Assets - Content"
        ],
        "parameters": [
          {
            "name": "asset_id",
            "in": "path",
            "required": true,
            "description": "Unique 32-character hex identifier of the asset",
            "schema": {
              "type": "string"
            },
            "example": "a211ab5f351f4b398426efb59b0c72a3"
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/replace"
        },
        "responses": {
          "200": {
            "description": "Asset content replaced successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UploadResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Asset not found"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/assets/{asset_id}/content/original/download": {
      "get": {
        "summary": "Download",
        "operationId": "download_get",
        "description": "Use this API to retrieve the original file or a pre-defined image conversion or a video transcode. HTTP Range header can also be used to retrieve large file as multiple parts.\n\n### HTTP RESPONSE\n\nThe file is returned. Mime type and length of the content returned will be set in the response header.\n\n### Download large file as multiple parts\n\nYou can use HTTP Range header parameter to download a large file as multiple parts. For details about the HTTP Range header, please visit `http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35`",
        "tags": [
          "Assets - Content"
        ],
        "responses": {
          "200": {
            "description": "Successful operation"
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "parameters": [
          {
            "name": "asset_id",
            "in": "path",
            "required": true,
            "description": "Unique 32-character hex identifier of the asset",
            "schema": {
              "type": "string"
            },
            "example": "a211ab5f351f4b398426efb59b0c72a3"
          }
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/assets/{asset_id}/delete": {
      "post": {
        "summary": "Delete",
        "operationId": "delete_post",
        "description": "API to delete an asset or it's conversions. Deleting the `original` is a soft-delete within FileSpin. It will mark Asset as deleted and hide it from view (See Purge API to completely purge an Asset). Asset administrators can retrieve deleted Assets using Search API by setting `trashed` option to true. Unknown custom keys and keys that do not apply to the file type will be ignored\n\n> **Warning:** If an `original` is deleted, all it's conversions will be deleted. If a deleted `original` is restored, conversions that are enabled in the profile will be re-created.\n\n### Request JSON Parameters\n\n| Key    | Value | Description                                                      |\n| ------ | ----- | ---------------------------------------------------------------- |\n| `keys` | JSON  | List of conversion keys. See below for Keys that you can specify |\n\n| Asset/Key type    | keys list values                                                                                                   |\n| ----------------- | ------------------------------------------------------------------------------------------------------------------ |\n| `Image`           | Built-in keys such as \"deepzoom\" and/or all the custom conversion keys setup in account settings                   |\n| `Video`           | Built-in keys such as \"480p-video\", \"480p-wm-video\", \"hls-video\", \"storyboard\", etc                                |\n| `Original`        | To delete the original asset, use the key \"original\". Note this will delete and purge all conversions from storage |\n| `Addon`           | Addon key defined by the addons deployed                                                                           |\n| `All Conversions` | Use the special key `*` to delete all conversions                                                                  |\n\n### Webhook callback on delete completion\n\nOnce the delete request is completed, callback is issued to configured Webhook.\n\nPlease see Tools & Integration- > Webhooks section for `file-deleted` event callback to learn about the callback JSON structure.\n\n### HTTP Response\n\nStandard HTTP Status code - 202 or 200",
        "tags": [
          "Assets - Content"
        ],
        "responses": {
          "200": {
            "description": "Successful operation"
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeleteRequest"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "asset_id",
            "in": "path",
            "required": true,
            "description": "Unique 32-character hex identifier of the asset",
            "schema": {
              "type": "string"
            },
            "example": "a211ab5f351f4b398426efb59b0c72a3"
          }
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/assets/bulk/delete": {
      "post": {
        "summary": "Delete - Bulk",
        "operationId": "delete___bulk_post",
        "description": "API to delete assets in bulk. This soft deletes the asset which marks the original as deleted and removes all conversions and addons for an asset.\n\n> **Warning:** If an `original` is deleted, all it's conversions will be deleted. If a deleted `original` is restored, conversions that are enabled in the profile will be re-created.\n\n### Request JSON Parameters\n\n| Key          | Value  | Description                                                                                     |\n| ------------ | ------ | ----------------------------------------------------------------------------------------------- |\n| `start_time` | string | The start time for the range in ISO 8601 format. Date range is for the Asset Upload Time. |\n| `end_time`   | string | The start time for the range in ISO 8601 format. Date range is for the Asset Upload Time. |\n\nExample Request body\n\n```json\n{\n  \"start_time\": \"2025-01-20T00:00:00Z\",\n  \"end_time\": \"2025-01-30T23:59:59Z\"\n}\n```\n\n### Webhook callback and Database exports on asset deletion\n\nFor each asset deleted, callback/export is issued to configured Webhook/Database.\n\nPlease see Tools & Integration- > Webhooks and Database Export sections to learn about the callbacks.\n\n### HTTP Response\n\nReturns a job id in below JSON if request was successful.\n\n```json\n{\n  \"status\": \"QUEUED\",\n  \"message\": \"Job queued\",\n  \"job_id\": 947\n}\n```\n\n### API Limits\n\nThis API is part of restricted APIs to prevent abuse and inadvertent actions. The limitations include:-\n\n* API rate limits\n* range limits such as total number of assets that can be deleted in one API call. Default is 1000 assets.\n* range limits such as date ranges that can be used in API request. Default is 31 days.\n\nThese limits may be different for custom enterprise deployments. Please check with our Support team if needed.",
        "tags": [
          "Assets - Content"
        ],
        "responses": {
          "200": {
            "description": "Successful operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProcessingResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkDeleteRequest"
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/assets/trash/{asset_id}/undelete": {
      "post": {
        "summary": "Undelete",
        "operationId": "undelete_post",
        "description": "API to undelete an asset that has been deleted.\n\n> **Warning:** For undelete only \"original\" key is accepted.\n\n> **Note:** Note that upon a asset restore operation, conversions enabled in the profile will be re-generated.\n\n### Webhook callback on undelete completion\n\nOnce the undelete request is completed, callback is issued to configured Webhook.\n\nPlease see Tools & Integration- > Webhooks section for `file-undeleted` event callback to learn about the callback JSON structure.\n\n### HTTP Response\n\nStandard HTTP Status code - 202 or 200",
        "tags": [
          "Assets - Content"
        ],
        "responses": {
          "200": {
            "description": "Successful operation"
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "requestBody": {
          "$ref": "#/components/requestBodies/undelete"
        },
        "parameters": [
          {
            "name": "asset_id",
            "in": "path",
            "required": true,
            "description": "Unique 32-character hex identifier of the asset",
            "schema": {
              "type": "string"
            },
            "example": "a211ab5f351f4b398426efb59b0c72a3"
          }
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/assets/trash/purge": {
      "delete": {
        "summary": "Purge Deleted Assets",
        "operationId": "purge_delete",
        "description": "**This is a ADMIN-only API**\n\nAPI to completely purge all assets that are in Trash (i.e. in `deleted` state) across all users within a User Group.\n\n> **Warning:** When an asset is purged all its conversions and associated data will also be purged. Purged files and data cannot be recovered. Please exercise caution.\n\n> **Note:** Note that this API only purges files whose \"original\" has been deleted using the Delete API\n\n### HTTP Response\n\nStandard HTTP Status code - 202 or 200",
        "tags": [
          "Assets - Content"
        ],
        "responses": {
          "200": {
            "description": "Successful operation"
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "requestBody": {
          "content": {
            "text/plain": {
              "schema": {
                "type": "string"
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/assets/{asset_id}/content/set_public_access": {
      "post": {
        "summary": "Set Public Access",
        "operationId": "set_public_access_post",
        "description": "This API can be used to set public-read access to a file or its conversions in the Cloud Storage (such as S3).\n\n> **Warning:** This makes the file publicly accessible in the cloud storage. Do this only if you intend to let everyone in the world access the file.\n\n**Possible Key values**\n\n| Type        | keys list values                                                                                                                                                                                                       |\n| ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| All files   | Built-in key `original` **the asset original file**                                                                                                                                                                    |\n| Image files | Built-in keys: `deepzoom` and/or all the custom conversion keys setup in account settings                                                                                                                              |\n| Video files | Built-in keys: `360p-video`, `360p-wm-video`, `480p-video`, `480p-wm-video`, `720p-video`, `720p-wm-video`, `1080p-video`, `1080p-wm-video` and/or `hls-video` (note that \\*-wm-video keys are for watermarked videos) |\n\n### HTTP Response\n\nStandard HTTP Status code - 202 or 200",
        "tags": [
          "Assets - Content"
        ],
        "responses": {
          "200": {
            "description": "Successful operation"
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicAccessRequest"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "asset_id",
            "in": "path",
            "required": true,
            "description": "Unique 32-character hex identifier of the asset",
            "schema": {
              "type": "string"
            },
            "example": "a211ab5f351f4b398426efb59b0c72a3"
          }
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/assets/{asset_id}/data": {
      "get": {
        "summary": "Get Data",
        "operationId": "get_data_get",
        "description": "Retrieve an Asset's data that includes `Core metadata`, `Custom metadata`, conversions and addon details.\n\n### HTTP RESPONSE\n\nHTTP Status code and JSON response that follows Standard [Asset Data Format](https://developers.filespin.io/api/asset-data-format)",
        "tags": [
          "Assets - Data"
        ],
        "responses": {
          "200": {
            "description": "Successful operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AssetData"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "parameters": [
          {
            "name": "asset_id",
            "in": "path",
            "required": true,
            "description": "Unique 32-character hex identifier of the asset",
            "schema": {
              "type": "string"
            },
            "example": "a211ab5f351f4b398426efb59b0c72a3"
          }
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/assets/{asset_id}/data/update": {
      "post": {
        "summary": "Update Data",
        "operationId": "update_data_post",
        "description": "Save arbitrary JSON data as custom metadata for an asset.\n\n> **Note:** To add custom metadata during asset upload, see [Upload API](https://developers.filespin.io/api-reference/assets/upload-asset-post)\n\n### Higher throughput with async mode\n\nThe Update Data API synchronously updates asset data within multiple services (Database, Search). For higher throughput with eventual consistency, use the `async` query parameter. Supply `async=1` in the API URL, e.g. `/api/v1/assets/{asset_id}/data/update?async=1`.\n\n> **Warning:** When `async=1` is used, Get Data and Search may take seconds to minutes to reflect metadata changes. Use async mode only if this trade-off is acceptable.\n\n### REQUEST JSON BODY\n\nThe request body should be a JSON with `data` and `mode` keys.\n\n> **Note:** Add \"filespin_search_txt\" special key to have it's value indexed for search. This is useful if you would like to add your own ID to a file and later retrieve the file by that ID.\n\n> **Important:** Ensure that custom data fields sent for update do not begin with `_filespin`. This is a reserved field prefix used by FileSpin to capture internal and generated data such as addon processing outputs. Data fields that begin with `_filespin` are not user updateable.\n\n**Example request**\n\nTo update file data, send a JSON payload like below to store with the file.\n\n```\n{\n  \"data\": {\n    \"input1\": \"value1\",\n    \"input2\": \"value2\",\n    \"filespin_search_txt\": \"MY_OWN_FILE_ID\"\n  },\n  \"mode\": \"APPEND\"\n}\n```\n\n| Key    | Value  | Description                                                                                |\n| ------ | ------ | ------------------------------------------------------------------------------------------ |\n| `data` | JSON   | JSON data to be saved with the file                                                        |\n| `mode` | string | `APPEND` will append the data to any existing data. `REPLACE` will overwrite with the new data |\n\n#### \"APPEND\" mode\n\nConsider the scenario where\n\n**Asset contains this data:**\n\n```json\n{\n  \"data\": {\n    \"myfield\": \"myvalue\",\n    \"input1\": \"OLD-VALUE\"\n  }\n}\n```\n\n**\"APPEND\" mode request is sent with the below payload**\n\n```json\n{\n  \"data\": {\n    \"input1\": \"NEW-VALUE\",\n    \"input2\": \"value2\"\n  },\n  \"mode\": \"APPEND\"\n}\n```\n\nAsset will be updated so that the resulting asset data is as below:-\n\n**Note that any existing field value is overwritten by new value if that field is sent in payload**\n\n**Final Asset Data**\n\n```json\n{\n  \"data\": {\n    \"myfield\": \"myvalue\",\n    \"input1\": \"NEW-VALUE\",\n    \"input2\": \"value2\"\n  }\n}\n```\n\n#### \"REPLACE\" mode\n\nConsider the scenario where\n\n**Asset contains this data:**\n\n```json\n{\n  \"data\": {\n    \"myfield\": \"myvalue\"\n  }\n}\n```\n\n**\"REPLACE\" mode request is sent with the below payload**\n\n```json\n{\n  \"data\": {\n    \"input1\": \"value1\",\n    \"input2\": \"value2\",\n    \"filespin_search_txt\": \"MY_OWN_FILE_ID\"\n  },\n  \"mode\": \"REPLACE\"\n}\n```\n\nAsset will be updated so that the resulting asset data is as below:-\n\n**Final Asset Data**\n\n```json\n{\n  \"data\": {\n    \"input1\": \"value1\",\n    \"input2\": \"value2\",\n    \"filespin_search_txt\": \"MY_OWN_FILE_ID\"\n  }\n}\n```\n\n### API Limits\n\n* Maximum payload size is limited to 2000 characters.\n* If Asset is in `NOT_READY` state (that is, asset is in-flight to Storage) this API will return HTTP 400. Check for `OK` status using Asset Data API before updating or retry after a few seconds.\n* If Asset metadata is being updated by another process, this API will return a HTTP 202 until the other update completes.\n\n### JSON Schema support\n\nFileSpin supports JSON Schema for Asset Data. Assigning schema to asset data enables versatile field-based search and additional data validations.\n\nOnce one or more schemas have been setup for an account, you can pass the optional schema id `data_schema_id` as shown below to automatically assign a schema to the asset data.\n\n```\n{\n  \"data\": {\n    \"input1\": \"value1\",\n    \"input2\": \"value2\",\n    \"filespin_search_txt\": \"MY_OWN_FILE_ID\"\n  },\n  \"mode\": \"APPEND\",\n  \"data_schema_id\": 1\n}\n```",
        "tags": [
          "Assets - Data"
        ],
        "responses": {
          "200": {
            "description": "Successful operation"
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateDataRequest"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "asset_id",
            "in": "path",
            "required": true,
            "description": "Unique 32-character hex identifier of the asset",
            "schema": {
              "type": "string"
            },
            "example": "a211ab5f351f4b398426efb59b0c72a3"
          },
          {
            "name": "async",
            "in": "query",
            "required": false,
            "description": "`0` = synchronous (default), `1` = asynchronous. Use `async=1` for higher throughput with eventual consistency.\nWhen `async=1`, Get Data and Search may take seconds to minutes to reflect changes.\n",
            "schema": {
              "type": "string",
              "enum": [
                "0",
                "1"
              ],
              "default": "0"
            }
          }
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/assets/{asset_id}/content/{conversion_name}": {
      "post": {
        "summary": "Add Conversion",
        "operationId": "addConversion_post",
        "description": "Use this API to upload and add a custom conversion file to an asset (such a manually edited copy of an image). The uploaded file will be stored as an asset's conversion in the Cloud Storage.\n\n### HTTP REQUEST\n\n| Key               | Value  | Description                                                                                                                                       |\n| :---------------- | :----- | :------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `ASSET_ID`        | string | Asset ID, 32 character alphanumeric UUID                                                                                                          |\n| `CONVERSION_NAME` | string | An identifier for the Conversion such as `my_edited_copy`. It must not exceed 30 characters. It can only be alphanumeric. Spaces are not allowed. |\n\n### HTTP RESPONSE\n\nStandard HTTP Status code - 202 or 200",
        "tags": [
          "Assets - Conversions"
        ],
        "parameters": [
          {
            "name": "asset_id",
            "in": "path",
            "required": true,
            "description": "Unique 32-character hex identifier of the asset",
            "schema": {
              "type": "string"
            },
            "example": "a211ab5f351f4b398426efb59b0c72a3"
          },
          {
            "name": "conversion_name",
            "in": "path",
            "required": true,
            "description": "Name of the conversion to add",
            "schema": {
              "type": "string"
            },
            "example": "thumbnail"
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/add-conversion"
        },
        "responses": {
          "200": {
            "description": "Conversion added successfully"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Asset not found"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      },
      "delete": {
        "summary": "Delete Conversion",
        "operationId": "deleteConversion_delete",
        "description": "Use this API to delete a conversion file of an asset.\n\n### HTTP RESPONSE\n\nAppropriate HTTP Status Code as specified in [Response Codes] section\n\n### HTTP REQUEST\n\n| Key               | Value  | Description                                                                                                                                       |\n| :---------------- | :----- | :------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `ASSET_ID`        | string | Asset ID, 32 character alphanumeric UUID                                                                                                          |\n| `CONVERSION_NAME` | string | An identifier for the Conversion such as `my_edited_copy`. It must not exceed 30 characters. It can only be alphanumeric. Spaces are not allowed. |",
        "tags": [
          "Assets - Conversions"
        ],
        "parameters": [
          {
            "name": "asset_id",
            "in": "path",
            "required": true,
            "description": "Unique 32-character hex identifier of the asset",
            "schema": {
              "type": "string"
            },
            "example": "a211ab5f351f4b398426efb59b0c72a3"
          },
          {
            "name": "conversion_name",
            "in": "path",
            "required": true,
            "description": "Name of the conversion to delete",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Conversion deleted successfully"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Asset or conversion not found"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/assets/{asset_id}/conversions/{id}": {
      "get": {
        "summary": "Get Conversion",
        "operationId": "get_conversion_get",
        "description": "Asset conversions can be retrieved:-\n\n**As Static Image Conversion URL**\n\n*When using this option, all[On-demand Image transformation] options such as resize, crop, etc can be applied.*\n\n**As a signed URL via /get\\_link API**\n\nUse `/get_link` API providing the `conversion_name` as `CONTENT_KEY` as described in **[Asset Get Link]** section\n\n> **Note:** Note that these methods cannot be used to retrieve special conversions such as Zoomable image, HLS video, etc\n\n### HTTP REQUEST\n\n| Key               | Value  | Description                                                                                                                                       |\n| :---------------- | :----- | :------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `ASSET_ID`        | string | Asset ID, 32 character alphanumeric UUID                                                                                                          |\n| `CONVERSION_NAME` | string | An identifier for the Conversion such as `my_edited_copy`. It must not exceed 30 characters. It can only be alphanumeric. Spaces are not allowed. |",
        "tags": [
          "Assets - Conversions"
        ],
        "responses": {
          "200": {
            "description": "Successful operation"
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "parameters": [
          {
            "name": "asset_id",
            "in": "path",
            "required": true,
            "description": "Unique 32-character hex identifier of the asset",
            "schema": {
              "type": "string"
            },
            "example": "a211ab5f351f4b398426efb59b0c72a3"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Resource identifier",
            "schema": {
              "type": "string"
            },
            "example": "1"
          }
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/assets/{asset_id}/get_link": {
      "get": {
        "summary": "Get Link (Single Asset)",
        "operationId": "link_type___object_storage_get",
        "description": "Get a content link for a single asset. The returned URL can be used to display or download the asset's original file or any of its conversions.\n\n**Example response:**\n\n```\nhttps://cdn.filespin.io/api/v1/files/content/c5651f8783f64d09985f0dd38359d846?key=thumbnail&expiry=1486556379&delivery=display&accessId=IZJTAMBQ...&signature=ScdZeFTEs41edg...\n```",
        "tags": [
          "Assets - Content Links"
        ],
        "responses": {
          "200": {
            "description": "Successful operation — returns the content link URL"
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "parameters": [
          {
            "name": "key",
            "in": "query",
            "description": "`original` or any pre-defined conversion name/key for images and video transcodes. See your Settings for image and video keys.",
            "required": true,
            "example": "original",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "expiry",
            "in": "query",
            "description": "Seconds after which the link should expire. Defaults to `6000` (10 minutes). Use the special value `MAX` to set expiry to maximum possible (cdn: 19 January 2038, object_storage: 7 days).",
            "required": false,
            "example": "MAX",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "link_type",
            "in": "query",
            "description": "Get CDN link or direct storage link. `cdn` — served via FileSpin CDN, cached at edge. `object_storage` — served directly from storage. Defaults to `cdn`.",
            "required": false,
            "example": "cdn",
            "schema": {
              "type": "string",
              "enum": [
                "cdn",
                "object_storage"
              ]
            }
          },
          {
            "name": "delivery",
            "in": "query",
            "description": "Get a link for display or download. `display` — suitable for embedding in a page. `download` — triggers a file download when clicked. Defaults to `download`.",
            "required": false,
            "example": "download",
            "schema": {
              "type": "string",
              "enum": [
                "display",
                "download"
              ]
            }
          },
          {
            "name": "accessId",
            "in": "query",
            "description": "Access ID used to sign URLs. Obtain from your account Authorization Settings page.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "asset_id",
            "in": "path",
            "required": true,
            "description": "Unique 32-character hex identifier of the asset",
            "schema": {
              "type": "string"
            },
            "example": "a211ab5f351f4b398426efb59b0c72a3"
          }
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/assets/get_link": {
      "post": {
        "summary": "Get Link (Multiple Assets)",
        "operationId": "multiple_asset_post",
        "description": "Get content links for multiple assets in a single request. Pass asset IDs in the request body as a JSON array (maximum 100 IDs).\n\n**Example response:**\n\n```json\n{\n  \"c5651f8783f64d09985f0dd38359d846\": \"https://cdn.filespin.io/api/v1/files/content/c5651f8783f64d09985f0dd38359d846?key=thumbnail&expiry=1486556379&delivery=display&accessId=IZJTAMBQ...&signature=ScdZeFTEs41edg...\",\n  \"aa2e7cce8a1e479daf5eb94cc413e8cb\": \"https://cdn.filespin.io/api/v1/files/content/aa2e7cce8a1e479daf5eb94cc413e8cb?key=thumbnail&expiry=1486556379&delivery=display&accessId=IZJTAMBQ...&signature=ScdZeFTEs41edg...\"\n}\n```",
        "tags": [
          "Assets - Content Links"
        ],
        "responses": {
          "200": {
            "description": "Successful operation — returns a JSON object mapping each asset ID to its content link URL"
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "parameters": [
          {
            "name": "key",
            "in": "query",
            "description": "`original` or any pre-defined conversion name/key for images and video transcodes. See your Settings for image and video keys.",
            "required": true,
            "example": "original",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "delivery",
            "in": "query",
            "description": "Get a link for display or download. `display` — suitable for embedding in a page. `download` — triggers a file download when clicked. Defaults to `download`.",
            "required": false,
            "example": "download",
            "schema": {
              "type": "string",
              "enum": [
                "display",
                "download"
              ]
            }
          },
          {
            "name": "expiry",
            "in": "query",
            "description": "Seconds after which the link should expire. Defaults to `6000` (10 minutes). Use the special value `MAX` to set expiry to maximum possible (cdn: 19 January 2038, object_storage: 7 days).",
            "required": false,
            "example": "MAX",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "link_type",
            "in": "query",
            "description": "Get CDN link or direct storage link. `cdn` — served via FileSpin CDN, cached at edge. `object_storage` — served directly from storage. Defaults to `cdn`.",
            "required": false,
            "example": "cdn",
            "schema": {
              "type": "string",
              "enum": [
                "cdn",
                "object_storage"
              ]
            }
          },
          {
            "name": "accessId",
            "in": "query",
            "description": "Access ID used to sign URLs. Obtain from your account Authorization Settings page.",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/multiple_asset"
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/assets/search": {
      "post": {
        "summary": "Run Search",
        "operationId": "Search___standard_options_post",
        "description": "Send a HTTP POST request with search criteria to run the search and get first page of results (default 30 per page)\n\n### POST Request JSON\n\nAll parameters are optional. A complete JSON payload for search request below:-\n\n```json\n{\n  \"keyword\": \"sample\",\n  \"ids\": [\"116f6a2a266d45d58d067f7c39a2e4dd\", \"213f7a7a238d45d58d067f7c49a5e4ac\"],\n  \"file_name\": \"test*\",\n  \"content_type\": \"image* OR video* OR audio*\",\n  \"creator_id\": 100,\n  \"upload_time_range\": {\n    \"start\": \"2013-01-01T10:25:11Z\",\n    \"end\": \"2013-02-01T10:25:11Z\"\n  },\n  \"file_size_range\": {\n    \"start\": 10240,\n    \"end\": 402600\n  },\n  \"sort_by\": [\n    \"upload_time_range_DESC\",\n    \"file_size_range_ASC\",\n    \"content_type_DESC\"\n  ],\n  \"limit_per_page\": 30,\n  \"extended_result\": false,\n  \"addons_criteria\": [\"ON_DEMAND_IMAGE\"],\n  \"trashed\": false\n}\n```\n\n| Key                 | Type            | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |\n| ------------------- | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `keyword`           | string          | (optional) Search for keywords (includes keywords added to reserved Asset metadata field `filespin_search_txt` or custom schema fields with `keyword_searchable` set to `true`.  Use `OR` to find assets that match any of the given search words. `john OR doe` will find assets that contain `john` or `doe` in keywords. Use `AND` to find assets that contain both `john` and `doe` in keywords.`OR` and `AND` conditions cannot be used together in a search. `keyword` cannot contain more than 40 words |\n| `ids`               |                 | (optional) A list of asset ids, like `[\"116f6a2a266d45d58d067f7c39a2e4dd\", \"213f7a7a238d45d58d067f7c49a5e4ac\"]` .When sent result will be filtered for assets with these ids. A maximum of 100 ids can be passed.                                                                                                                                                                                                                                                                                              |\n| `file_name`         | string          | (optional) File name, `*` wildcard character is allowed in the suffix. To find multiple types in search supply value separated by `OR`, like `myfile1* OR myfile2*`. Note that `.` is a reserved search character and cannot be used in file name search                                                                                                                                                                                                                                                       |\n| `content_type`      | string          | (optional) File content type type. `*` wildcard is allowed. To find multiple types in search supply value separated by `OR`, like `image* OR video*`                                                                                                                                                                                                                                                                                                                                                           |\n| `creator_id`        | integer         | (optional) Search only the files created by this user. Note that the user calling the API must belong to the same user group as the user id passed                                                                                                                                                                                                                                                                                                                                                             |\n| `upload_time_range` | JSON            | (optional) Like `{\"start\": TIME, \"end\": TIME }` where TIME is an ISO 8601 datetime string, such as \"2013-01-20T15:30:25Z\". Range is inclusive, times will be considered as UTC times                                                                                                                                                                                                                                                                                                                           |\n| `file_size_range`   | JSON            | (optional) Like `{\"start\": SIZE, \"end\": SIZE }` where SIZE is in bytes ( 1 KiB = 1024 bytes, 1 MiB = 1048576 bytes), range is inclusive                                                                                                                                                                                                                                                                                                                                                                        |\n| `limit_per_page`    | integer         | (optional) Limit how many files are returned in a page. Can be from `1` to `30`. Defaults to `30`.                                                                                                                                                                                                                                                                                                                                                                                                             |\n| `sort_by`           | JSON            | (optional) List of key strings. Sort keys can be `file_name`, `content_type`, `upload_time_range` or \"file_size_range\". Append `_ASC` or `_DESC` to the key to sort by ascending or descending order. Example: `[\"upload_time_range_DESC\", \"file_size_range_ASC\"]` will sort by upload_time_range in descending order and within that by ascending file_size. Default sort is by descending order of upload_time_range. If sort_by keys are provided, it will override default sorting.                        |\n| `extended_result`   | boolean         | (optional) Set this to `true` to return extended result which will contain the complete asset data for asset ids returned. Searches with this set to` true` will take longer to run                                                                                                                                                                                                                                                                                                                            |\n| `trashed`           | boolean         | (optional) Set this to `true` to return files that have been deleted (but not purged). Deleted files will not be returned in normal searches. Admin role is required to retrieve deleted assets                                                                                                                                                                                                                                                                                                                |\n| `addons_criteria`   | List of strings | (optional) List of addon IDs to filter the results. Use this list to filter for assets with any of these addons processed successfully. For example, to retrieve assets that have FACE_RECOGNITION addon, use `[\"FACE_RECOGNITION\"]`.  To retrieve assets that have either ON_DEMAND_IMAGE or FACE_RECOGNITION addon, use `[\"ON_DEMAND_IMAGE\",\"FACE_RECOGNITION\"]`.                                                                                                                                            |\n\nFor advanced search techniques including exact match, special characters, custom schema fields, range queries, and tips, see [Advanced Search Options](https://developers.filespin.io/api-reference/asset-search/advanced-search-options).\n\n### HTTP Response\n\nHTTP Status code and JSON response like below.\n\n```json\n//Response JSON with {Asset Data}\n{\n    \"status\": \"OK\",\n    \"search_result_id\": \"0a9761f2f9\",\n    \"total_files\": 1,\n    \"page\": 1,\n    \"total_pages\": 1,\n    \"result\": [\"116f6a2a266d45d58d067f7c39a2e4dd\"],\n    \"extended_result\": {\n       \"116f6a2a266d45d58d067f7c39a2e4dd\": {Asset Data}\n    }\n}\n```\n\nAsset Data is as specified in [Asset Data Format](https://developers.filespin.io/api/asset-data-format) - the JSON format used across all Asset API responses.\n\n| Key                | Value   | Description                                                                                                                                                           |\n| ------------------ | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `status`           | string  | `OK` if search was successful, `ERROR` otherwise                                                                                                                      |\n| `search_result_id` | string  | An alphanumeric value between `10` and `32` characters, valid 60 minutes from time of API call                                                                        |\n| `total_files`      | integer | Total number of files found for the search. Note that there may be more than one page of results if there are more than 100 files in result                           |\n| `page`             | integer | Index of currently returned result page, always less than or equal to `total_pages`                                                                                   |\n| `total_pages`      | integer | Total number of pages in the search result                                                                                                                            |\n| `result`           | JSON    | List of `file ids`. Defaults to 30 ids per page. The actual count returned may vary but will not exceed 30 depending on asset activity at the time the API is called. |\n| `extended_result`  | JSON    | A dictionary containing the current data for each file id returned in result. Data for each file follows [Asset Data Format](https://developers.filespin.io/api/asset-data-format) JSON     |\n\n> **Warning:** The number of result pages that can be retrieved is limited to 10,000 assets. If there are more than 10,000 hits, we recommend that you use additional search parameters such as `upload_time_range` to limit the results.",
        "tags": [
          "Search"
        ],
        "responses": {
          "200": {
            "description": "Successful operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SearchRequest"
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/assets/search/{search_id}/{page}": {
      "get": {
        "summary": "Retrieve Result Pages",
        "operationId": "retrieveSearchResultPages_get",
        "description": "### Request Query Parameters\n\n| Parameter          | Type    | Description                                                                                                      |\n| ------------------ | ------- | ---------------------------------------------------------------------------------------------------------------- |\n| `SEARCH_RESULT_ID` | string  | The `SEARCH_RESULT_ID` returned in the HTTP POST call                                                            |\n| `PAGE_NO`          | integer | Index of result page requested, should be less than or equal to the `total pages` returned in the HTTP POST call |\n\nThe HTTP GET response JSON is the same as for HTTP POST that provides one page of search result.",
        "tags": [
          "Search"
        ],
        "responses": {
          "200": {
            "description": "Successful operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "parameters": [
          {
            "name": "search_id",
            "in": "path",
            "required": true,
            "description": "Search result set identifier for pagination",
            "schema": {
              "type": "string"
            },
            "example": "abc123"
          },
          {
            "name": "page",
            "in": "path",
            "required": true,
            "description": "Page number for paginated results",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/assets/{asset_id}/content/original/duplicates": {
      "get": {
        "summary": "Find Duplicates (by checksum)",
        "operationId": "find_duplicates_get",
        "description": "Retrieve duplicates of an asset original file by checking for the Asset file's MD5 checksum.\n\n> **Note:** This API will identify duplicates even if the original file name of assets are different.\n\n### RESPONSE JSON\n\n**Example response**\n\n```json\n{\n  \"id\": \"99d819953914402babbdeb68337ea6a3\",\n  \"name\": \"example.jpg\",\n  \"size\": 8836363,\n  \"content_type\": \"image/jpeg\",\n  \"checksum\": \"5f5f26bd7c0f62c6e02e44c73d09734e\",\n  \"total_files\": 2,\n  \"total_pages\": 1,\n  \"page\": 1,\n  \"duplicates\": [\n    \"425f6a2a266d45d58d067f7c39a2e4bd\",\n    \"a563da2a266d45d58d067b8c39a3d5ad\"\n  ]\n}\n```\n\n| Key            | Value   | Description                                                                                                                                                                                          |\n| -------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `id`           | string  | File's unique ID, 32 character alphanumeric UUID                                                                                                                                                     |\n| `name`         | string  | File name                                                                                                                                                                                            |\n| `size`         | integer | Size of file in bytes                                                                                                                                                                                |\n| `checksum`     | string  | MD5 checksum                                                                                                                                                                                         |\n| `content_type` | string  | MIME type                                                                                                                                                                                            |\n| `duplicates`   | JSON    | List of file ids whose MD5 checksum is the same as the asset id. Defaults to 30 `duplicates` per page. The actual count returned may vary depending on asset activity at the time the API is called. |\n| `total_files`  | integer | Number of duplicate files found                                                                                                                                                                      |\n| `total_pages`  | integer | Number of pages in result.                                                                                                                                                                           |\n| `page`         | integer | Current page of the result. Defaults to 1.                                                                                                                                                           |",
        "tags": [
          "Search"
        ],
        "responses": {
          "200": {
            "description": "Successful operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DuplicatesResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "parameters": [
          {
            "name": "asset_id",
            "in": "path",
            "required": true,
            "description": "Unique 32-character hex identifier of the asset",
            "schema": {
              "type": "string"
            },
            "example": "a211ab5f351f4b398426efb59b0c72a3"
          }
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/assets/{asset_id}/process": {
      "post": {
        "summary": "Process",
        "operationId": "process_post",
        "description": "Assets can be processed for image transformations, video transcodes and other custom workflows using `/process` API.\n\nThe `/process` API is useful in the following scenarios:-\n\n* Create static image conversions that are not covered by On-demand Image Conversion\n* Re-process a static image conversion to apply a new watermark\n* Re-process an image if there are any on-demand image conversion errors\n* Generate standard video transcodes that do not exist for a video file\n* Re-apply a new watermark to existing video transcodes\n\n**Built-in Image processing keys**\n\n| Key             | Description                                                  |\n| --------------- | ------------------------------------------------------------ |\n| `smart_imaging` | Used for on-demand images and image annotation re-processing |\n\nAlso, once processing completes, Asset Data JSON will contain process state for `smart_imaging` as below:\n\n```json\n\"addons_info\": {\n    \"ON_DEMAND_IMAGE\": {\n      \"available\": true\n    }\n  }\n```\n\n**Built-in Video processing keys**\n\n* Built-in keys that correspond to video quality and sizes: `360p-video`, `480p-video`, `720p-video`, `1080p-video`, `hls-video`\n* Watermarked transcodes: `360p-wm-video`, `480p-wm-video`,`720p-wm-video`,`1080p-wm-video`\n\n> **Warning:** For `hls-video` transcode, the source video must be equal or greater than 360 px in height. If a source video smaller than 360 px in height, please enable `UPSCALE` option in Video Settings for `hls-video` to generate HLS transcodes. In general, you do not need a HLS video transcode for a video that is small as there is no bandwidth benefit for small videos.\n\n**Special video processing keys**\n\n| Key            | Description                                                                                                                         |\n| -------------- | ----------------------------------------------------------------------------------------------------------------------------------- |\n| `clip_preview` | Generate a preview clip of the video using user's settings profile                                                                  |\n| `storyboard`   | Generate a set of storyboard images for the video using user's video settings profile. `STORYBOARD` addon must be enabled for this. |\n\nNote:\n\n1. That unknown keys and keys that do not apply to the file type will be ignored.\n2. This API returns job ID only for videos.\n\n> **Note:** Once a image/video conversion is processed, callbacks are issued to registered webhooks.\n\n### HTTP Response\n\nStandard HTTP Status code - 202 or 200\n\n| Key       | Value   | Description                                                                                              |\n| --------- | ------- | -------------------------------------------------------------------------------------------------------- |\n| `status`  | string  | Status of the process. Can be `QUEUED` or `ERROR`                                                        |\n| `message` | string  | Message describing the status                                                                            |\n| `job_id`  | integer | Job ID of the process. Can be used to query the status of job using [Job Status API] |",
        "tags": [
          "Asset Processing"
        ],
        "responses": {
          "200": {
            "description": "Successful operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProcessingResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "requestBody": {
          "$ref": "#/components/requestBodies/process"
        },
        "parameters": [
          {
            "name": "asset_id",
            "in": "path",
            "required": true,
            "description": "Unique 32-character hex identifier of the asset",
            "schema": {
              "type": "string"
            },
            "example": "a211ab5f351f4b398426efb59b0c72a3"
          }
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/assets/content/original/reprocess": {
      "post": {
        "summary": "Process (bulk)",
        "operationId": "Batch_Process_post",
        "description": "The asset batch processing API is useful in the following scenarios:-\n\n* process multiple assets to apply updated watermark\n* process multiple assets to create a specific conversion, transcode or addon\n\n> **Warning:** This API is available for users with ADMIN role. Users with other roles will be denied access.\n\n### REQUEST JSON BODY\n\n```json\n{\n        \"ids\": [\n           \"7204fbc866d94805ad3fab3e1a194abd\"\n        ],\n       \"conversions\": [\"smart_imaging\"],\n       \"transcodes\": [\"480p-video\"],\n       \"addons\": [\"storyboard\"]\n}\n```\n\n**Note:**\n\n* A maximum of 100 assets can be re-processed in one API call\n* If `conversions`, `transcodes` or `addons` are all empty, or not provided, all conversions, transcodes and addons enabled in caller's account settings will be re-processed.\n* Unknown keys in `conversions`, `transcodes` or `addons` and keys that do not apply to the file type will be ignored.\n\n| Parameter     | Description                                                                                                                                                             |\n| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `ids`         | Asset Ids of assets that should be re-processed                                                                                                                         |\n| `conversions` | (optional) List of conversion keys such as deepzoom. See [Asset Processing API] for keys                                                                                |\n| `transcodes`  | (optional) List of transcode keys such as 480p-video. See [Asset Processing API] for keys                                                                               |\n| `addons`      | (optional) List of addon keys such as storyboard. Addon must be available and enabled in the caller's account. See specific addon in [Addons section](#addons-amp-addon-api) for keys |\n\n### HTTP RESPONSE\n\nStandard HTTP Status codes",
        "tags": [
          "Asset Processing"
        ],
        "responses": {
          "200": {
            "description": "Successful operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProcessingResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchProcessRequest"
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/assets/{asset_id}/clip/process": {
      "post": {
        "summary": "Transcode/Clip Create",
        "operationId": "Transcode_Clip_Create_post",
        "description": "You can make use of `/clip/process` API to create custom transcodes to :-\n\n* create a clip from specific section of a video\n* add a custom watermark to a video other than the default watermark\n\nThe transcode output will be added as a conversion to the asset and stored in Video transcodes bucket specified in account settings. Webhook callback will be issued once output is created.\n\n### REQUEST JSON\n\n| Key                   | Value                      | Description                                                                                                                                                                                                                                                            |\n| --------------------- | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `name`                | string                     | Conversion name. The transcode output will be named as `name.mp4`, like `clip_sample.mp4`                                                                                                                                                                              |\n| `preset`              | string                     | Any of the standard video transcode keys `360p-video`, `360p-wm-video`, `480p-video`, `480p-wm-video`, `720p-video`, `720p-wm-video`, `1080p-video`, `1080p-wm-video`                                                                                                  |\n| `start`               | integer or timecode string | (optional) Defaults to `0`. Seconds into the video for clip start.                                                                                                                                                                                                     |\n| `length`              | integer                    | (optional) Defaults to entire video. Length of clip in seconds                                                                                                                                                                                                         |\n| `public`              | boolean                    | (optional) Defaults to `false`. Make the output file public in Storage to allow playback using /transcodes API without signed URL                                                                                                                                      |\n| `aspect`              | string                     | (optional) Defaults to \"pad\". Determines aspect and padding. Can be `\"pad\"` - to add padding, `\"preserve\"` - preserves original aspect ratio, padding color will be ignored, `\"scale\"` - scales the output, `\"crop\"` - crops the output to match requested dimensions. |\n| `padding`             | string                     | (optional) Defaults to `000000` - black. Padding color. Applies only when aspect is \"pad\". Value is a six character colorcode such as `000000` - black, `ffffff` - white, etc.                                                                                         |\n| `upscale`             | boolean                    | (optional) Defaults to `false`. Upscale the output if original is of lower size than requested output size.                                                                                                                                                            |\n| `watermark`           | object                     | (optional) Defaults to `null`. Add a watermark to the output. See below for details.                                                                                                                                                                                   |\n| `watermark.url`       | string                     | (required) URL of the watermark image. Can be a public URL or an on-demand image URL of an asset in your account                                                                                                                                                       |\n| `watermark.placement` | string                     | (optional) Defaults to account watermark setting. Position of the watermark. Can be `top-left`, `top-right`, `bottom-left`, `bottom-right` or `center`                                                                                                                 |\n| `watermark.scale`     | float                      | (optional) Defaults to account watermark setting. Scale of the watermark. Can range from `0` to `1`. `0.1` will scale the watermark to 10% of the output video size and place it at the specified placement, `0.5` will scale it to 50% of output video size.          |\n\n> **Warning:** If name provided is the same as an existing conversion name, the existing conversion will be overwritten. For example, if asset already has a `480p-video` conversion and this API is called with name set to `480p-video`, the existing conversion will be overwritten by the output of this processing.\n\nNote:\n\n* Transcode output will be added to Asset as a Conversion automatically using the given `name` key\n* Transcode output details can be retrieved using the `Get Data` API (see Asset Data Storyboard JSON example)\n* Transcode output is stored in Video Transcodes storage bucket specified in account settings\n\n> **Note:** Once a processing completes, callbacks are issued to registered webhooks.\n\n### HTTP RESPONSE\n\nStandard HTTP Status code - 202 or 200 and JSON response body as below:-\n\n```json\n{\n    \"status\": \"QUEUED\",\n    \"message\": \"Job queued\",\n    \"job_id\": 42\n}\n```\n\n| Key       | Value   | Description                                                                                              |\n| --------- | ------- | -------------------------------------------------------------------------------------------------------- |\n| `status`  | string  | Status of the process. Can be `QUEUED` or `ERROR`                                                        |\n| `message` | string  | Message describing the status                                                                            |\n| `job_id`  | integer | Job ID of the process. Can be used to query the status of job using [Job Status API] |",
        "tags": [
          "Asset Processing"
        ],
        "responses": {
          "200": {
            "description": "Successful operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProcessingResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ClipCreateRequest"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "asset_id",
            "in": "path",
            "required": true,
            "description": "Unique 32-character hex identifier of the asset",
            "schema": {
              "type": "string"
            },
            "example": "a211ab5f351f4b398426efb59b0c72a3"
          }
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/assetschemas": {
      "get": {
        "summary": "List Asset Schemas",
        "operationId": "listAssetSchemas_get",
        "description": "Retrieve all Asset Schema definitions available.\n\n### HTTP RESPONSE\n\n| Parameter | Type   | Description                                                                                                                      |\n| --------- | ------ | -------------------------------------------------------------------------------------------------------------------------------- |\n| `status`  | string | `OK` or `ERROR`                                                                                                                  |\n| `data`    | JSON   | List of `{Asset Schema JSON}` definitions as specified in  [Asset Schema JSON Format] |\n\n### Response JSON\n\n```json\n{\n\n  \"status\": \"OK\",\n  \"data\": [ {Asset Schema JSON} ]\n\n}\n```",
        "tags": [
          "Asset Schemas"
        ],
        "responses": {
          "200": {
            "description": "List of asset schemas"
          },
          "401": {
            "description": "Unauthorized"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      },
      "post": {
        "summary": "Create Asset Schema",
        "operationId": "createAssetSchema_post",
        "description": "Create a new Asset Schema definition.\n\n> **Note:** When creating custom schema, please follow these guidelines to get the best performance:-\n>\n> * Limit maximum size of a text field to 1000 characters, particularly fields marked as `searchable`\n> * Limit maximum metadata JSON payload per asset to 3000 characters\n\n> **Warning:** Do not provide `id` when creating a schema — it is assigned by the server.\n\n> **Info:** Creating schemas requires the `SCHEMA_ADMIN` permission. Typically, only ADMIN users have this.\n\n## Designing a custom schema\n\nA schema has `name`, `status`, and a `schema` object with JSON Schema properties. Each property uses `filespin_properties` for UI and search behavior.\n\n### Supported field types\n\n| Type | Example |\n|------|---------|\n| `string` | `\"type\": \"string\", \"maxLength\": 500` |\n| `string` (email) | `\"type\": \"string\", \"format\": \"email\"` |\n| `string` (date) | `\"type\": \"string\", \"format\": \"date\"` (YYYY-MM-DD) |\n| `enum` | `\"type\": \"string\", \"enum\": [\"draft\", \"approved\"]` |\n| `array` | `\"type\": \"array\", \"items\": {\"type\": \"string\"}` |\n| `number` | `\"type\": \"number\"` |\n| `boolean` | `\"type\": \"boolean\"` |\n\n### filespin_properties\n\n| Property | Effect |\n|----------|--------|\n| `searchable` | Field is included in full-text search |\n| `keyword_searchable` | Field contributes to keyword search |\n| `ui.order` | Display order in forms (lower numbers first) |\n| `ui.multiline` | Render as text area instead of single-line input |\n| `ui.hidden` | Don't show in the form |\n\n### Request body example\n\n```json\n{\n  \"name\": {\"en\": \"Product Assets\"},\n  \"status\": \"ACTIVE\",\n  \"schema\": {\n    \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n    \"type\": \"object\",\n    \"properties\": {\n      \"product_name\": {\n        \"type\": \"string\",\n        \"maxLength\": 200,\n        \"filespin_properties\": {\n          \"title\": {\"en\": \"Product Name\"},\n          \"searchable\": true,\n          \"keyword_searchable\": true,\n          \"ui\": {\"order\": 1}\n        }\n      },\n      \"sku\": {\n        \"type\": \"string\",\n        \"maxLength\": 50,\n        \"filespin_properties\": {\n          \"title\": {\"en\": \"SKU\"},\n          \"searchable\": false,\n          \"ui\": {\"order\": 2}\n        }\n      },\n      \"category\": {\n        \"type\": \"string\",\n        \"enum\": [\"clothing\", \"accessories\", \"footwear\", \"electronics\"],\n        \"filespin_properties\": {\n          \"title\": {\"en\": \"Category\"},\n          \"searchable\": false,\n          \"ui\": {\"order\": 3}\n        }\n      },\n      \"tags\": {\n        \"type\": \"array\",\n        \"items\": {\"type\": \"string\", \"maxLength\": 100},\n        \"filespin_properties\": {\n          \"title\": {\"en\": \"Tags\"},\n          \"searchable\": true,\n          \"keyword_searchable\": true,\n          \"ui\": {\"order\": 4}\n        }\n      }\n    }\n  }\n}\n```\n\n### Response\n\nReturns the ID of the newly created schema:\n\n```json\n{\n  \"id\": 3\n}\n```\n\nFor assigning schemas to assets, search integration, and best practices, see [Organizing Assets with Custom Metadata Schemas](https://developers.filespin.io/guides/asset-schemas).",
        "tags": [
          "Asset Schemas"
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/create"
        },
        "responses": {
          "200": {
            "description": "Schema created successfully"
          },
          "400": {
            "description": "Invalid schema definition"
          },
          "401": {
            "description": "Unauthorized"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/assetschemas/{schema_id}": {
      "get": {
        "summary": "Get Asset Schema",
        "operationId": "getAssetSchema_get",
        "description": "Retrieve an Asset Schema definition.\n\n### HTTP Response\n\nHTTP Status code and JSON response with Asset Schema definition. See [Asset Schema JSON Format]",
        "tags": [
          "Asset Schemas"
        ],
        "parameters": [
          {
            "name": "schema_id",
            "in": "path",
            "required": true,
            "description": "Numeric identifier of the asset schema",
            "schema": {
              "type": "integer"
            },
            "example": 563
          }
        ],
        "responses": {
          "200": {
            "description": "Asset schema details"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Schema not found"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      },
      "put": {
        "summary": "Update Asset Schema",
        "operationId": "updateAssetSchema_put",
        "description": "Update an existing Asset Schema definition.\n\n> **Warning:** Built-in Asset Schema (Schema ID 0) cannot be updated using this API.\n\n### What you CAN change\n\n- Add new fields — existing assets won't have values for these fields, which is fine\n- Increase `maxLength` for text fields — makes the field accept longer values\n\n### What you SHOULD NOT change\n\n- Field types — can't change a string to a number\n- Search properties (`keyword_searchable`, `searchable`) — would require re-indexing\n- Remove fields — would orphan existing data\n- Rename fields — same as remove + add, breaks existing data\n- Decrease `minLength` — would invalidate previously valid data\n\n> **Tip:** Since you can't change field types or search properties, plan your schema carefully before creating it. If you need incompatible changes, create a new schema and migrate assets gradually. After migration, deactivate the old schema by setting `status: \"INACTIVE\"`.\n\nFor more on schema versioning and soft-delete, see [Organizing Assets with Custom Metadata Schemas](https://developers.filespin.io/guides/asset-schemas).\n\n### Request Body JSON\n\nInclude `id` of the Asset Schema to be updated in the request payload:-\n\n```json\n{\n  \"id\": 26,\n  \"name\": {\n    \"en\": \"My Asset Schema\"\n  },\n  \"status\": \"ACTIVE\",\n  \"schema\": {\n    \"$id\": \"https://app.filespin.io/api/v1/json-schema/Asset/CustomMetadata.v1.schema.json\",\n    \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n    \"type\": \"object\",\n    \"title\": \"My Asset Metadata\",\n    \"required\": [],\n    \"properties\": {\n      \"email\": {\n        \"title\": \"An Email\",\n        \"type\": \"string\",\n        \"format\": \"email\",\n        \"minLength\": 5,\n        \"maxLength\": 200,\n        \"filespin_properties\": {\n          \"title\": {\n            \"en\": \"an email\"\n          },\n          \"hint\": {\n            \"en\": \"an email\"\n          },\n          \"placeholder\": {\n            \"en\": \"an email\"\n          },\n          \"searchable\": true,\n          \"keyword_searchable\": false,\n          \"ui\": {\n            \"order\": 4,\n            \"readonly\": false,\n            \"disabled\": false,\n            \"hidden\": false\n          }\n        }\n      }\n    }\n  }\n}\n```\n\n\n### Response\n\nReturns HTTP 200 on success. The response body is the updated schema definition.",
        "tags": [
          "Asset Schemas"
        ],
        "parameters": [
          {
            "name": "schema_id",
            "in": "path",
            "required": true,
            "description": "Numeric identifier of the asset schema",
            "schema": {
              "type": "integer"
            },
            "example": 563
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/update"
        },
        "responses": {
          "200": {
            "description": "Schema updated successfully"
          },
          "400": {
            "description": "Invalid schema definition"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Schema not found"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      },
      "delete": {
        "summary": "Delete Asset Schema",
        "operationId": "deleteAssetSchema_delete",
        "description": "Delete an asset schema by its ID. Consider deactivating the schema instead of deleting it to prevent orphaned data.",
        "tags": [
          "Asset Schemas"
        ],
        "parameters": [
          {
            "name": "schema_id",
            "in": "path",
            "required": true,
            "description": "Numeric identifier of the asset schema",
            "schema": {
              "type": "integer"
            },
            "example": 563
          }
        ],
        "responses": {
          "200": {
            "description": "Schema deleted successfully"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Schema not found"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/assetschemas/presets": {
      "get": {
        "summary": "List Schema Presets",
        "operationId": "listSchemaPresets_get",
        "description": "Retrieve a list of available asset schema presets. Presets are pre-configured schema templates for common use cases.\n\n### Available presets\n\n| Preset | Fields | Best for |\n|--------|--------|----------|\n| Marketing | 19 | Campaign tracking, brand assets, channel distribution |\n| E-Commerce & Retail | 23 | Product catalogs, SKU tracking, seasonal collections |\n| Events & Conferences | 21 | Session/speaker tracking, sponsor assets |\n| Attractions & Experiences | 19 | Venue management, guest photos |\n| Hospitality & Travel | 20 | Hotel/venue assets, seasonal campaigns |\n| Fashion & Apparel | 21 | Collections, style tracking, lookbooks |\n\n### Using presets\n\nPresets are available for immediate use. Reference the preset ID when creating a schema or assigning metadata. For example, use `ecommerce` to tag assets with product-specific fields like SKU, category, and season. Each preset includes common fields (title, description, tags, status, project) plus industry-specific fields. You can customize them after creation.\n\nFor the full workflow, see [Organizing Assets with Custom Metadata Schemas](https://developers.filespin.io/guides/asset-schemas).",
        "tags": [
          "Asset Schemas"
        ],
        "responses": {
          "200": {
            "description": "List of available schema presets"
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/assetschemas/presets/{preset_id}": {
      "get": {
        "summary": "Get Schema Preset",
        "operationId": "getSchemaPreset_get",
        "description": "Retrieve a specific asset schema preset by its identifier.",
        "tags": [
          "Asset Schemas"
        ],
        "parameters": [
          {
            "name": "preset_id",
            "in": "path",
            "required": true,
            "description": "The preset identifier (e.g. ecommerce, marketing, real-estate)",
            "schema": {
              "type": "string"
            },
            "example": "ecommerce"
          }
        ],
        "responses": {
          "200": {
            "description": "Schema preset details"
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "404": {
            "description": "Preset not found"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/assetcollections": {
      "get": {
        "summary": "Get All Collections",
        "operationId": "get_all_collections_get",
        "description": "Retrieve Collections upto a maximum of 30. For retrieving additional collections, use the Collection Search API with pagination.\n\n### HTTP RESPONSE\n\n| Parameter                | Type    | Description                                                                            |\n| ------------------------ | ------- | -------------------------------------------------------------------------------------- |\n| `status`                 | string  | `OK` or `ERROR`                                                                        |\n| `data.total_collections` | integer | Total number of collections, includes private and group collections user has access to |\n| `data.collections`       | JSON    | List of Collections in `Asset Collection JSON` format                                  |\n\n### Response JSON\n\n```json\n{\n  \"status\": \"OK\",\n  \"data\": {\n    \"total_collections\": 1,\n    \"collections\": [\n      {COLLECTION_JSON}\n    ]\n  }\n}\n```",
        "tags": [
          "Collections"
        ],
        "responses": {
          "200": {
            "description": "Successful operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CollectionListResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      },
      "post": {
        "summary": "Search Collections",
        "operationId": "search_collections_post",
        "description": "Search and retrieve Collections with pagination. Use the `total_collections` and `limit` to calculate `offset` to paginate.\n\n### REQUEST JSON\n\nThe request payload JSON keys are as below. Although all parameters are optional, atleast one parameter must be passed to get useful results. We suggest sending ` { \"sort_by\": [\"last_update DESC\"] }`\n\n| Parameter            | Type    | Description                                                                                                                                                                                                                                                                                                                                                    |\n| -------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `keyword `           | string  | (optional) Keyword to search with. Keyword will match any word in Collection `name`. Defaults to empty string (equivalent to `*` wildcard)                                                                                                                                                                                                                     |\n| `private_only `      | boolean | (optional) `true` if only private collections should be returned. Defaults to `false`                                                                                                                                                                                                                                                                          |\n| `last_update_range ` | JSON    | (optional) Like `{\"start\": \"2022-03-18T01:01:01Z\", \"end\": \"2022-04-24T01:01:01Z\"}` where the dates are ISO 8601 datetime format values                                                                                                                                                                                                                         |\n| `sort_by`            | JSON    | (optional) Example: `[\"group_access ASC\", \"name ASC\", \"last_update DESC\"]` where `group_access`,`name`, `last_update` are the only allowed sort fields. `ASC`is for ascending natural sort order,`DESC` is for descending natural sort order. To sort by `group_access`, then `name` and then by `last_update`, list them in sequence as in the example above. |\n| `offset `            | integer | (optional) Offset for paging. Defaults to `0`. If `limit` is 30, to retrieve second   page, set `offset` to `30`, for third page set `offset` to `60`, etc                                                                                                                                                                                                     |\n| `limit `             | integer | (optional) Page limit. Defaults to `30`. Maximum is `30`.                                                                                                                                                                                                                                                                                                      |\n\n### HTTP RESPONSE\n\nSame as /api/v1/collections response.",
        "tags": [
          "Collections"
        ],
        "responses": {
          "200": {
            "description": "Successful operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CollectionListResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CollectionSearchRequest"
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/assetcollection/{collection_id}": {
      "get": {
        "summary": "Get Collection",
        "operationId": "get_collection_get",
        "description": "Retrieve a Collection.\n\n> **Note:** When no Collection ID is passed, the API returns the Default Basket Collection. Basket Collection name is always SELECTED\\_ASSETS. Basket is a special collection whose name, description and group\\_access cannot be updated.\n\n### HTTP RESPONSE\n\n| Parameter | Type   | Description                                    |\n| --------- | ------ | ---------------------------------------------- |\n| `status`  | string | `OK` or `ERROR`                                |\n| `data`    | JSON   | Collection in `Asset Collection JSON` format   |\n\n### Response JSON\n\n```json\n{\n  \"status\": \"OK\",\n  \"data\": {\n    \"id\": 21,\n    \"user_id\": 45,\n    \"name\": \"SELECTED_ASSETS\",\n    \"description\": \"\",\n    \"last_update\": \"2022-01-24T09:11:05Z\",\n    \"assets\": [\"3b5123160c474720931292c33eb46c52\"],\n    \"group_access\": false,\n    \"user_name\": \"John Doe\",\n    \"user_email\": \"john@example.org\",\n    \"extended_result\": {}\n  }\n}\n```",
        "tags": [
          "Collections"
        ],
        "responses": {
          "200": {
            "description": "Successful operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CollectionData"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "parameters": [
          {
            "name": "collection_id",
            "in": "path",
            "required": true,
            "description": "Identifier of the asset collection",
            "schema": {
              "type": "string"
            },
            "example": "1"
          }
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      },
      "patch": {
        "summary": "Update Collection",
        "operationId": "update_collection_patch",
        "description": "Update a Collection with partial data. At least one of `name`, `description`, `group_access`, `additions`, `deletions`, or `source_id` must be provided.\n\n> **Note:** The default Basket collection (`SELECTED_ASSETS`) cannot have its name, description, or group access updated.\n\n### REQUEST PARAMETERS\n\n| Parameter      | Type    | Description                                                                                          |\n| -------------- | ------- | ---------------------------------------------------------------------------------------------------- |\n| `name`         | string  | (optional) New collection name                                                                       |\n| `description`  | string  | (optional) New collection description                                                                |\n| `group_access` | boolean | (optional) `true` to share with group, `false` for private                                           |\n| `additions`    | array   | (optional) List of asset IDs to add to the collection                                                |\n| `deletions`    | array   | (optional) List of asset IDs to remove from the collection                                           |\n| `source_id`    | integer | (optional) Collection ID whose assets will be merged into `additions`                                |\n\n### REQUEST JSON\n\n```json\n{\n  \"name\": \"Updated Collection Name\",\n  \"description\": \"New description\",\n  \"group_access\": true,\n  \"additions\": [\"b3ad7854e1ad4ce8a8c83272447f980b\"],\n  \"deletions\": [\"caf2b5f2e80a40729e32489ee65ef0d8\"]\n}\n```\n\n### HTTP RESPONSE\n\n| Parameter | Type   | Description                                  |\n| --------- | ------ | -------------------------------------------- |\n| `status`  | string | `OK` or `ERROR`                              |\n| `data`    | JSON   | Collection in `Asset Collection JSON` format |\n\n### Response JSON\n\n```json\n{\n  \"status\": \"OK\",\n  \"data\": {\n    \"id\": 21,\n    \"user_id\": 45,\n    \"name\": \"Updated Collection Name\",\n    \"description\": \"New description\",\n    \"last_update\": \"2025-01-24T09:11:05Z\",\n    \"assets\": [\"b3ad7854e1ad4ce8a8c83272447f980b\"],\n    \"group_access\": true,\n    \"user_name\": \"John Doe\",\n    \"user_email\": \"john@example.org\",\n    \"extended_result\": {}\n  }\n}\n```",
        "tags": [
          "Collections"
        ],
        "responses": {
          "200": {
            "description": "Successful operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CollectionData"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "requestBody": {
          "$ref": "#/components/requestBodies/update_collection"
        },
        "parameters": [
          {
            "name": "collection_id",
            "in": "path",
            "required": true,
            "description": "Identifier of the asset collection",
            "schema": {
              "type": "string"
            },
            "example": "1"
          }
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      },
      "put": {
        "summary": "Replace/Clear Collection",
        "operationId": "replace_clear_collection_put",
        "description": "## Replace assets\n\nReplace existing assets in a Collection with a new list of assets.\n\n### REQUEST PARAMETERS\n\n| Parameter | Type | Description                         |\n| --------- | ---- | ----------------------------------- |\n| `assets`  | JSON | List of Collection id to be updated |\n\n### REQUEST JSON\n\n```json\n{\n \"assets\": [\"b3ad7854e1ad4ce8a8c83272447f980b\"]\n}\n```\n\n## Clear assets\n\nClear all Assets from a Collection by putting an empty list of assets.\n\n### REQUEST JSON\n\n```json\n{\n \"assets\": []\n}\n```\n\n### HTTP RESPONSE\n\nStandard HTTP Codes",
        "tags": [
          "Collections"
        ],
        "responses": {
          "200": {
            "description": "Successful operation"
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CollectionCreateRequest"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "collection_id",
            "in": "path",
            "required": true,
            "description": "Identifier of the asset collection",
            "schema": {
              "type": "string"
            },
            "example": "1"
          }
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      },
      "delete": {
        "summary": "Delete Collection",
        "operationId": "delete_collection_delete",
        "description": "Delete a Collection\n\n### HTTP RESPONSE\n\nStandard HTTP Codes",
        "tags": [
          "Collections"
        ],
        "responses": {
          "200": {
            "description": "Successful operation"
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "requestBody": {
          "$ref": "#/components/requestBodies/delete_collection"
        },
        "parameters": [
          {
            "name": "collection_id",
            "in": "path",
            "required": true,
            "description": "Identifier of the asset collection",
            "schema": {
              "type": "string"
            },
            "example": "1"
          }
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/assetcollection": {
      "post": {
        "summary": "Create Collection",
        "operationId": "create_collection_post",
        "description": "## Create\n\nCreate a new Asset Collection\n\n> **Note:** A collection can have a maximum of 300 assets.\n\n### REQUEST PARAMETERS\n\n| Parameter      | Type    | Description                                                 |\n| -------------- | ------- | ----------------------------------------------------------- |\n| `name`         | string  | Collection name. Defaults `Collection {timestamp}`          |\n| `assets`       | JSON    | List of asset ids. Defaults to empty list                   |\n| `description`  | string  | (optional) Collection description. Defaults to empty string |\n| `group_access` | boolean | (optional) `true` or `false`. Defaults to `false`           |\n\n### REQUEST JSON\n\n```json\n{  \"name\": \"Test Collection\",\n   \"assets\": [\"b3ad7854e1ad4ce8a8c83272447f980b\",\"caf2b5f2e80a40729e32489ee65ef0d8\"]\n}\n```\n\n### HTTP RESPONSE\n\nCollection in `Asset Collection JSON` format\n\n## Duplicate\n\nDuplicate an Asset Collection\n\nInclude Source Collection id `source_id` to duplicate\n\n### REQUEST PARAMETERS\n\n| Parameter       | Type    | Description                                                                                                                  |\n| --------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------- |\n| `source_id`     | number  | Source Collection id to duplicate                                                                                            |\n| `name`          | string  | (optional) Collection name. Defaults to Source Collection Name formatted as `Copy of {Source Collection Name} @ {timestamp}` |\n| `description `  | string  | (optional) Collection description. Defaults to source collection description                                                 |\n| `group_access ` | boolean | (optional) `true` or `false`. Defaults to `false`                                                                            |\n\n### REQUEST JSON\n\n```json\n{\n\"source_id\": 1,\n\"name\": \"My Collection\",\n\"description\": \"a description\",\n\"group_access\": false\n}\n```\n\n### HTTP RESPONSE\n\nCollection in Asset Collection JSON format.",
        "tags": [
          "Collections"
        ],
        "responses": {
          "200": {
            "description": "Successful operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CollectionData"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CollectionCreateRequest"
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/assetcollection/{collection_id}/download": {
      "get": {
        "summary": "Download Collection",
        "operationId": "download_collection_get",
        "description": "Download assets in a Collection as a zip file or retrieve a downloadable URL (URL will expire in 10 minutes).\n\n### Note\n\n* If `as_url` parameter is set to `y`, the response body contains the download URL. Example: `/api/v1/assetcollection/1/download?as_url=y`\n* If `as_url` parameter is not set, download will start immediately. Download will be a zip file with `Content-Disposition` header set to `attachment; filename=\"download.zip\"`.\n* If there are no assets to be downloaded in a collection the API returns `400` `Bad request`.\n\n> **Warning:** When `as_url=y`, the download URL expires in 10 minutes — the download must be started within 10 minutes of the URL creation time.",
        "tags": [
          "Collections"
        ],
        "responses": {
          "200": {
            "description": "Successful operation"
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "parameters": [
          {
            "name": "collection_id",
            "in": "path",
            "required": true,
            "description": "Identifier of the asset collection",
            "schema": {
              "type": "string"
            },
            "example": "1"
          },
          {
            "name": "as_url",
            "in": "query",
            "required": false,
            "description": "Set to `y` to receive a download URL instead of starting the download directly. The URL expires in 10 minutes.",
            "schema": {
              "type": "string",
              "enum": [
                "y"
              ]
            },
            "example": "y"
          }
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/account": {
      "get": {
        "summary": "User Account",
        "operationId": "User_Account_get",
        "description": "A user can retrieve their own data using this API.\n\n### RESPONSE JSON\n\nAs defined in [User Profile JSON Format](https://developers.filespin.io/api-reference/user/user-api-introduction#user-profile-json-format) section.",
        "tags": [
          "Users & Settings"
        ],
        "responses": {
          "200": {
            "description": "Successful operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserProfile"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/users": {
      "get": {
        "summary": "Retrieve Users",
        "operationId": "retrieve_users_get",
        "description": "User Administrator can retrieve all users within their user group. A maximum of 30 users can be retrieved in one request. Use the `total_users` and `offset` parameter to retrieve more users.\n\n### RESPONSE JSON\n\n```json\n{\n    \"status\": \"OK\",\n    \"total_users\": 60,\n    \"count\": 30,\n    \"users\": [\n        {USER_DATA_JSON}\n        ]\n}\n```\n\n| Key           | Value  | Description                                                                       |\n| ------------- | ------ | --------------------------------------------------------------------------------- |\n| `status`      | string | `OK` if request was successfully received, `ERROR` if request cannot be processed |\n| `total_users` | number | Total users in the user group                                                     |\n| `count`       | number | Users in the response                                                             |\n| `users`       | List   | List of [User Profile JSON Format](https://developers.filespin.io/api-reference/user/user-api-introduction#user-profile-json-format) |",
        "tags": [
          "Users & Settings"
        ],
        "responses": {
          "200": {
            "description": "Successful operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserListResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      },
      "post": {
        "summary": "Search Users",
        "operationId": "search_users_post",
        "description": "Retrieve more users using`offset` parameter. Can also be used with filtering criteria such as `email`, `first_name`, etc.\n\n### REQUEST JSON\n\n```json\n{\n  \"email\": \"user@example.org\",\n  \"first_name\": \"FIRST NAME\",\n  \"last_name\": \"LAST NAME\",\n  \"enabled_only\": false,\n  \"offset\": 0\n}\n```\n\n| Parameter      | Type    | Description                                                                                                                                                       |\n| -------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `email`        | string  | Wildcards are not allowed, however partial email string such as `user@example` will be matched.                                                                     |\n| `first_name`   | string  | Wildcards are not allowed, partial string will be matched                                                                                                          |\n| `last_name`    | string  | Wildcards are not allowed, partial string will be matched                                                                                                          |\n| `enabled_only` | boolean | Set `true` to only retrieve enabled users                                                                                                                          |\n| `offset`       | number  | Defaults to `0`. The record number to start from when retrieving users. Calculate this using `total_users` and the `count` of actual users retrieved in the request |\n\n### Response JSON\n\n```json\n{\n    \"status\": \"OK\",\n    \"total_users\": 60,\n    \"count\": 30,\n    \"users\": [\n        {USER_DATA_JSON}\n        ]\n}\n```",
        "tags": [
          "Users & Settings"
        ],
        "responses": {
          "200": {
            "description": "Successful operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserListResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UserSearchRequest"
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/users/{user_id}": {
      "get": {
        "summary": "Retrieve by User ID",
        "operationId": "retrieve_by_User_ID_get",
        "description": "API for User Administrator to retrieve a user within their user group.\n\n### RESPONSE JSON\n\nAs defined in [User Profile JSON Format](https://developers.filespin.io/api-reference/user/user-api-introduction#user-profile-json-format) section.",
        "tags": [
          "Users & Settings"
        ],
        "responses": {
          "200": {
            "description": "Successful operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserProfile"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "parameters": [
          {
            "name": "user_id",
            "in": "path",
            "required": true,
            "description": "Numeric identifier of the user",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/users/new": {
      "post": {
        "summary": "Create User",
        "operationId": "create_user_post",
        "description": "User Administrator can create a user. The new user receives an activation email with a signup link to set their password and complete onboarding.\n\n### HTTP RESPONSE\n\nStandard HTTP codes.",
        "tags": [
          "Users & Settings"
        ],
        "responses": {
          "200": {
            "description": "Successful operation"
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "requestBody": {
          "$ref": "#/components/requestBodies/create_user"
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/user/notifications": {
      "get": {
        "summary": "Get User Notifications",
        "operationId": "getUserNotifications_get",
        "description": "Notifications returned are limited to latest 100.\n\n#### HTTP RESPONSE\n\nStandard HTTP code and JSON payload as below.\n\n```json\n{\n  \"notifications\": [\n    {\n      \"id\": 2,\n      \"message\": \"Collection updated by joe@example.org\",\n      \"url\": \"/collection/1\",\n      \"disposal\": \"ON_ACK\",\n      \"timestamp\": \"2022-05-14T07:08:49Z\"\n    },\n    {\n      \"id\": 1,\n      \"message\": \"Welcome! New notifications will appear here.\",\n      \"url\": null,\n      \"disposal\": \"ON_READ\",\n      \"timestamp\": \"2022-05-15T07:08:15Z\"\n    }\n  ]\n}\n```\n\n| Parameter   | Details                                                       |\n| ----------- | ------------------------------------------------------------- |\n| `id`        | Notification id, used for disposing                           |\n| `message`   | Notification text                                             |\n| `url`       | Any associated URL                                            |\n| `disposal`  | What should be done with the message. See below               |\n| `timestamp` | ISO 8601 datetime indicating when the notification was issued |\n\nNotifications have two disposals listed below.\n\n| Disposal type | Details                                                            |\n| ------------- | ------------------------------------------------------------------ |\n| `ON_READ`     | Disposed automatically when retrieved                              |\n| `ON_ACK`      | User must acknowledge the notification to dispose it |",
        "tags": [
          "Users & Settings"
        ],
        "responses": {
          "200": {
            "description": "List of user notifications",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotificationList"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/user/settings": {
      "get": {
        "summary": "Get Account Settings",
        "operationId": "Settings_get",
        "description": "Retrieve the user settings that include : -\n\n`storage`, `auth`, `webhook`, `database`, `image`, `video`, `addons`, etc.\n\nSettings keys are described in the following settings against the Update Settings API calls.",
        "tags": [
          "Users & Settings"
        ],
        "responses": {
          "200": {
            "description": "Successful operation"
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/user/settings/update": {
      "patch": {
        "summary": "Update Settings",
        "operationId": "update_settings_patch",
        "description": "Update account settings by sending a PATCH request with a partial settings payload. The JSON payload uses a `key`/`value` structure where `key` identifies the settings section to update.\n\n**Valid keys:** `storage`, `webhook`, `database`, `image`, `video`, `addons`, `watermark`\n\n### Storage\n\nUpdate S3 storage bucket configuration. All keys are mandatory.\n\n> **Warning:** If using different S3 buckets for Originals, Derivatives and Transcodes, all buckets must be in the same region.\n\n```json\n{\n  \"key\": \"storage\",\n  \"value\": {\n    \"originals_root\": \"MY-S3-BUCKET\",\n    \"originals_root_folder\": \"folder/path\",\n    \"derivatives_root\": \"MY-S3-BUCKET\",\n    \"derivatives_root_folder\": \"folder/path\",\n    \"transcodes_root\": \"MY-S3-BUCKET\",\n    \"transcodes_root_folder\": \"folder/path\"\n  }\n}\n```\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `key` | string | Set to `storage` |\n| `value`.`originals_root` | string | S3 bucket name for original asset files |\n| `value`.`originals_root_folder` | string | Path prefix for objects in the bucket |\n| `value`.`derivatives_root` | string | S3 bucket name for image conversions |\n| `value`.`derivatives_root_folder` | string | Path prefix for objects in the bucket |\n| `value`.`transcodes_root` | string | S3 bucket name for video transcodes |\n| `value`.`transcodes_root_folder` | string | Path prefix for objects in the bucket |\n\n### Webhook\n\nUpdate webhook callback URLs and events. All keys mandatory.\n\n```json\n{\n  \"key\": \"webhook\",\n  \"value\": {\n    \"web_urls\": \"https://myapp.example.org/receiver\",\n    \"callback_events\": {\n      \"file-saved\": true,\n      \"file-processed\": true,\n      \"file-data-updated\": true,\n      \"file-deleted\": true,\n      \"file-undeleted\": true,\n      \"addon-processed\": false\n    }\n  }\n}\n```\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `key` | string | Set to `webhook` |\n| `value`.`web_urls` | string | Comma-separated URLs (max 3). Can be empty. |\n| `value`.`callback_events` | JSON | Event flags: `file-saved`, `file-processed`, `file-data-updated`, `file-deleted`, `file-undeleted`, `addon-processed` |\n\n### Database\n\nUpdate external database export configuration. All keys mandatory.\n\n```json\n{\n  \"key\": \"database\",\n  \"value\": {\n    \"db_url\": \"mysql://USER:PASSWORD@DB_HOST/DATABASE\"\n  }\n}\n```\n\nAll webhook events are auto-enabled for database export. Use empty `db_url` to disable.\n\n### Image\n\nUpdate image conversion settings. Maximum **10 conversions** (including `deepzoom`). The `deepzoom` conversion only accepts `watermark`, `enabled`, `public`.\n\n```json\n{\n  \"key\": \"image\",\n  \"value\": {\n    \"on_demand_image_private\": false,\n    \"conversions\": [\n      {\n        \"key\": \"500x500WEB\",\n        \"value\": {\n          \"format\": \"jpg\",\n          \"watermark\": false,\n          \"enabled\": true,\n          \"public\": false,\n          \"height\": 500,\n          \"width\": 500,\n          \"dpi\": 72\n        }\n      },\n      {\n        \"key\": \"deepzoom\",\n        \"value\": {\n          \"watermark\": false,\n          \"enabled\": false,\n          \"public\": true\n        }\n      }\n    ]\n  }\n}\n```\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `key` | string | Set to `image` |\n| `value`.`on_demand_image_private` | boolean | `true` to restrict on-demand image access to authenticated users |\n| `value`.`conversions` | array | List of image conversion objects (max 10) |\n| `conversions[].key` | string | Conversion name (min 3 characters), e.g. `500x500WEB`, `orig_web`, `deepzoom` |\n| `conversions[].value.format` | string | Output format: `jpg`, `png`, `webp` |\n| `conversions[].value.watermark` | boolean | Apply watermark to this conversion |\n| `conversions[].value.enabled` | boolean | Enable this conversion for new uploads |\n| `conversions[].value.public` | boolean/string | Public access for this conversion |\n| `conversions[].value.height` | integer | Output height in pixels (omit or empty string for original size) |\n| `conversions[].value.width` | integer | Output width in pixels (omit or empty string for original size) |\n| `conversions[].value.dpi` | integer | Output DPI (e.g. `72`, `150`, `300`) |\n\n### Video\n\nUpdate video transcode, preview, and thumbnail settings. All four top-level keys are required.\n\nAspect options: `pad`, `preserve`, `scale`, `crop`. Storyboard modes: `number`, `second`, `keyframes`. Transcode keys: `360p-video`, `360p-wm-video`, `480p-video`, `480p-wm-video`, `720p-video`, `720p-wm-video`, `1080p-video`, `1080p-wm-video`, `hls-video`.\n\n```json\n{\n  \"key\": \"video\",\n  \"value\": {\n    \"video_transcode_test_mode\": false,\n    \"thumbnails\": {\n      \"video_default\": {\n        \"width\": 480,\n        \"height\": 360\n      },\n      \"storyboard\": {\n        \"enabled\": true,\n        \"mode\": \"number\",\n        \"mode_value\": 10,\n        \"width\": 320,\n        \"height\": 240,\n        \"public\": true,\n        \"aspect\": \"pad\",\n        \"padding\": \"000000\",\n        \"upscale\": false\n      }\n    },\n    \"preview\": {\n      \"video_preview_enabled\": true,\n      \"video_preview_public\": true,\n      \"video_preview_start\": 0,\n      \"video_preview_length\": 60,\n      \"video_preview_preset\": \"480p-wm-video\",\n      \"video_preview_aspect\": \"pad\",\n      \"video_preview_padding\": \"000000\",\n      \"video_preview_upscale\": false\n    },\n    \"transcodes\": {\n      \"480p-video\": {\n        \"watermark\": false,\n        \"enabled\": true,\n        \"public\": false,\n        \"aspect\": \"pad\",\n        \"padding\": \"000000\",\n        \"upscale\": false\n      },\n      \"720p-video\": {\n        \"watermark\": false,\n        \"enabled\": false,\n        \"public\": false,\n        \"aspect\": \"pad\",\n        \"padding\": \"000000\",\n        \"upscale\": false\n      },\n      \"hls-video\": {\n        \"watermark\": true,\n        \"enabled\": false,\n        \"public\": true,\n        \"aspect\": \"pad\",\n        \"padding\": \"000000\",\n        \"upscale\": false\n      }\n    }\n  }\n}\n```\n\n> **Note:** The `transcodes` object above shows a subset for brevity. All nine transcode keys must be included: `360p-video`, `360p-wm-video`, `480p-video`, `480p-wm-video`, `720p-video`, `720p-wm-video`, `1080p-video`, `1080p-wm-video`, `hls-video`.\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `key` | string | Set to `video` |\n| `value`.`video_transcode_test_mode` | boolean | Enable test mode (transcodes are not triggered automatically) |\n| `value`.`thumbnails.video_default` | object | Default video thumbnail size: `width` (10-1920), `height` (10-1080) |\n| `value`.`thumbnails.storyboard` | object | (optional) Storyboard settings: `enabled`, `mode`, `mode_value`, `width`, `height`, `public`, `aspect`, `padding`, `upscale` |\n| `value`.`preview` | object | Video preview clip settings |\n| `preview.video_preview_enabled` | boolean | Enable preview clip generation |\n| `preview.video_preview_public` | boolean | Public access for preview clips |\n| `preview.video_preview_start` | integer | Start time in seconds |\n| `preview.video_preview_length` | integer | Preview duration in seconds |\n| `preview.video_preview_preset` | string | Transcode preset to use for preview (must be one of the transcode keys) |\n| `preview.video_preview_aspect` | string | Aspect mode: `pad`, `preserve`, `scale`, `crop` |\n| `preview.video_preview_padding` | string | Hex color for padding (e.g. `000000`) |\n| `preview.video_preview_upscale` | boolean | Allow upscaling |\n| `value`.`transcodes` | object | Transcode presets keyed by resolution name |\n| `transcodes.{preset}` | object | Per-preset settings: `watermark`, `enabled`, `public`, `aspect`, `padding`, `upscale` |\n\n### Addons\n\nSee [Update Addons Settings](update-addons-settings-post) for the dedicated endpoint.\n\n### Watermark\n\nUpdate watermark placement and scaling. See [Update Watermark](https://developers.filespin.io/api-reference/user/update-watermark) for the two-step process (upload image, then confirm via this PATCH with `key: \"watermark\"`).",
        "tags": [
          "Users & Settings"
        ],
        "responses": {
          "200": {
            "description": "Successful operation"
          },
          "202": {
            "description": "Accepted (storage, watermark updates are asynchronous)"
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "requestBody": {
          "$ref": "#/components/requestBodies/update_settings"
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/user/settings/addons/{addon_key}": {
      "post": {
        "summary": "Update Addons Settings",
        "operationId": "update_Addons_Settings_post",
        "description": "Update `addons` by sending below payload.\n\n**Note: This update will overwrite the entire addons settings. All addon keys must be must be supplied** along with their corresponding target state for `added` and `enabled`.\n\n> **Note:** All addons that support event hooks can be updated using this API\n>\n> **Pre-requisite: Addon must be available for the user account. Contact Support if addon is not available for the account.**\n\n### REQUEST PAYLOAD\n\n```json\n{\n  \"key\": \"addons\",\n  \"value\": {\n    \"STORYBOARD\": {\n      \"added\": true,\n      \"enabled\": true\n    }\n  }\n}\n```\n\n* `added` specifies whether the user has added this available addon to their account\n* `enabled` specifies whether this addon has been activated by user\n\n| Parameters | Type   | Description                                                                                                                                                                                                         |\n| :--------- | :----- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `key`      | string | Set to`addons`                                                                                                                                                                                                      |\n| `value`    | JSON   | To add the available addon to the profile, set `added` to `true`. To enable an addon that has been `added`, set `enabled` to `true`. An addon has to be both `added` and `enabled` for it to be part of the processing pipeline. |",
        "tags": [
          "Users & Settings"
        ],
        "responses": {
          "200": {
            "description": "Successful operation"
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "requestBody": {
          "$ref": "#/components/requestBodies/update_addons_settings"
        },
        "parameters": [
          {
            "name": "addon_key",
            "in": "path",
            "required": true,
            "description": "Addon identifier key",
            "schema": {
              "type": "string"
            },
            "example": "FACE_RECOGNITION"
          }
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/jobs/{job_id}": {
      "get": {
        "summary": "Get Job",
        "operationId": "Status_get",
        "description": "Jobs API provides status of all user initiated jobs in FileSpin.\n\n`/jobs/{job_id}` API returns the status of a job.\n\n### RESPONSE JSON\n\nThe API call will return with a JSON response as below.\n\n```json\n {\n  \"status\": \"COMPLETED\",\n  \"message\": \"\",\n  \"job_id\": 1234,\n  \"creator_id\": 272,\n  \"requested_at\": \"2017-04-20T16:08:02Z\",\n  \"completed_at\": \"2017-04-20T16:08:02Z\",\n  \"job_steps\": {\n  },\n  \"input\": {},\n  \"callback\": {},\n  \"type\": \"VIDEO_TRANSCODE\"\n}\n```\n\n### RESPONSE PARAMETERS\n\n| Key            | Value   | Description                                                                                                                          |\n| -------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------ |\n| `status`       | string  | Can be `\"QUEUED\"`, `\"IN_PROGRESS\"`,` \"COMPLETED\"`, `\"ERROR\"`                                                                         |\n| `message`      | string  | On `\"ERROR\"` status, this will contain the error message that can be used to diagnose the error                                      |\n| `job_id`       | integer | The job ID to track the job                                                                                                          |\n| `creator_id`   | integer | Id of the user who initiated the job                                                                                                 |\n| `requested_at` | string  | ISO 8601 datetime, time at which the job request was received                                                                        |\n| `completed_at` | string  | ISO 8601 datetime, time at which the job completed                                                                                   |\n| `job_steps`    | JSON    | The job steps and step completion timestamps. This is useful for monitoring progress. The steps will vary depending on the job type. |\n| `input`        | JSON    | The API request JSON that created this job                                                                                           |\n| `callback`     | JSON    | The callback JSON issued if job completed. If job is not completed yet, this will be an empty dictionary                             |\n| `type`         | string  | The job type. Only `\"VIDEO_TRANSCODE\"` supported at this time                                                                        |\n\n**Steps for Video Transcode Job**\n\nThe `job_steps` for `VIDEO_TRANSCODE` job type is as below:-\n\n```json\n{\n   \"transcodes\": {\n          \"480p-video\": {\n              \"status\": \"COMPLETED\",\n              \"percent_complete\": 100,\n              \"started_at\": \"2023-07-18T15:09:24Z\",\n              \"finished_at\": \"2023-07-18T15:09:28Z\",\n              \"message\": \"\"\n          }\n      },\n     \"addons\": {\n           \"storyboard\": {\n               \"status\": \"COMPLETED\",\n               \"percent_complete\": 100,\n               \"started_at\": \"2023-07-18T15:06:12Z\",\n               \"finished_at\": \"2023-07-18T15:08:46Z\",\n               \"message\": \"\"\n           }\n       },\n      \"preprocess\": {\n          \"status\": \"COMPLETED\",\n          \"percent_complete\": 100,\n          \"started_at\": \"2023-07-18T15:09:24Z\",\n          \"finished_at\": \"2023-07-18T15:09:25Z\",\n          \"message\": \"Downloaded & verified integrity of input file test.mov\"\n      },\n      \"postprocess\": {\n          \"status\": \"COMPLETED\",\n          \"percent_complete\": 100,\n          \"started_at\": \"2023-07-18T15:09:26Z\",\n          \"finished_at\": \"2023-07-18T15:09:28Z\",\n          \"message\": \"Completed uploading outputs\"\n      }\n}\n```\n\n| Key                | Value   | Description                                                                                     |\n| ------------------ | ------- | ----------------------------------------------------------------------------------------------- |\n| `status`           | string  | Can be `\"QUEUED\"`,`\"IN_PROGRESS\"`, `\"COMPLETED\"`, `\"ERROR\"`                                     |\n| `message`          | string  | On `\"ERROR\"` status, this will contain the error message that can be used to diagnose the error |\n| `percent_complete` | integer | Job progress as percentage value                                                                |\n| `started_at`       | string  | ISO 8601 datetime, time at which the step processing was started                                |\n| `finished_at`      | string  | ISO 8601 datetime, time at which the step completed                                             |",
        "tags": [
          "Jobs"
        ],
        "responses": {
          "200": {
            "description": "Successful operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobStatus"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "404": {
            "description": "Job not found"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "description": "Identifier of the background job",
            "schema": {
              "type": "string"
            },
            "example": "12345"
          }
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/jobs": {
      "get": {
        "summary": "Get Jobs",
        "operationId": "Retrieve_get",
        "description": "Jobs API provides status of all user initiated jobs in FileSpin.\n\n`/jobs` API returns the list of jobs initiated by caller. Use `offset` and `limit` query parameters to paginate through results.\n\n### RESPONSE JSON\n\nThe API call will return with a JSON response as below.\n\n```json\n{\n    \"count\": 15,\n    \"limit\": 30,\n    \"offset\": 0,\n    \"total\": 15,\n    \"jobs\": [\n    ]\n}\n```\n\n| key      | Value   | Description                                                                 |\n| -------- | ------- | --------------------------------------------------------------------------- |\n| `count`  | integer | The number of jobs returned in this response                                |\n| `offset` | integer | Defaults to `0`. The offset for job records                                 |\n| `limit`  | integer | Defaults to `30`. The number of jobs to return                              |\n| `total`  | integer | The total number of jobs initiated by the caller                            |\n| `jobs`   | JSON    | The list of job JSON as specified in [Job Status - Get] |",
        "tags": [
          "Jobs"
        ],
        "responses": {
          "200": {
            "description": "Successful operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobList"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "parameters": [
          {
            "name": "offset",
            "in": "query",
            "description": "Number of jobs to skip for pagination",
            "required": false,
            "example": 0,
            "schema": {
              "type": "integer",
              "default": 0
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of jobs to return",
            "required": false,
            "example": 10,
            "schema": {
              "type": "integer",
              "default": 30
            }
          }
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/cdn/prefetch": {
      "post": {
        "summary": "Prefetch",
        "operationId": "Prefetch_post",
        "description": "This API provides prefetch for assets so that you can pre-cache assets in CDN to speed up your websites and apps.\n\nYou can pre-cache:-\n\n* video transcodes such as 480p-video.mp4, 720p-video.mp4, 1080p-video.mp4, etc.\n  * Example public transcode `https://cdn.filespin.io/api/v1/assets/ASSET_ID/transcodes/480p-video.mp4`\n  * Example signed transcode `https://cdn.filespin.io/api/v1/assets/ASSET_ID/transcodes/480p-video.mp4?expiry=1452894790&accessId=IZJTAMBQGAYDAMBQGAYDAMBQGAYDANKT&signature=vsR0_NFfeLEJPc8MXWMh2xI2Qvg%3D`\n* image conversions like below\n  * Example public conversion `https://cdn.filespin.io/api/v1/assets/ASSET_ID/conversions?resize=200,200`\n  * Example signed conversion `https://cdn.filespin.io/api/v1/assets/ASSET_ID/conversions?resize=200,200&expiry=1510659108&accessId=IZJTAMBQGAYDAMBQGAYDAMBQDBYDAMBR&signature=dwtRLuuL0PSmC-ZoIsh5zerMguc%3D`\n* other asset content obtained via `get_link` API such as\n  * Example public asset `https://cdn.filespin.io/api/v1/files/content/ASSET_ID?key=original&expiry=1695802858&delivery=display&accessId=IZJTAMBQGAYDAMBQGAYDAMBQDBYDAMBR&signature=4FfPR8CyNFcEzf2jbGG5Ui6tBB0%3D`\n\n### Request JSON\n\n```json\n{\n  \"asset_urls\": [\"/video/8e563c1435e643b19fea2d42f2f73948/720p-wm-video.mp4\"],\n  \"cache_expiry\": 12\n}\n```\n\n**Note:**\n\n* API payload can have upto 1000 asset URLs\n* [DEPRECATED] Cache expiry can range from 12 hours to 30 days (720 hours)\n* The `asset_urls` parameter should be valid video or image url parts\n* If the CDN Asset URL is not public, it must be a signed URL part\n  * see [Signing Video URLs]\n  * see [Signing Image URLs]\n  * see [Asset Get Link API]\n\n> **Note:** CDN prefetch requests are throttled to prevent abuse. If you have more than a few assets to pre-cache, batch them in one API call.",
        "tags": [
          "CDN"
        ],
        "responses": {
          "200": {
            "description": "Successful operation"
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CdnPrefetchRequest"
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/cdn/purge": {
      "post": {
        "summary": "Purge",
        "operationId": "Purge_post",
        "description": "This API provides purge option for cached CDN assets. You can use this to purge cached assets. See [CDN Asset Prefetch]  for types of cached assets you can purge.\n\n**Note:**\n\n* API payload can have upto 1000 asset URLs\n* The `asset_urls` parameter should be valid video or image url parts\n* If the CDN Asset URL is not public, it must be a signed URL part\n  * see [Signing Video URLs]\n  * see [Signing Image URLs]\n  * see [Asset Get Link API]\n\n> **Note:** CDN purge requests are throttled to prevent abuse. Please use purge with appropriate expiry to reduce volume of purge requests.If you have more than a few assets to purge, we recommend that you batch them in one API call.\n\n### REQUEST JSON\n\nThe request body should be a JSON as below.\n\n```json\n{\n  \"asset_urls\": [\n    \"/api/v1/assets/f99255d2bf8142b29561641491e9940c/transcodes/480p-video.mp4\",\n    \"/api/v1/assets/f99255d2bf8142b29561641491e9940c/transcodes/480p-video.mp4?expiry=1452894790&accessId=IZJTAMBQGAYDAMBQGAYDAMBQGAYDANKT&signature=vsR0_NFfeLEJPc8MXWMh2xI2Qvg%3D\",\n    \"/api/v1/assets/0c3c6d026858460abc4de1dcb4de15ac/conversions?resize=200,200\",\n    \"/api/v1/assets/0c3c6d026858460abc4de1dcb4de15ac/conversions?resize=200,200&expiry=1510659108&accessId=IZJTAMBQGAYDAMBQGAYDAMBQDBYDAMBR&signature=dwtRLuuL0PSmC-ZoIsh5zerMguc%3D\",\n    \"/api/v1/files/content/0c3c6d026858460abc4de1dcb4de15ac?key=original&expiry=1510659108&accessId=IZJTAMBQGAYDAMBQGAYDAMBQDBYDAMBR&signature=dwtRLuuL0PSmC-ZoIsh5zerMguc%3D\"\n  ]\n}\n```\n\n| Key          | Value | Description                                      |\n| ------------ | ----- | ------------------------------------------------ |\n| `asset_urls` | list  | List of asset URLs parts. Maximum of `1000` URLs |",
        "tags": [
          "CDN"
        ],
        "responses": {
          "200": {
            "description": "Successful operation"
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CdnPurgeRequest"
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/stats/api": {
      "get": {
        "summary": "Retrieve API Stats",
        "operationId": "Retrieve_API_Stats_get",
        "description": "### RESPONSE JSON\n\nThe API call will return with a JSON response as below.\n\n**When user\\_id is not sent in parameters**, the API returns consolidated stats for the user group. `user_id` will be set to `*` in this case.\n\n```json\n{\n    \"usergroup_id\": 42,\n    \"period\": 24,\n    \"data\": {\n        \"*\": {\n            \"/api/v1/assets/{ASSET_ID}/data\": 69,\n            \"/api/v1/assets/{ASSET_ID}/conversions\": 8828,\n            \"/api/v1/schema/{ID}\": 426\n        }\n    }\n}\n```\n\n**When user\\_id is sent in parameters**, the API returns stats for the user. `user_id` will be set to appropriate id in this case as below.\n\n```json\n{\n    \"usergroup_id\": 42,\n    \"period\": 24,\n    \"data\": {\n        \"42\": {\n            \"/api/v1/assets/{ASSET_ID}/data\": 69,\n            \"/api/v1/assets/{ASSET_ID}/conversions\": 8828,\n            \"/api/v1/schema/{ID}\": 426\n        }\n    }\n}\n```\n\n| key                | Value   | Description                                                                                                                  |\n| ------------------ | ------- | ---------------------------------------------------------------------------------------------------------------------------- |\n| `usergroup_id`     | integer | User group id                                                                                                                |\n| `period`           | integer | the period for which stats is returned. Defaults to 24 (hours)                                                               |\n| `data`             | JSON    | JSON with `user_id` as key. The list key `\"42\"` is the User ID. `\"*\"` for consolidated group stats.                          |\n| `data`.`{user_id}` | object  | Key-Value pairs with API path as the key and call count as the value. IDs in paths are replaced with `{ASSET_ID}` and `{ID}` |",
        "tags": [
          "Usage Stats"
        ],
        "responses": {
          "200": {
            "description": "Successful operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiStatsResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "parameters": [
          {
            "name": "user_id",
            "in": "query",
            "description": "Filter to a specific user. Omit for consolidated group stats (keyed under `*`).",
            "required": false,
            "example": "42",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "period",
            "in": "query",
            "description": "Period in hours (24–8760). Defaults to 24.",
            "required": false,
            "example": "720",
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/stats/storage": {
      "get": {
        "summary": "Retrieve Storage Stats",
        "operationId": "Retrieve_Storage_Stats_get",
        "description": "### RESPONSE JSON\n\nThe API call will return with a JSON response as below.\n\n**When user\\_id is not sent in parameters**, the API returns consolidated stats for the user group. `user_id` will be set to `*` in this case.\n\n```json\n{\n    \"usergroup_id\": 42,\n    \"period\": 24,\n    \"data\": {\n        \"*\": {\n          \"/api/v1/assets/{ASSET_ID}/conversions\": 8828,\n           \"/api/v1/schema/{ID}\": 426\n         }\n    }\n}\n```\n\n**When user\\_id is sent in parameters**, the API returns stats for the user. `user_id` will be set to appropriate id  in this case as below.\n\n```json\n{\n    \"usergroup_id\": 42,\n    \"period\": 24,\n    \"data\": {\n        \"42\": {\n          \"/api/v1/assets/{ASSET_ID}/conversions\": 8828,\n           \"/api/v1/schema/{ID}\": 426\n         }\n    }\n}\n```\n\n| key                | Value   | Description                                                                                                                  |\n| ------------------ | ------- | ---------------------------------------------------------------------------------------------------------------------------- |\n| `usergroup_id`     | integer | User group id                                                                                                                |\n| `period`           | integer | the period for which stats is returned. Defaults to 24 (hours)                                                               |\n| `data`             | JSON    | JSON with `user_id` as key. The list key `\"42\"` is the User IDs.                                                             |\n| `data`.`{user_id}` | string  | Key-Value pairs with API as the key and count as the value. Note that IDs in API are replaced with placeholder `{ASSET_ID}` and `{ID}` |",
        "tags": [
          "Usage Stats"
        ],
        "responses": {
          "200": {
            "description": "Successful operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiStatsResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "parameters": [
          {
            "name": "user_id",
            "in": "query",
            "description": "The user_id parameter",
            "required": true,
            "example": "USER_ID",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "period",
            "in": "query",
            "description": "The period parameter",
            "required": true,
            "example": "720",
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/stats/transcodes": {
      "get": {
        "summary": "Retrieve Transcode Stats",
        "operationId": "Retrieve_Transcode_Stats_get",
        "description": "### RESPONSE JSON\n\nThe API call will return with a JSON response as below.\n\n```json\n{\n    \"usergroup_id\": 42,\n    \"period\": 24,\n    \"data\": {\n        \"42\": {\n           \"VIDEO_TRANSCODE_SECONDS\": 145\n         },\n        \"43\": {\n           \"VIDEO_TRANSCODE_SECONDS\": 87266\n         }\n    }\n}\n```\n\n| key                | Value   | Description                                                                         |\n| ------------------ | ------- | ----------------------------------------------------------------------------------- |\n| `usergroup_id`     | integer | User group id                                                                       |\n| `period`           | integer | the period for which stats is returned. Defaults to 24 (hours)                      |\n| `data`             | JSON    | JSON with `user_id` as key. The list keys `\"42\"` and `\"43\"` are User IDs.           |\n| `data`.`{user_id}` | string  | Key-Value pairs with `VIDEO_TRANSCODE_SECONDS` as the key and seconds as the value. |",
        "tags": [
          "Usage Stats"
        ],
        "responses": {
          "200": {
            "description": "Successful operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiStatsResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "parameters": [
          {
            "name": "period",
            "in": "query",
            "description": "The period parameter",
            "required": true,
            "example": "720",
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/stats/addons": {
      "get": {
        "summary": "Retrieve Addon Stats",
        "operationId": "Retrieve_Addon_Stats_get",
        "description": "### RESPONSE JSON\n\nThe API call will return with a JSON response as below.\n\n```json\n{\n    \"usergroup_id\": 42,\n    \"period\": 24,\n    \"data\": {\n        \"42\": {\n           \"REMOVE_BACKGROUND\": 282,\n           \"STORYBOARD\": 882\n        },\n        \"43\": {\n         \"REMOVE_BACKGROUND\": 997\n         }\n    }\n}\n```\n\n| key                | Value   | Description                                                                     |\n| ------------------ | ------- | ------------------------------------------------------------------------------- |\n| `usergroup_id`     | integer | User group id                                                                   |\n| `period`           | integer | the period for which stats is returned. Defaults to 24 (hours)                  |\n| `data`             | JSON    | JSON with `user_id` as key. The list keys `\"42\"` and `\"43\"` are User IDs.       |\n| `data`.`{user_id}` | string  | Key-Value pairs with Addon ID as the key and usage count as the value.          |",
        "tags": [
          "Usage Stats"
        ],
        "responses": {
          "200": {
            "description": "Successful operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiStatsResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "parameters": [
          {
            "name": "period",
            "in": "query",
            "description": "The period parameter",
            "required": true,
            "example": "720",
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/assets/{asset_id}/addons/image_analysis": {
      "get": {
        "summary": "Retrieve Auto-tags",
        "operationId": "Retrieve_Auto_tags_get",
        "description": "API to retrieve an image asset's auto-tag data.\n\n### Response JSON\n\n```json\n{\n  \"labelAnnotations\": [\n    {\n      \"score\": 0.8699386,\n      \"data\": \"alabel\"\n    }\n  ],\n  \"bestGuessLabels\": [\n    {\n      \"label\": \"red elephant\",\n      \"languageCode\": \"en\"\n    }\n  ],\n  \"textAnnotations\": [\n    {\n      \"locale\": \"en\",\n      \"data\": \"Detected text from the image\"\n    }\n  ]\n}\n```\n\n| Parameter          | Description                                                                        |\n| ------------------ | ---------------------------------------------------------------------------------- |\n| `labelAnnotations` | List of labels with confidence score (`0` = least confident, `1` = very confident) |\n| `bestGuessLabels`  | Best guess summary of the image                                                    |\n| `textAnnotations`  | OCR text detected in the image with locale. Annotations are keyword searchable. Words shorter than 3 characters are excluded and a maximum of 500 words are indexed. Empty array if no text detected |",
        "tags": [
          "Addons - Image Analysis"
        ],
        "responses": {
          "200": {
            "description": "Successful operation"
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "parameters": [
          {
            "name": "asset_id",
            "in": "path",
            "required": true,
            "description": "Unique 32-character hex identifier of the asset",
            "schema": {
              "type": "string"
            },
            "example": "a211ab5f351f4b398426efb59b0c72a3"
          }
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/assets/file/addons/bg_remove": {
      "post": {
        "summary": "Remove Background (Upload)",
        "operationId": "remove_bg_post",
        "description": "Remove background from an uploaded image (no asset ID in path). Use `image` as the multipart-form field name for the uploaded file.\n\nBehaviour and response type are controlled by the **mode** and **disposition** query parameters.\n\n### Mode\n\n| Value               | Meaning |\n|---------------------|---------|\n| `get_image`         | Return the processed PNG only. No save. `disposition` is ignored. |\n| `save_image`        | Save the result only. Response is JSON (no PNG). Requires `disposition`. |\n| `get_image_and_save`| Return the PNG and also save in the background. Requires `disposition`. |\n\n### Disposition\n\n| Value              | Meaning |\n|--------------------|---------|\n| `add_conversion`   | Save the result as a named conversion on an existing asset. Requires `asset_id` query parameter. `conversion_name` controls the conversion key. |\n| `add_new_asset`    | Save the result as a new asset. Optional: `metadata=inherit` with `asset_id` query to copy source custom data and set lineage. |\n\n### Validation Rules\n\n- If **mode** is `save_image` or `get_image_and_save`, **disposition** is required.\n- If **disposition** is `add_conversion`, **asset_id** query parameter is required and **conversion_name** must match `^[a-zA-Z0-9_-]{1,30}$`.\n- **metadata** is only allowed when **disposition** is `add_new_asset`. Allowed value: `inherit`.\n- If **metadata** is `inherit`, **asset_id** query parameter is required.\n\n### Response\n\n- **mode = `get_image`** (default): `Content-Type: image/png` — PNG bytes in body.\n- **mode = `get_image_and_save`**: `Content-Type: image/png` — PNG bytes in body (save happens in background).\n- **mode = `save_image`**, **disposition = `add_conversion`**:\n  ```json\n  { \"status\": \"ok\", \"mode\": \"save_image\", \"disposition\": \"add_conversion\", \"asset_id\": \"<id>\", \"conversion_name\": \"<name>\" }\n  ```\n- **mode = `save_image`**, **disposition = `add_new_asset`**:\n  ```json\n  { \"status\": \"ok\", \"mode\": \"save_image\", \"disposition\": \"add_new_asset\", \"source_asset_id\": \"<id>\", \"metadata\": \"inherit\", \"new_asset_id\": \"<id>\" }\n  ```\n  (`source_asset_id` and `metadata` only present when provided; `new_asset_id` when save succeeds.)",
        "tags": [
          "Addons - Background Removal"
        ],
        "responses": {
          "200": {
            "description": "Successful operation. Response depends on `mode`:\n- `get_image` or `get_image_and_save`: PNG image bytes with `Content-Type: image/png`.\n- `save_image`: JSON object with save details.",
            "content": {
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/bg_remove_save_response"
                }
              }
            }
          },
          "400": {
            "description": "Bad request — invalid mode/disposition/conversion_name; missing asset_id when required; metadata used with non-add_new_asset disposition."
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error - Processing or save failure"
          }
        },
        "parameters": [
          {
            "name": "mode",
            "in": "query",
            "required": false,
            "description": "Processing mode. Default: `get_image`.",
            "schema": {
              "type": "string",
              "enum": [
                "get_image",
                "save_image",
                "get_image_and_save"
              ],
              "default": "get_image"
            },
            "example": "get_image"
          },
          {
            "name": "disposition",
            "in": "query",
            "required": false,
            "description": "Required when mode is `save_image` or `get_image_and_save`. Determines how the result is saved.",
            "schema": {
              "type": "string",
              "enum": [
                "add_conversion",
                "add_new_asset"
              ]
            },
            "example": "add_new_asset"
          },
          {
            "name": "conversion_name",
            "in": "query",
            "required": false,
            "description": "Name of the conversion when `disposition=add_conversion`. 1–30 chars, alphanumeric, hyphens/underscores only. Default: `bg_removed`.",
            "schema": {
              "type": "string",
              "pattern": "^[a-zA-Z0-9_-]{1,30}$",
              "default": "bg_removed"
            },
            "example": "bg_removed"
          },
          {
            "name": "metadata",
            "in": "query",
            "required": false,
            "description": "Only allowed when `disposition=add_new_asset`. Use `inherit` to copy source asset custom data to the new asset.",
            "schema": {
              "type": "string",
              "enum": [
                "inherit"
              ]
            },
            "example": "inherit"
          },
          {
            "name": "asset_id",
            "in": "query",
            "required": false,
            "description": "Required when `disposition=add_conversion` or when `metadata=inherit` with `disposition=add_new_asset`. Identifies the target asset for conversions or source asset for metadata inheritance.",
            "schema": {
              "type": "string"
            },
            "example": "a211ab5f351f4b398426efb59b0c72a3"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "image": {
                    "type": "string",
                    "format": "binary",
                    "description": "The image file to remove background from"
                  }
                },
                "required": [
                  "image"
                ]
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/assets/{asset_id}/addons/bg_remove": {
      "get": {
        "summary": "Remove Background (Asset)",
        "operationId": "Bg_Remove_GET_get",
        "description": "Remove background from an existing asset by asset ID. The original file for the given asset is downloaded and processed.\n\nBehaviour and response type are controlled by the **mode** and **disposition** query parameters.\n\n### Mode\n\n| Value               | Meaning |\n|---------------------|---------|\n| `get_image`         | Return the processed PNG only. No save. `disposition` is ignored. |\n| `save_image`        | Save the result only. Response is JSON (no PNG). Requires `disposition`. |\n| `get_image_and_save`| Return the PNG and also save in the background. Requires `disposition`. |\n\n### Disposition\n\n| Value              | Meaning |\n|--------------------|---------|\n| `add_conversion`   | Save the result as a named conversion on the asset identified by `{asset_id}`. `conversion_name` controls the conversion key. |\n| `add_new_asset`    | Save the result as a new asset. Optional: `metadata=inherit` to copy source asset custom data and set lineage. |\n\n### Validation Rules\n\n- If **mode** is `save_image` or `get_image_and_save`, **disposition** is required.\n- If **disposition** is `add_conversion`, **conversion_name** must match `^[a-zA-Z0-9_-]{1,30}$`.\n- **metadata** is only allowed when **disposition** is `add_new_asset`. Allowed value: `inherit`.\n\n### Response\n\n- **mode = `get_image`** (default): `Content-Type: image/png` — PNG bytes in body.\n- **mode = `get_image_and_save`**: `Content-Type: image/png` — PNG bytes in body (save happens in background).\n- **mode = `save_image`**, **disposition = `add_conversion`**:\n  ```json\n  { \"status\": \"ok\", \"mode\": \"save_image\", \"disposition\": \"add_conversion\", \"asset_id\": \"<id>\", \"conversion_name\": \"<name>\" }\n  ```\n- **mode = `save_image`**, **disposition = `add_new_asset`**:\n  ```json\n  { \"status\": \"ok\", \"mode\": \"save_image\", \"disposition\": \"add_new_asset\", \"source_asset_id\": \"<id>\", \"metadata\": \"inherit\", \"new_asset_id\": \"<id>\" }\n  ```\n  (`source_asset_id` and `metadata` only present when provided; `new_asset_id` when save succeeds.)",
        "tags": [
          "Addons - Background Removal"
        ],
        "responses": {
          "200": {
            "description": "Successful operation. Response depends on `mode`:\n- `get_image` or `get_image_and_save`: PNG image bytes with `Content-Type: image/png`.\n- `save_image`: JSON object with save details.",
            "content": {
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/bg_remove_save_response"
                }
              }
            }
          },
          "400": {
            "description": "Bad request — invalid mode/disposition/conversion_name; missing required parameters; metadata used with non-add_new_asset disposition; asset not ready."
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error - Processing or save failure"
          }
        },
        "parameters": [
          {
            "name": "asset_id",
            "in": "path",
            "required": true,
            "description": "Unique 32-character hex identifier of the asset",
            "schema": {
              "type": "string"
            },
            "example": "a211ab5f351f4b398426efb59b0c72a3"
          },
          {
            "name": "mode",
            "in": "query",
            "required": false,
            "description": "Processing mode. Default: `get_image`.",
            "schema": {
              "type": "string",
              "enum": [
                "get_image",
                "save_image",
                "get_image_and_save"
              ],
              "default": "get_image"
            },
            "example": "get_image"
          },
          {
            "name": "disposition",
            "in": "query",
            "required": false,
            "description": "Required when mode is `save_image` or `get_image_and_save`. Determines how the result is saved.",
            "schema": {
              "type": "string",
              "enum": [
                "add_conversion",
                "add_new_asset"
              ]
            },
            "example": "add_conversion"
          },
          {
            "name": "conversion_name",
            "in": "query",
            "required": false,
            "description": "Name of the conversion when `disposition=add_conversion`. 1–30 chars, alphanumeric, hyphens/underscores only. Default: `bg_removed`.",
            "schema": {
              "type": "string",
              "pattern": "^[a-zA-Z0-9_-]{1,30}$",
              "default": "bg_removed"
            },
            "example": "bg_removed"
          },
          {
            "name": "metadata",
            "in": "query",
            "required": false,
            "description": "Only allowed when `disposition=add_new_asset`. Use `inherit` to copy source asset custom data to the new asset.",
            "schema": {
              "type": "string",
              "enum": [
                "inherit"
              ]
            },
            "example": "inherit"
          }
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/assets/{asset_id}/addons/face_recognition": {
      "post": {
        "summary": "Index Faces",
        "operationId": "Face_Recognition_post",
        "description": "Analyse, detect, extract, and index faces in an image. The method requires an `asset_id` in the path parameter to identify the image to analyze. The `POST` method also returns the asset ID of the image that was processed. `409` response indicates that an asset with the provided ID has been already processed.\n\nThis API will automatically update Asset metadata for built-in FileSpin field `_filespin_fr_count` with the count of faces indexed for the asset.\n\n> **Note:** A maximum of 10 faces will be detected and indexed per image.\n\n### Request JSON\n\nThis example shows a request payload JSON to process an asset and update the metadata.\n\n```json\n{\n    \"disposition\": {\n        \"update_metadata\": true\n    }\n}\n```\n\n| Parameter                        | Type    | Description                                                                                                                       |\n| -------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------- |\n| `disposition`                    | JSON    | (optional) Indicates how analysed data must be disposed                                                                           |\n| `disposition` .`update_metadata` | Boolean | `true` if Asset Metadata should be updated for FR. FileSpin reserved field `_filespin_fr_count` will always be added to metadata. |",
        "tags": [
          "Addons - Face Recognition"
        ],
        "responses": {
          "200": {
            "description": "Successful operation"
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "409": {
            "description": "Conflict - Faces already indexed for this asset"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "requestBody": {
          "$ref": "#/components/requestBodies/face_recognition"
        },
        "parameters": [
          {
            "name": "asset_id",
            "in": "path",
            "required": true,
            "description": "Unique 32-character hex identifier of the asset",
            "schema": {
              "type": "string"
            },
            "example": "a211ab5f351f4b398426efb59b0c72a3"
          }
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      },
      "get": {
        "summary": "Face Index Status",
        "operationId": "Get_Request_Status_get",
        "description": "Retrieve the current status of the face indexing request by providing the `asset_id` in the path parameter.\n\n### Response JSON\n\n```json\n{\n    \"state\": \"QUEUED\"\n}\n```\n\n| Parameter | Type   | Description                                                           |\n| --------- | ------ | --------------------------------------------------------------------- |\n| `state`   | string | Status of the asset, one of `QUEUED`, `PROCESSING`, `DONE` or `ERROR` |",
        "tags": [
          "Addons - Face Recognition"
        ],
        "responses": {
          "200": {
            "description": "Successful operation"
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "parameters": [
          {
            "name": "asset_id",
            "in": "path",
            "required": true,
            "description": "Unique 32-character hex identifier of the asset",
            "schema": {
              "type": "string"
            },
            "example": "a211ab5f351f4b398426efb59b0c72a3"
          }
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/ml/people/facesearch": {
      "post": {
        "summary": "Face Search",
        "operationId": "Face_Search_post",
        "description": "Search for faces in an image. The method requires the `image` parameter to perform the search. The `limit_per_page` parameter is optional and defaults to 30 if not provided. The method returns a list of assets that match the search criteria.\n\n### Face Search Filters\n\nThe `filters` option provides the ability to filter face search results with the metadata fields associated with the Asset. This is useful when you want to search for faces with specific metadata fields such as `location` set to `london` and `age` set to `30`.\n\n**Notes:**\n\n* `filters` option is only available when FR Addon Settings has been updated for `event hooks` with appropriate event criteria\n* `filters` JSON should be passed as a string in the multipart form data:\n  ```\n  curl --request POST \\\n    --url https://app.filespin.io/api/v1/ml/people/facesearch \\\n    --header 'X-FileSpin-Api-Key: UPDATE_ME' \\\n    --header 'content-type: multipart/form-data' \\\n    --form image=@face.jpg \\\n    --form 'filters={\"field1\": \"y\"}'\n  ```\n* `filters` support string, number, boolean and date fields\n* Asset Metadata fields that end with `Date` are treated as date fields. Date ranges can be passed as `{\"createdDate\": [\"2021-01-01T01:01:01Z\", \"2022-02-02T02:02:02Z\"]}` (ISO 8601, inclusive)\n* Fields passed in `filters` are case-sensitive and ANDed together\n* A field value may contain multiple space-separated values which are ORed together, e.g. `{\"location\": \"earth mars\"}`\n\n### Response\n\nA successful `POST` request returns a list of assets that match the search criteria. If `extended_result` is `true`, response includes Asset Data for all assets in the page.\n\n```json\n{\n    \"data\": {\n        \"matches\": [\"asset_id1\", \"asset_id2\", \"asset_id3\"],\n        \"extended_result\": {\n            \"asset_id1\": {\"Asset Data JSON\"},\n            \"asset_id2\": {\"Asset Data JSON\"}\n        }\n    },\n    \"page\": 1,\n    \"search_id\": \"eed4c602a80a4920a4a9e56b5d3ea161\",\n    \"limit_per_page\": 30,\n    \"hits\": 3\n}\n```\n\n| Parameter         | Type    | Description                                                                                                                                                                                                                                                  |\n| ----------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `data`            | JSON    | A dictionary with `matches` that contains a list of asset ids that are direct matches. If `include groups` is set to true in request, `group_matches` will be returned with the list of asset ids that the algorithm has determined to be in the same group. |\n| `extended_result` | JSON    | A dictionary containing the current data for each file id returned in result. Data for each file follows [Asset Data Format](https://developers.filespin.io/api/asset-data-format) JSON. If `extended_result` is `false` or not set, response will not contain this JSON.                                            |\n| `page`            | integer | Index of the page from the result pages. Index is calculated using `limit_per_page`.                                                                                                                                                                         |\n| `search_id`       | string  | Returned if `save_search` was set to `true` in the request.                                                                                                                                                                                                  |\n| `limit_per_page`  | integer | As specified in the request or the default.                                                                                                                                                                                                                  |\n| `hits`            | integer | Total number of hits for this search. Pagination can be done using this and `limit_per_page`.                                                                                                                                                                |",
        "tags": [
          "Addons - Face Recognition"
        ],
        "responses": {
          "200": {
            "description": "Successful operation"
          },
          "400": {
            "description": "Bad request - Invalid or missing data"
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "image": {
                    "type": "string",
                    "format": "binary",
                    "description": "An image to perform the search. Cannot exceed 10MB."
                  },
                  "save_search": {
                    "type": "boolean",
                    "description": "Whether to store the search criteria. Defaults to true.",
                    "default": true
                  },
                  "strictness": {
                    "type": "number",
                    "description": "A number from 0 to 10. Defaults to 9.9.",
                    "default": 9.9
                  },
                  "extended_result": {
                    "type": "boolean",
                    "description": "Set to true to return extended asset data. Defaults to false.",
                    "default": false
                  },
                  "filters": {
                    "type": "string",
                    "description": "JSON string of filter fields and values."
                  },
                  "limit_per_page": {
                    "type": "integer",
                    "description": "Results per page, 1 to 30. Defaults to 30.",
                    "default": 30
                  }
                },
                "required": [
                  "image"
                ]
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      },
      "get": {
        "summary": "Paginated Search Results",
        "operationId": "Retrieve_Paginated_Search_get",
        "description": "Retrieve a paginated search result for up to 30 assets per page. The method requires the `page` and `search_id` parameters from the Face Search response to retrieve the results.\n\nThe HTTP GET response JSON is the same as for the Face Search POST that provides one page of search results.",
        "tags": [
          "Addons - Face Recognition"
        ],
        "responses": {
          "200": {
            "description": "Successful operation"
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "parameters": [
          {
            "name": "search_id",
            "in": "query",
            "description": "The search_id parameter",
            "required": true,
            "example": "SEARCH_ID",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "The page parameter",
            "required": true,
            "example": "1",
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/assets/addons/face_recognition/delete": {
      "post": {
        "summary": "Delete Face Data",
        "operationId": "Delete_Data_post",
        "description": "Delete all Face Data associated with the provided assets. It will not delete the `_filespin_fr_count` field in Asset Metadata.\n\n### Request JSON\n\n```json\n{\n    \"ids\": [\"asset_id_1\", \"asset_id_2\"]\n}\n```\n\n| Parameter | Type | Description                                                                                                       |\n| --------- | ---- | ----------------------------------------------------------------------------------------------------------------- |\n| `ids`     | JSON | (Optional) List of asset ids to delete Face Recognition addon data. **A maximum of 100 asset ids can be passed.** |\n\n### Response\n\nAPI responds with HTTP 202. Face Recognition data will usually be deleted completely from the system within a few seconds.\n\n### API Limits\n\nA maximum of 100 ids can be sent per request.",
        "tags": [
          "Addons - Face Recognition"
        ],
        "responses": {
          "200": {
            "description": "Successful operation"
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "requestBody": {
          "$ref": "#/components/requestBodies/delete_data"
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/assets/{asset_id}/storyboard/test.jpg": {
      "get": {
        "summary": "Get Storyboard",
        "operationId": "Get_Storyboard_get",
        "description": "Retrieve storyboard images with dynamic image sizing.\n\nYou can use `/api/v1/assets/{ASSET_ID}/storyboard` CDN API to display dynamically resized storyboard images. This works the same way as On-demand Image Transformations, including all the resizing, cropping and other parameters.\n\n### HTTP Request\n\n`https://cdn.filespin.io/api/v1/assets/{ASSET_ID}/storyboard/[FILE_NAME]?[SIZING_PARAMETERS]`\n\n### Example\n\n```html\n<img src=\"https://cdn.filespin.io/api/v1/assets/3c3a28764d634de59eef7ad9314db612/storyboard/storyboard_000001.jpg?resize=500,500\" />\n```\n\n### URL Parameters\n\n| Key                 | Value  | Description                                                                                                                                                           |\n| ------------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `ASSET_ID`          | string | Asset ID of the video file                                                                                                                                            |\n| `FILE_NAME`         | string | Name of the storyboard file to be resized. This will be one of the files generated based on the Video Storyboard settings.                                            |\n| `SIZING_PARAMETERS` | string | These parameters are the same as the On-demand Image parameters (except Watermark parameter). Refer to On-demand Image Transformations documentation for details. |",
        "tags": [
          "Addons - Video Storyboard"
        ],
        "responses": {
          "200": {
            "description": "Successful operation"
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "parameters": [
          {
            "name": "asset_id",
            "in": "path",
            "required": true,
            "description": "Unique 32-character hex identifier of the asset",
            "schema": {
              "type": "string"
            },
            "example": "a211ab5f351f4b398426efb59b0c72a3"
          }
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/api/v1/callbacks/reissue": {
      "post": {
        "summary": "Reissue Callbacks",
        "operationId": "Reissue_Callbacks_post",
        "description": "In cases where asset callback were not received, there are two ways to re-issue Web callbacks and Database exports.\n\n1. Use the Dashboard -> Tools menu option\n2. Use the `/reissue` API\n\nThe following sections details the API option.\n\n### Reissue Callbacks & Exports API\n\nSend a HTTP POST request to re-issue web callbacks and database exports for assets uploaded within a specified time range. This API is asynchronous.\n\n#### Authentication\n\n* Requires `ASSET_ADMIN` role API Key.\n* Requires `X-FileSpin-Api-Key: <API_KEY>` header.\n\n### POST Request JSON\n\nThe request requires a time range. A complete JSON payload for the reissue request below:\n\n```json\n{\n  \"start_time\": \"2017-06-01T00:00:00Z\",\n  \"end_time\": \"2017-06-07T23:59:59Z\"\n}\n```\n\n| Key          | Type   | Description                                                                                                                               |\n| :----------- | :----- | :---------------------------------------------------------------------------------------------------------------------------------------- |\n| `start_time` | string | (Required) Start date of the time range in ISO 8601 format (`YYYY-MM-DDTHH:MM:SSZ`).                                                     |\n| `end_time`   | string | (Required) End date of the time range in ISO 8601 format (`YYYY-MM-DDTHH:MM:SSZ`). Must be after `start_time`. Must not exceed 7 days from `start_time`. |\n\n### HTTP Response\n\nHTTP Status code **202 Accepted** implies the task has been queued successfully.\n\n```json\n\"Re-issue callbacks started for assets uploaded from 2017-06-01T00:00:00Z to 2017-06-07T23:59:59Z\"\n```\n\n| Status Code       | Description                                                                                                                |\n| :---------------- | :------------------------------------------------------------------------------------------------------------------------- |\n| `202 Accepted`    | The request has been accepted for processing. The operation is asynchronous; the API returns immediately after queuing the task. |\n| `400 Bad Request` | Invalid date format or logic (e.g., `end_date` is before `start_date`, or range exceeds 7 days).                                 |\n| `403 Forbidden`   | User does not have `ASSET_ADMIN` permission.                                                                                     |\n\n> **Warning:** * **Time Limit:** The time range (`end_date` - `start_date`) is limited to a maximum of **7 days**.\n> * **Scope:** Only assets belonging to the authenticated user are processed.\n> * **Resource Usage:** Ensure receiving webhook and target database are setup for callbacks. Use caution when reissuing callbacks for large numbers of assets.",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "202": {
            "description": "Accepted - Reissue task queued successfully"
          },
          "400": {
            "description": "Bad request - Invalid date format or range exceeds 7 days"
          },
          "401": {
            "description": "Unauthorized - Invalid or missing authentication"
          },
          "403": {
            "description": "Forbidden - Insufficient permissions (requires ASSET_ADMIN)"
          },
          "500": {
            "description": "Internal server error"
          }
        },
        "requestBody": {
          "$ref": "#/components/requestBodies/reissue_callbacks"
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    }
  },
  "components": {
    "requestBodies": {
      "add-conversion": {
        "content": {
          "multipart/form-data": {
            "schema": {
              "$ref": "#/components/schemas/add-conversion"
            }
          }
        },
        "description": "",
        "required": true
      },
      "create": {
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/create"
            }
          }
        },
        "description": "",
        "required": true
      },
      "create_user": {
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/create_user"
            }
          }
        },
        "description": "",
        "required": true
      },
      "delete_collection": {
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/delete_collection"
            }
          }
        },
        "description": "",
        "required": true
      },
      "delete_data": {
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/delete_data"
            }
          }
        },
        "description": "",
        "required": true
      },
      "face_recognition": {
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/face_recognition"
            }
          }
        },
        "description": "",
        "required": true
      },
      "get_jwt_and_basic_user_info": {
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/get_jwt_and_basic_user_info"
            }
          }
        },
        "description": "",
        "required": true
      },
      "multiple_asset": {
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/multiple_asset"
            }
          }
        },
        "description": "",
        "required": true
      },
      "process": {
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/process"
            }
          }
        },
        "description": "",
        "required": true
      },
      "reissue_callbacks": {
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/reissue_callbacks"
            }
          }
        },
        "description": "",
        "required": true
      },
      "replace": {
        "content": {
          "multipart/form-data": {
            "schema": {
              "$ref": "#/components/schemas/replace"
            }
          }
        },
        "description": "",
        "required": true
      },
      "undelete": {
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/undelete"
            }
          }
        },
        "description": "",
        "required": true
      },
      "update": {
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/update"
            }
          }
        },
        "description": "",
        "required": true
      },
      "update_addons_settings": {
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/update_addons_settings"
            }
          }
        },
        "description": "",
        "required": true
      },
      "update_collection": {
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/update_collection"
            }
          }
        },
        "description": "",
        "required": true
      },
      "update_settings": {
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/update_settings"
            }
          }
        },
        "description": "Partial settings update. key: storage|webhook|database|image|video|addons|watermark",
        "required": true
      },
      "upload": {
        "content": {
          "multipart/form-data": {
            "schema": {
              "$ref": "#/components/schemas/upload"
            }
          }
        },
        "description": "",
        "required": true
      }
    },
    "schemas": {
      "ApiStatsResponse": {
        "type": "object",
        "description": "API usage statistics response.",
        "properties": {
          "usergroup_id": {
            "type": "integer",
            "description": "User group ID"
          },
          "period": {
            "type": "integer",
            "description": "Period in hours (default 24)"
          },
          "data": {
            "type": "object",
            "description": "Stats keyed by user_id (`*` for consolidated). Values are API path to count mappings.",
            "additionalProperties": true
          }
        },
        "example": {
          "usergroup_id": 42,
          "period": 24,
          "data": {
            "*": {
              "/api/v1/assets/{ASSET_ID}/conversions": 8828
            }
          }
        }
      },
      "AssetData": {
        "type": "object",
        "description": "Standard Asset Data format used across all Asset API responses and webhook callbacks.",
        "properties": {
          "id": {
            "type": "string",
            "description": "Asset's unique ID, 32 character alphanumeric UUID",
            "example": "99d819953914402babbdeb68337ea6a3"
          },
          "status": {
            "type": "string",
            "description": "Asset status. `OK` if saved successfully, `NOT_READY` if being saved, `ERROR` if invalid, `ARCHIVED` if archived (read-only).",
            "enum": [
              "OK",
              "NOT_READY",
              "ERROR",
              "ARCHIVED"
            ]
          },
          "event": {
            "type": "string",
            "description": "Event type: file-saved, file-processed, or file-data-updated"
          },
          "name": {
            "type": "string",
            "description": "File name",
            "example": "sample.mov"
          },
          "size": {
            "type": "integer",
            "description": "Size of file in bytes",
            "example": 8836363
          },
          "checksum": {
            "type": "string",
            "description": "MD5 checksum",
            "example": "5f5f26bd7c0f62c6e02e44c73d09734e"
          },
          "provider": {
            "type": "string",
            "description": "Source of the file - local or one of the supported cloud providers"
          },
          "storage_type": {
            "type": "string",
            "description": "`AMAZON_S3` if S3, `FILESPIN` if managed by FileSpin",
            "enum": [
              "AMAZON_S3",
              "FILESPIN"
            ]
          },
          "bucket": {
            "type": "string",
            "description": "S3 Bucket name",
            "example": "filespin-labs"
          },
          "key": {
            "type": "string",
            "description": "S3 Object key for this file"
          },
          "public": {
            "type": "boolean",
            "description": "`true` if file is publicly accessible, `false` otherwise"
          },
          "content_type": {
            "type": "string",
            "description": "MIME type",
            "example": "video/quicktime"
          },
          "creator_id": {
            "type": "integer",
            "description": "User ID of file owner",
            "example": 272
          },
          "update_user_id": {
            "type": "integer",
            "description": "User ID of user who last updated the file"
          },
          "upload_time": {
            "type": "string",
            "format": "date-time",
            "description": "ISO 8601 datetime when the original file was uploaded"
          },
          "update_time": {
            "type": "string",
            "format": "date-time",
            "description": "ISO 8601 datetime when the asset metadata was last updated"
          },
          "upload_source": {
            "type": "string",
            "description": "Where the file was sourced from"
          },
          "data_schema_id": {
            "type": "integer",
            "description": "JSON Schema ID for the asset data"
          },
          "metadata": {
            "type": "object",
            "description": "File metadata. For image/video files, `width`, `height` in pixels and `duration` in seconds are always returned.",
            "properties": {
              "width": {
                "type": "integer",
                "example": 1200
              },
              "height": {
                "type": "integer",
                "example": 800
              },
              "duration": {
                "type": "number",
                "description": "Duration in seconds (video/audio)"
              }
            }
          },
          "data": {
            "type": "object",
            "description": "Optional user-data stored along with the asset",
            "additionalProperties": true
          },
          "conversions": {
            "type": "object",
            "description": "Standard image/video conversions and those generated by addons",
            "additionalProperties": true
          },
          "addons_info": {
            "type": "object",
            "description": "Indicates which addons were processed for the asset",
            "additionalProperties": true
          },
          "errors": {
            "type": "object",
            "description": "Errors if any while processing asset",
            "additionalProperties": true
          }
        },
        "example": {
          "id": "99d819953914402babbdeb68337ea6a3",
          "status": "OK",
          "name": "sample.mov",
          "size": 8836363,
          "checksum": "5f5f26bd7c0f62c6e02e44c73d09734e",
          "provider": "local",
          "storage_type": "AMAZON_S3",
          "bucket": "filespin-labs",
          "key": "/99d819953914402babbdeb68337ea6a3/sample.jpg",
          "public": false,
          "content_type": "video/quicktime",
          "creator_id": 272,
          "upload_time": "2015-07-02T08:12:56Z",
          "update_user_id": 272,
          "update_time": "2015-07-02T08:12:56Z",
          "upload_source": "upload.example.com",
          "data_schema_id": 1,
          "metadata": {
            "width": 1200,
            "height": 800,
            "duration": 30
          },
          "data": {
            "foo": "bar"
          },
          "conversions": {
            "720p-video": {
              "storage_type": "s3",
              "bucket": "filespin-labs",
              "key": "/99d819953914402babbdeb68337ea6a3/720p-video.mp4",
              "width": 1280,
              "height": 720,
              "duration": 30,
              "size": 716000,
              "public": true,
              "watermarked": false
            }
          },
          "addons_info": {
            "ON_DEMAND_IMAGE": {
              "available": true
            }
          }
        }
      },
      "BatchProcessRequest": {
        "type": "object",
        "description": "Request to batch process multiple assets. ADMIN role required.",
        "properties": {
          "ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Asset IDs to re-process. Maximum 100."
          },
          "conversions": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "List of conversion keys (e.g. `smart_imaging`, `deepzoom`)"
          },
          "transcodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "List of transcode keys (e.g. `480p-video`, `720p-video`)"
          },
          "addons": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "List of addon keys (e.g. `storyboard`). Addon must be enabled."
          }
        },
        "example": {
          "ids": [
            "7204fbc866d94805ad3fab3e1a194abd"
          ],
          "conversions": [
            "smart_imaging"
          ],
          "transcodes": [
            "480p-video"
          ],
          "addons": [
            "storyboard"
          ]
        }
      },
      "BulkDeleteRequest": {
        "type": "object",
        "description": "Request to bulk delete assets within a date range. ADMIN role required.",
        "required": [
          "start_time",
          "end_time"
        ],
        "properties": {
          "start_time": {
            "type": "string",
            "format": "date-time",
            "description": "Start of date range (ISO 8601). Range is for Asset Upload Time."
          },
          "end_time": {
            "type": "string",
            "format": "date-time",
            "description": "End of date range (ISO 8601). Range is for Asset Upload Time."
          }
        },
        "example": {
          "start_time": "2025-01-20T00:00:00Z",
          "end_time": "2025-01-30T23:59:59Z"
        }
      },
      "CdnPrefetchRequest": {
        "type": "object",
        "description": "CDN prefetch request. Pre-cache assets in CDN.",
        "properties": {
          "asset_urls": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "List of asset URL parts. Maximum 1000 URLs."
          },
          "cache_expiry": {
            "type": "integer",
            "description": "[DEPRECATED] Cache expiry in hours (12-720)"
          }
        },
        "example": {
          "asset_urls": [
            "/video/8e563c1435e643b19fea2d42f2f73948/720p-wm-video.mp4"
          ],
          "cache_expiry": 12
        }
      },
      "CdnPurgeRequest": {
        "type": "object",
        "description": "CDN purge request. Remove cached assets from CDN.",
        "properties": {
          "asset_urls": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "List of asset URL parts. Maximum 1000 URLs."
          }
        },
        "example": {
          "asset_urls": [
            "/api/v1/assets/f99255d2bf8142b29561641491e9940c/transcodes/480p-video.mp4",
            "/api/v1/assets/0c3c6d026858460abc4de1dcb4de15ac/conversions?resize=200,200"
          ]
        }
      },
      "ClipCreateRequest": {
        "type": "object",
        "description": "Request to create a custom video transcode or clip.",
        "required": [
          "name",
          "preset"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Conversion name. Output will be named `name.mp4`."
          },
          "preset": {
            "type": "string",
            "description": "Video transcode preset key",
            "enum": [
              "360p-video",
              "360p-wm-video",
              "480p-video",
              "480p-wm-video",
              "720p-video",
              "720p-wm-video",
              "1080p-video",
              "1080p-wm-video"
            ]
          },
          "start": {
            "description": "Seconds into the video for clip start. Default: 0.",
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "string"
              }
            ]
          },
          "length": {
            "type": "integer",
            "description": "Length of clip in seconds. Default: entire video."
          },
          "public": {
            "type": "boolean",
            "description": "Make output public in storage. Default: `false`."
          },
          "aspect": {
            "type": "string",
            "description": "Aspect handling: `pad`, `preserve`, `scale`, `crop`. Default: `pad`.",
            "enum": [
              "pad",
              "preserve",
              "scale",
              "crop"
            ]
          },
          "padding": {
            "type": "string",
            "description": "Padding color hex code (without #). Default: `000000` (black).",
            "example": "000000"
          },
          "upscale": {
            "type": "boolean",
            "description": "Upscale if original is smaller. Default: `false`."
          },
          "watermark": {
            "type": "object",
            "description": "Custom watermark settings.",
            "properties": {
              "url": {
                "type": "string",
                "description": "URL of watermark image"
              },
              "placement": {
                "type": "string",
                "description": "Position: `top-left`, `top-right`, `bottom-left`, `bottom-right`, `center`"
              },
              "scale": {
                "type": "number",
                "description": "Scale 0-1. 0.1 = 10% of video size."
              }
            }
          }
        },
        "example": {
          "name": "clip_sample",
          "preset": "480p-video",
          "start": 5,
          "length": 30,
          "public": false
        }
      },
      "CollectionCreateRequest": {
        "type": "object",
        "description": "Request to create or duplicate a collection.",
        "properties": {
          "name": {
            "type": "string",
            "description": "Collection name. Defaults to `Collection {timestamp}`"
          },
          "assets": {
            "type": "array",
            "maxItems": 300,
            "items": {
              "type": "string"
            },
            "description": "List of asset IDs. Defaults to empty list. Maximum 300 assets per collection."
          },
          "description": {
            "type": "string",
            "description": "Collection description. Defaults to empty string."
          },
          "group_access": {
            "type": "boolean",
            "description": "`true` or `false`. Defaults to `false`."
          },
          "source_id": {
            "type": "integer",
            "description": "Source Collection ID to duplicate (for duplicate operation)"
          }
        },
        "example": {
          "name": "Test Collection",
          "assets": [
            "b3ad7854e1ad4ce8a8c83272447f980b",
            "caf2b5f2e80a40729e32489ee65ef0d8"
          ]
        }
      },
      "CollectionData": {
        "type": "object",
        "description": "Asset Collection data format.",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Collection ID"
          },
          "user_id": {
            "type": "integer",
            "description": "Collection creator ID"
          },
          "name": {
            "type": "string",
            "description": "Collection name"
          },
          "description": {
            "type": "string",
            "description": "Collection description"
          },
          "last_update": {
            "type": "string",
            "format": "date-time",
            "description": "When the collection was last updated (ISO 8601)"
          },
          "assets": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "List of asset IDs"
          },
          "group_access": {
            "type": "boolean",
            "description": "`true` if assets can be accessed by other users in the user group"
          },
          "user_name": {
            "type": "string",
            "description": "Collection creator name"
          },
          "user_email": {
            "type": "string",
            "format": "email",
            "description": "Collection creator email"
          },
          "extended_result": {
            "type": "object",
            "description": "Asset data keyed by asset ID",
            "additionalProperties": {
              "$ref": "#/components/schemas/AssetData"
            }
          }
        },
        "example": {
          "id": 21,
          "user_id": 45,
          "name": "My Collection",
          "description": "An example description",
          "last_update": "2022-01-24T09:11:05Z",
          "assets": [
            "3b5123160c474720931292c33eb46c52"
          ],
          "group_access": false,
          "user_name": "John Doe",
          "user_email": "john@example.org",
          "extended_result": {}
        }
      },
      "CollectionListResponse": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "OK",
              "ERROR"
            ]
          },
          "data": {
            "type": "object",
            "properties": {
              "total_collections": {
                "type": "integer",
                "description": "Total number of collections"
              },
              "collections": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/CollectionData"
                }
              }
            }
          }
        },
        "example": {
          "status": "OK",
          "data": {
            "total_collections": 1,
            "collections": []
          }
        }
      },
      "CollectionSearchRequest": {
        "type": "object",
        "description": "Search criteria for collections. At least one parameter should be passed.",
        "properties": {
          "keyword": {
            "type": "string",
            "description": "Keyword to match collection name. Defaults to `*` wildcard."
          },
          "private_only": {
            "type": "boolean",
            "description": "Return only private collections. Default: `false`."
          },
          "last_update_range": {
            "type": "object",
            "properties": {
              "start": {
                "type": "string",
                "format": "date-time"
              },
              "end": {
                "type": "string",
                "format": "date-time"
              }
            }
          },
          "sort_by": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Sort fields: `group_access`, `name`, `last_update` with `ASC`/`DESC`"
          },
          "offset": {
            "type": "integer",
            "description": "Pagination offset. Default: 0."
          },
          "limit": {
            "type": "integer",
            "description": "Page limit. Default: 30. Maximum: 30."
          }
        },
        "example": {
          "sort_by": [
            "last_update DESC"
          ],
          "limit": 30,
          "offset": 0
        }
      },
      "DeleteRequest": {
        "type": "object",
        "description": "Request to delete asset conversions or the original.",
        "properties": {
          "keys": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Conversion keys to delete. Use `original` to soft-delete the asset. Use `*` to delete all conversions. Image keys: `deepzoom`, custom keys. Video keys: `480p-video`, `hls-video`, etc."
          }
        },
        "example": {
          "keys": [
            "original"
          ]
        }
      },
      "DuplicatesResponse": {
        "type": "object",
        "description": "Response from find duplicates operation.",
        "properties": {
          "id": {
            "type": "string",
            "description": "Asset's unique ID"
          },
          "name": {
            "type": "string",
            "description": "File name"
          },
          "size": {
            "type": "integer",
            "description": "Size in bytes"
          },
          "content_type": {
            "type": "string",
            "description": "MIME type"
          },
          "checksum": {
            "type": "string",
            "description": "MD5 checksum"
          },
          "total_files": {
            "type": "integer",
            "description": "Number of duplicate files found"
          },
          "total_pages": {
            "type": "integer",
            "description": "Number of pages in result"
          },
          "page": {
            "type": "integer",
            "description": "Current page (default 1)"
          },
          "duplicates": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "List of duplicate asset IDs (up to 30 per page)"
          }
        },
        "example": {
          "id": "99d819953914402babbdeb68337ea6a3",
          "name": "example.jpg",
          "size": 8836363,
          "content_type": "image/jpeg",
          "checksum": "5f5f26bd7c0f62c6e02e44c73d09734e",
          "total_files": 2,
          "total_pages": 1,
          "page": 1,
          "duplicates": [
            "425f6a2a266d45d58d067f7c39a2e4bd",
            "a563da2a266d45d58d067b8c39a3d5ad"
          ]
        }
      },
      "IngestFromUriRequest": {
        "type": "object",
        "description": "Request to ingest a file from an external HTTP URL or S3 bucket.",
        "required": [
          "name",
          "key"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "File name for the new asset"
          },
          "key": {
            "type": "string",
            "description": "S3 URI (e.g. `s3://my-bucket/test.jpg`) or HTTPS URL (e.g. `https://example.com/test.jpg`)"
          }
        },
        "example": {
          "name": "test.jpg",
          "key": "https://example.com/test.jpg"
        }
      },
      "IngestResponse": {
        "type": "object",
        "description": "Response from ingest-from-URI operation.",
        "properties": {
          "id": {
            "type": "string",
            "description": "Asset ID, 32 character alphanumeric UUID"
          },
          "status": {
            "type": "string",
            "description": "`QUEUED` if request was successfully received, `ERROR` if request cannot be processed",
            "enum": [
              "QUEUED",
              "ERROR"
            ]
          },
          "message": {
            "type": "string",
            "description": "Additional details about status"
          }
        },
        "example": {
          "id": "ceace459cd2a4d2c904e38e9ab352ebb",
          "status": "QUEUED",
          "message": "Queued for processing"
        }
      },
      "JobList": {
        "type": "object",
        "description": "Paginated list of jobs.",
        "properties": {
          "count": {
            "type": "integer",
            "description": "Number of jobs returned in this response"
          },
          "limit": {
            "type": "integer",
            "description": "Page limit (default 30)"
          },
          "offset": {
            "type": "integer",
            "description": "Record offset (default 0)"
          },
          "total": {
            "type": "integer",
            "description": "Total number of jobs initiated by the caller"
          },
          "jobs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/JobStatus"
            },
            "description": "List of job records"
          }
        },
        "example": {
          "count": 15,
          "limit": 30,
          "offset": 0,
          "total": 15,
          "jobs": []
        }
      },
      "JobStatus": {
        "type": "object",
        "description": "Job status information.",
        "properties": {
          "status": {
            "type": "string",
            "description": "Job status",
            "enum": [
              "QUEUED",
              "IN_PROGRESS",
              "COMPLETED",
              "ERROR"
            ]
          },
          "message": {
            "type": "string",
            "description": "On ERROR, contains the error message for diagnosis"
          },
          "job_id": {
            "type": "integer",
            "description": "Job ID for tracking"
          },
          "creator_id": {
            "type": "integer",
            "description": "ID of the user who initiated the job"
          },
          "requested_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the job request was received"
          },
          "completed_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the job completed"
          },
          "job_steps": {
            "type": "object",
            "description": "Job steps and step completion timestamps. Steps vary by job type.",
            "additionalProperties": true
          },
          "input": {
            "type": "object",
            "description": "The API request JSON that created this job"
          },
          "callback": {
            "type": "object",
            "description": "The callback JSON issued if job completed. Empty if not completed yet."
          },
          "type": {
            "type": "string",
            "description": "Job type",
            "example": "VIDEO_TRANSCODE"
          }
        },
        "example": {
          "status": "COMPLETED",
          "message": "",
          "job_id": 1234,
          "creator_id": 272,
          "requested_at": "2017-04-20T16:08:02Z",
          "completed_at": "2017-04-20T16:08:02Z",
          "job_steps": {},
          "input": {},
          "callback": {},
          "type": "VIDEO_TRANSCODE"
        }
      },
      "LoginResponse": {
        "type": "object",
        "properties": {
          "user_id": {
            "type": "integer",
            "description": "Unique user identifier",
            "example": 42
          },
          "user_email": {
            "type": "string",
            "description": "User's email address",
            "example": "user@example.org"
          },
          "username": {
            "type": "string",
            "description": "User name",
            "example": "John Doe"
          },
          "jwt": {
            "type": "string",
            "description": "JSON Web Token for subsequent API calls"
          },
          "role_id": {
            "type": "integer",
            "description": "User role ID (1=ADMIN, 2=MANAGER, 3=USER, 4=CREATOR)",
            "example": 1
          },
          "role_name": {
            "type": "string",
            "description": "User role name",
            "example": "ADMIN"
          },
          "permissions": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "List of permission tokens for this user's role",
            "example": [
              "CREATE_ASSET",
              "READ_ASSET",
              "EDIT_ASSET"
            ]
          },
          "uploadkey": {
            "type": "string",
            "description": "File upload key for use in Picker widget"
          },
          "accessID": {
            "type": "string",
            "description": "Access identifier for signed URL generation"
          },
          "preferences": {
            "type": "object",
            "description": "User preferences"
          },
          "notifications": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "List of notification messages since last login",
            "example": [
              "Notification message 1"
            ]
          }
        }
      },
      "NotificationList": {
        "type": "object",
        "description": "List of user notifications.",
        "properties": {
          "notifications": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "integer",
                  "description": "Notification ID, used for disposing"
                },
                "message": {
                  "type": "string",
                  "description": "Notification text"
                },
                "url": {
                  "type": "string",
                  "nullable": true,
                  "description": "Associated URL"
                },
                "disposal": {
                  "type": "string",
                  "description": "`ON_READ` = disposed when retrieved, `ON_ACK` = must call Delete API",
                  "enum": [
                    "ON_READ",
                    "ON_ACK"
                  ]
                },
                "timestamp": {
                  "type": "string",
                  "format": "date-time",
                  "description": "When the notification was issued"
                }
              }
            }
          }
        },
        "example": {
          "notifications": [
            {
              "id": 2,
              "message": "Collection updated by joe@example.org",
              "url": "/collection/1",
              "disposal": "ON_ACK",
              "timestamp": "2022-05-14T07:08:49Z"
            },
            {
              "id": 1,
              "message": "Welcome! New notifications will appear here.",
              "url": null,
              "disposal": "ON_READ",
              "timestamp": "2022-05-15T07:08:15Z"
            }
          ]
        }
      },
      "ProcessingResponse": {
        "type": "object",
        "description": "Response from asset processing operations (process, clip, batch).",
        "properties": {
          "status": {
            "type": "string",
            "description": "Processing status",
            "enum": [
              "QUEUED",
              "ERROR"
            ]
          },
          "message": {
            "type": "string",
            "description": "Message describing the status"
          },
          "job_id": {
            "type": "integer",
            "description": "Job ID for tracking. Can be used with Job Status API."
          }
        },
        "example": {
          "status": "QUEUED",
          "message": "Job queued",
          "job_id": 42
        }
      },
      "PublicAccessRequest": {
        "type": "object",
        "description": "Request to set or remove public access on asset files.",
        "properties": {
          "keys": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Keys to make public/private. `original` for the asset file. Image: `deepzoom`, custom keys. Video: `360p-video`, `480p-video`, `720p-video`, `1080p-video`, `hls-video`, and watermarked variants."
          }
        },
        "example": {
          "keys": [
            "original",
            "720p-video"
          ]
        }
      },
      "SearchRequest": {
        "type": "object",
        "description": "Search criteria for finding assets. All parameters are optional.",
        "properties": {
          "keyword": {
            "type": "string",
            "description": "Search keywords. Includes keywords in reserved `filespin_search_txt` field or custom schema fields with `keyword_searchable` set to `true`. Use `OR` to match any word, `AND` to match all. Cannot contain more than 40 words."
          },
          "ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "List of asset IDs to filter by. Maximum 100 IDs.",
            "example": [
              "116f6a2a266d45d58d067f7c39a2e4dd"
            ]
          },
          "file_name": {
            "type": "string",
            "description": "File name filter. `*` wildcard allowed in suffix. Use `OR` for multiple patterns."
          },
          "content_type": {
            "type": "string",
            "description": "MIME type filter. `*` wildcard allowed. Use `OR` for multiple types, e.g. `image* OR video*`"
          },
          "creator_id": {
            "type": "integer",
            "description": "Filter by creator user ID. Caller must be in same user group."
          },
          "upload_time_range": {
            "type": "object",
            "description": "ISO 8601 datetime range (inclusive, UTC)",
            "properties": {
              "start": {
                "type": "string",
                "format": "date-time"
              },
              "end": {
                "type": "string",
                "format": "date-time"
              }
            }
          },
          "file_size_range": {
            "type": "object",
            "description": "File size range in bytes (inclusive). 1 KiB = 1024, 1 MiB = 1048576.",
            "properties": {
              "start": {
                "type": "integer"
              },
              "end": {
                "type": "integer"
              }
            }
          },
          "sort_by": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Sort keys: `file_name`, `content_type`, `upload_time_range`, `file_size_range`. Append `_ASC` or `_DESC`. Default: `upload_time_range_DESC`."
          },
          "limit_per_page": {
            "type": "integer",
            "description": "Results per page, 1-30. Default: 30.",
            "minimum": 1,
            "maximum": 30,
            "default": 30
          },
          "extended_result": {
            "type": "boolean",
            "description": "Set `true` to include complete asset data for each result. Slower.",
            "default": false
          },
          "trashed": {
            "type": "boolean",
            "description": "Set `true` to search deleted (not purged) assets. Requires Admin role.",
            "default": false
          },
          "addons_criteria": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter by addon IDs, e.g. `[\"FACE_RECOGNITION\", \"ON_DEMAND_IMAGE\"]`"
          },
          "schema_criteria": {
            "type": "object",
            "description": "Search on custom schema fields. Requires `data_schema_id`.",
            "properties": {
              "data_schema_id": {
                "type": "integer",
                "description": "Asset Data Schema ID to search on"
              },
              "fields": {
                "type": "object",
                "description": "Field name and search value pairs",
                "additionalProperties": true
              }
            }
          }
        },
        "example": {
          "keyword": "sample",
          "content_type": "image* OR video*",
          "upload_time_range": {
            "start": "2013-01-01T10:25:11Z",
            "end": "2013-02-01T10:25:11Z"
          },
          "sort_by": [
            "upload_time_range_DESC"
          ],
          "limit_per_page": 30,
          "extended_result": false
        }
      },
      "SearchResponse": {
        "type": "object",
        "description": "Search results with pagination.",
        "properties": {
          "status": {
            "type": "string",
            "description": "`OK` if search was successful, `ERROR` otherwise",
            "enum": [
              "OK",
              "ERROR"
            ]
          },
          "search_result_id": {
            "type": "string",
            "description": "Alphanumeric ID (10-32 chars), valid for 60 minutes. Use with GET to retrieve additional pages."
          },
          "total_files": {
            "type": "integer",
            "description": "Total number of files found"
          },
          "page": {
            "type": "integer",
            "description": "Current page index"
          },
          "total_pages": {
            "type": "integer",
            "description": "Total number of pages in the result"
          },
          "result": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "List of asset IDs (up to 30 per page)"
          },
          "extended_result": {
            "type": "object",
            "description": "When requested, contains full asset data keyed by asset ID",
            "additionalProperties": {
              "$ref": "#/components/schemas/AssetData"
            }
          },
          "query_criteria": {
            "type": "object",
            "description": "Original search query criteria from the POST request body. Only present when authenticated via JWT Bearer token or OAuth2 token (not included for API key requests).",
            "additionalProperties": true
          }
        },
        "example": {
          "status": "OK",
          "search_result_id": "0a9761f2f9",
          "total_files": 1,
          "page": 1,
          "total_pages": 1,
          "result": [
            "116f6a2a266d45d58d067f7c39a2e4dd"
          ],
          "query_criteria": {
            "keyword": "sunset",
            "content_type": "image",
            "sort_by": [
              "upload_time_range_DESC"
            ]
          }
        }
      },
      "UpdateDataRequest": {
        "type": "object",
        "description": "Request to update asset custom metadata.",
        "required": [
          "data",
          "mode"
        ],
        "properties": {
          "data": {
            "type": "object",
            "description": "JSON data to save with the asset. Fields starting with `_filespin` are reserved and not user-updateable.",
            "additionalProperties": true
          },
          "mode": {
            "type": "string",
            "description": "`APPEND` merges with existing data (overwrites matching keys). `REPLACE` overwrites all existing data.",
            "enum": [
              "APPEND",
              "REPLACE"
            ]
          },
          "data_schema_id": {
            "type": "integer",
            "description": "Optional schema ID to assign. If data doesn't conform to schema, searchable fields won't be indexed."
          }
        },
        "example": {
          "data": {
            "input1": "value1",
            "input2": "value2",
            "filespin_search_txt": "MY_OWN_FILE_ID"
          },
          "mode": "APPEND",
          "data_schema_id": 1
        }
      },
      "UploadResponse": {
        "type": "object",
        "description": "Response from asset upload or replace operations.",
        "properties": {
          "files": {
            "type": "array",
            "description": "List of uploaded files",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "description": "Asset ID, 32 character alphanumeric UUID"
                },
                "name": {
                  "type": "string",
                  "description": "File name"
                },
                "size": {
                  "type": "integer",
                  "description": "Size of file in bytes"
                },
                "checksum": {
                  "type": "string",
                  "description": "MD5 checksum"
                },
                "content_type": {
                  "type": "string",
                  "description": "MIME type"
                },
                "metadata": {
                  "type": "object",
                  "description": "Image metadata (when available). Exiftool values for ColorMode, ColorSpace, Orientation, Make, Model. Width and Height are always returned.",
                  "properties": {
                    "width": {
                      "type": "integer"
                    },
                    "height": {
                      "type": "integer"
                    },
                    "Make": {
                      "type": "string"
                    },
                    "Model": {
                      "type": "string"
                    },
                    "ColorSpace": {
                      "type": "string"
                    },
                    "Orientation": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "success": {
            "type": "boolean",
            "description": "`true` if upload completed, `false` otherwise"
          },
          "provider": {
            "type": "string",
            "description": "Always `local` to indicate local upload"
          }
        },
        "example": {
          "files": [
            {
              "id": "99d819953914402babbdeb68337ea6a3",
              "name": "sample.jpg",
              "size": 8836363,
              "checksum": "5f5f26bd7c0f62c6e02e44c73d09734e",
              "content_type": "image/jpeg",
              "metadata": {
                "Make": "Apple",
                "ColorSpace": "sRGB",
                "Model": "iPhone 3G",
                "Orientation": "Horizontal (normal)",
                "width": 1200,
                "height": 800
              }
            }
          ],
          "success": true,
          "provider": "local"
        }
      },
      "UserListResponse": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "OK",
              "ERROR"
            ]
          },
          "total_users": {
            "type": "integer"
          },
          "count": {
            "type": "integer"
          },
          "users": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UserProfile"
            }
          }
        },
        "example": {
          "status": "OK",
          "total_users": 60,
          "count": 30,
          "users": []
        }
      },
      "UserProfile": {
        "type": "object",
        "description": "User profile data format used across all User API responses.",
        "properties": {
          "id": {
            "type": "integer",
            "description": "User ID"
          },
          "access_id": {
            "type": "string",
            "description": "Access ID, used for signing requests for CDN APIs"
          },
          "apikey": {
            "type": "string",
            "description": "API Key for making API requests. Do not share."
          },
          "email": {
            "type": "string",
            "format": "email",
            "description": "User email"
          },
          "first_name": {
            "type": "string",
            "description": "First name"
          },
          "last_name": {
            "type": "string",
            "description": "Last name"
          },
          "enabled": {
            "type": "boolean",
            "description": "`true` if user is enabled, `false` if disabled"
          },
          "invite_status": {
            "type": "string",
            "description": "`REQUESTED` = login not activated yet, `REGISTERED` = activated and ready",
            "enum": [
              "REQUESTED",
              "REGISTERED"
            ]
          },
          "role_id": {
            "type": "integer",
            "description": "Role ID"
          },
          "group_id": {
            "type": "string",
            "description": "User group ID"
          },
          "locale": {
            "type": "string",
            "description": "Default user locale",
            "example": "en_US"
          },
          "permissions": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "List of permission tokens determined by user role"
          },
          "role_name": {
            "type": "string",
            "description": "Role name (built-in)",
            "enum": [
              "ADMIN",
              "MANAGER",
              "CREATOR",
              "USER"
            ]
          },
          "uploadKey": {
            "type": "string",
            "description": "Upload Key for FileSpin Picker file uploads"
          },
          "group_asset_access": {
            "type": "boolean",
            "description": "If `true`, user can access assets created by all users in the group"
          },
          "addons": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Addons available for the user"
          }
        },
        "example": {
          "id": 42,
          "access_id": "IZJTAMBQGAYDAMBQGAYDAMBQGAYDANKT",
          "apikey": "your-api-key",
          "email": "user@example.org",
          "first_name": "John",
          "last_name": "Doe",
          "enabled": true,
          "invite_status": "REGISTERED",
          "role_id": 1,
          "group_id": "42",
          "locale": "en_US",
          "permissions": [],
          "role_name": "ADMIN",
          "uploadKey": "upload-key",
          "group_asset_access": true,
          "addons": [
            "ON_DEMAND_IMAGE"
          ]
        }
      },
      "UserSearchRequest": {
        "type": "object",
        "description": "Search/filter criteria for users.",
        "properties": {
          "email": {
            "type": "string",
            "description": "Partial email match (no wildcards)"
          },
          "first_name": {
            "type": "string",
            "description": "Partial first name match"
          },
          "last_name": {
            "type": "string",
            "description": "Partial last name match"
          },
          "enabled_only": {
            "type": "boolean",
            "description": "Only retrieve enabled users"
          },
          "offset": {
            "type": "integer",
            "description": "Pagination offset. Default: 0."
          }
        },
        "example": {
          "email": "user@example",
          "enabled_only": true,
          "offset": 0
        }
      },
      "add-conversion": {
        "type": "object",
        "properties": {
          "file": {
            "type": "string"
          }
        }
      },
      "bg_remove_save_response": {
        "type": "object",
        "description": "JSON response returned when `mode=save_image`.",
        "required": [
          "status",
          "mode",
          "disposition"
        ],
        "properties": {
          "status": {
            "type": "string",
            "description": "Operation status.",
            "example": "ok"
          },
          "mode": {
            "type": "string",
            "description": "The processing mode used.",
            "enum": [
              "save_image"
            ],
            "example": "save_image"
          },
          "disposition": {
            "type": "string",
            "description": "The disposition used.",
            "enum": [
              "add_conversion",
              "add_new_asset"
            ],
            "example": "add_conversion"
          },
          "asset_id": {
            "type": "string",
            "description": "Asset ID of the target asset (present when `disposition=add_conversion`).",
            "example": "a211ab5f351f4b398426efb59b0c72a3"
          },
          "conversion_name": {
            "type": "string",
            "description": "Name of the conversion created (present when `disposition=add_conversion`).",
            "example": "bg_removed"
          },
          "new_asset_id": {
            "type": "string",
            "description": "Asset ID of the newly created asset (present when `disposition=add_new_asset` and save succeeds).",
            "example": "b322bc6f462g5c409537fg63270b1b94"
          },
          "source_asset_id": {
            "type": "string",
            "description": "Source asset ID used for metadata inheritance (present when `metadata=inherit` was provided).",
            "example": "a211ab5f351f4b398426efb59b0c72a3"
          },
          "metadata": {
            "type": "string",
            "description": "Metadata option used (present when `metadata=inherit` was provided).",
            "enum": [
              "inherit"
            ],
            "example": "inherit"
          }
        }
      },
      "create": {
        "type": "object",
        "properties": {
          "name": {
            "type": "object",
            "properties": {
              "en": {
                "type": "string"
              }
            }
          },
          "status": {
            "type": "string"
          },
          "schema": {
            "type": "object",
            "properties": {
              "$id": {
                "type": "string"
              },
              "$schema": {
                "type": "string"
              },
              "type": {
                "type": "string"
              },
              "title": {
                "type": "string"
              },
              "required": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "properties": {
                "type": "object",
                "properties": {
                  "alist": {
                    "type": "object",
                    "properties": {
                      "title": {
                        "type": "string"
                      },
                      "type": {
                        "type": "string"
                      },
                      "items": {
                        "type": "object",
                        "properties": {
                          "title": {
                            "type": "string"
                          },
                          "type": {
                            "type": "string"
                          },
                          "description": {
                            "type": "string"
                          },
                          "hint": {
                            "type": "string"
                          },
                          "minLength": {
                            "type": "number"
                          },
                          "maxLength": {
                            "type": "number"
                          }
                        }
                      },
                      "description": {
                        "type": "string"
                      },
                      "filespin_properties": {
                        "type": "object",
                        "properties": {
                          "title": {
                            "type": "object",
                            "properties": {
                              "en": {
                                "type": "string"
                              }
                            }
                          },
                          "hint": {
                            "type": "object",
                            "properties": {
                              "en": {
                                "type": "string"
                              }
                            }
                          },
                          "placeholder": {
                            "type": "object",
                            "properties": {
                              "en": {
                                "type": "string"
                              }
                            }
                          },
                          "keyword_searchable": {
                            "type": "boolean"
                          },
                          "searchable": {
                            "type": "boolean"
                          },
                          "ui": {
                            "type": "object",
                            "properties": {
                              "order": {
                                "type": "number"
                              },
                              "readonly": {
                                "type": "boolean"
                              },
                              "disabled": {
                                "type": "boolean"
                              },
                              "hidden": {
                                "type": "boolean"
                              }
                            }
                          }
                        }
                      }
                    }
                  },
                  "anumber": {
                    "type": "object",
                    "properties": {
                      "title": {
                        "type": "string"
                      },
                      "type": {
                        "type": "string"
                      },
                      "description": {
                        "type": "string"
                      },
                      "minLength": {
                        "type": "number"
                      },
                      "maxLength": {
                        "type": "number"
                      },
                      "filespin_properties": {
                        "type": "object",
                        "properties": {
                          "title": {
                            "type": "object",
                            "properties": {
                              "en": {
                                "type": "string"
                              }
                            }
                          },
                          "hint": {
                            "type": "object",
                            "properties": {
                              "en": {
                                "type": "string"
                              }
                            }
                          },
                          "placeholder": {
                            "type": "object",
                            "properties": {
                              "en": {
                                "type": "string"
                              }
                            }
                          },
                          "keyword_searchable": {
                            "type": "boolean"
                          },
                          "searchable": {
                            "type": "boolean"
                          },
                          "ui": {
                            "type": "object",
                            "properties": {
                              "order": {
                                "type": "number"
                              },
                              "readonly": {
                                "type": "boolean"
                              },
                              "disabled": {
                                "type": "boolean"
                              },
                              "hidden": {
                                "type": "boolean"
                              }
                            }
                          }
                        }
                      }
                    }
                  },
                  "adate": {
                    "type": "object",
                    "properties": {
                      "title": {
                        "type": "string"
                      },
                      "type": {
                        "type": "string"
                      },
                      "format": {
                        "type": "string"
                      },
                      "description": {
                        "type": "string"
                      },
                      "minLength": {
                        "type": "number"
                      },
                      "maxLength": {
                        "type": "number"
                      },
                      "filespin_properties": {
                        "type": "object",
                        "properties": {
                          "title": {
                            "type": "object",
                            "properties": {
                              "en": {
                                "type": "string"
                              }
                            }
                          },
                          "hint": {
                            "type": "object",
                            "properties": {
                              "en": {
                                "type": "string"
                              }
                            }
                          },
                          "placeholder": {
                            "type": "object",
                            "properties": {
                              "en": {
                                "type": "string"
                              }
                            }
                          },
                          "keyword_searchable": {
                            "type": "boolean"
                          },
                          "searchable": {
                            "type": "boolean"
                          },
                          "ui": {
                            "type": "object",
                            "properties": {
                              "order": {
                                "type": "number"
                              },
                              "readonly": {
                                "type": "boolean"
                              },
                              "disabled": {
                                "type": "boolean"
                              },
                              "hidden": {
                                "type": "boolean"
                              }
                            }
                          }
                        }
                      }
                    }
                  },
                  "anemail": {
                    "type": "object",
                    "properties": {
                      "title": {
                        "type": "string"
                      },
                      "type": {
                        "type": "string"
                      },
                      "format": {
                        "type": "string"
                      },
                      "minLength": {
                        "type": "number"
                      },
                      "maxLength": {
                        "type": "number"
                      },
                      "filespin_properties": {
                        "type": "object",
                        "properties": {
                          "title": {
                            "type": "object",
                            "properties": {
                              "en": {
                                "type": "string"
                              }
                            }
                          },
                          "hint": {
                            "type": "object",
                            "properties": {
                              "en": {
                                "type": "string"
                              }
                            }
                          },
                          "placeholder": {
                            "type": "object",
                            "properties": {
                              "en": {
                                "type": "string"
                              }
                            }
                          },
                          "keyword_searchable": {
                            "type": "boolean"
                          },
                          "searchable": {
                            "type": "boolean"
                          },
                          "ui": {
                            "type": "object",
                            "properties": {
                              "order": {
                                "type": "number"
                              },
                              "readonly": {
                                "type": "boolean"
                              },
                              "disabled": {
                                "type": "boolean"
                              },
                              "hidden": {
                                "type": "boolean"
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "create_user": {
        "type": "object",
        "required": [
          "first_name",
          "last_name",
          "email",
          "role_id"
        ],
        "properties": {
          "first_name": {
            "type": "string"
          },
          "last_name": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "role_id": {
            "type": "string"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the user account is enabled. Defaults to true."
          },
          "group_asset_access": {
            "type": "boolean",
            "description": "If true, user can access assets created by all users in the group."
          },
          "template_user_id": {
            "type": "integer",
            "description": "Copy settings from this user. Must be in the same group. Defaults to the creating admin."
          }
        }
      },
      "delete_collection": {
        "type": "object",
        "properties": {}
      },
      "delete_data": {
        "type": "object",
        "properties": {
          "ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "start_time": {
            "type": "string"
          },
          "end_time": {
            "type": "string"
          }
        }
      },
      "face_recognition": {
        "type": "object",
        "properties": {
          "disposition": {
            "type": "object",
            "properties": {
              "update_metadata": {
                "type": "boolean"
              }
            }
          }
        }
      },
      "get_jwt_and_basic_user_info": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string"
          },
          "password": {
            "type": "string"
          },
          "remember_me": {
            "type": "boolean",
            "default": false,
            "description": "When true, the JWT token will be valid for 30 days instead of the default 1 day."
          }
        }
      },
      "multiple_asset": {
        "type": "array",
        "items": {
          "type": "string"
        }
      },
      "process": {
        "type": "object",
        "properties": {
          "keys": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "reissue_callbacks": {
        "type": "object",
        "properties": {
          "start_time": {
            "type": "string"
          },
          "end_time": {
            "type": "string"
          }
        }
      },
      "replace": {
        "type": "object",
        "properties": {
          "file": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "undelete": {
        "type": "object",
        "properties": {
          "keys": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "update": {
        "type": "object",
        "properties": {
          "id": {
            "type": "number"
          },
          "name": {
            "type": "object",
            "properties": {
              "en": {
                "type": "string"
              }
            }
          },
          "status": {
            "type": "string"
          },
          "schema": {
            "type": "object",
            "properties": {
              "$schema": {
                "type": "string"
              },
              "type": {
                "type": "string"
              },
              "title": {
                "type": "string"
              },
              "required": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "properties": {
                "type": "object",
                "properties": {
                  "example_field": {
                    "type": "object",
                    "properties": {
                      "type": {
                        "type": "string"
                      },
                      "description": {
                        "type": "string"
                      },
                      "minLength": {
                        "type": "number"
                      },
                      "maxLength": {
                        "type": "number"
                      },
                      "filespin_properties": {
                        "type": "object",
                        "properties": {
                          "title": {
                            "type": "object",
                            "properties": {
                              "en": {
                                "type": "string"
                              }
                            }
                          },
                          "hint": {
                            "type": "object",
                            "properties": {
                              "en": {
                                "type": "string"
                              }
                            }
                          },
                          "placeholder": {
                            "type": "object",
                            "properties": {
                              "en": {
                                "type": "string"
                              }
                            }
                          },
                          "searchable": {
                            "type": "boolean"
                          },
                          "ui": {
                            "type": "object",
                            "properties": {
                              "order": {
                                "type": "number"
                              },
                              "readonly": {
                                "type": "boolean"
                              },
                              "disabled": {
                                "type": "boolean"
                              },
                              "hidden": {
                                "type": "boolean"
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "update_addons_settings": {
        "type": "object",
        "properties": {
          "event-hooks": {
            "type": "object",
            "properties": {
              "file-saved": {
                "type": "object",
                "properties": {
                  "enabled": {
                    "type": "boolean"
                  },
                  "content_types": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              },
              "disposition": {
                "type": "object",
                "properties": {
                  "update_metadata": {
                    "type": "boolean"
                  },
                  "pass_through_fields": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "confidence_threshold": {
                    "type": "number"
                  }
                }
              },
              "file-deleted": {
                "type": "object",
                "properties": {
                  "enabled": {
                    "type": "boolean"
                  },
                  "content_types": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              },
              "file-data-updated": {
                "type": "object",
                "properties": {
                  "enabled": {
                    "type": "boolean"
                  },
                  "content_types": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "schema_criteria": {
                    "type": "object",
                    "properties": {
                      "data_schema_id": {
                        "type": "number"
                      },
                      "fields": {
                        "type": "object",
                        "properties": {
                          "field1": {
                            "type": "string"
                          },
                          "field2": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "update_collection": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "New collection name"
          },
          "description": {
            "type": "string",
            "description": "New collection description"
          },
          "group_access": {
            "type": "boolean",
            "description": "`true` to share with group, `false` for private"
          },
          "additions": {
            "type": "array",
            "maxItems": 300,
            "items": {
              "type": "string"
            },
            "description": "Asset IDs to add to the collection. Total asset count after merge cannot exceed 300."
          },
          "deletions": {
            "type": "array",
            "maxItems": 300,
            "items": {
              "type": "string"
            },
            "description": "Asset IDs to remove from the collection"
          },
          "source_id": {
            "type": "integer",
            "description": "Collection ID whose assets will be merged into additions"
          }
        }
      },
      "update_settings": {
        "type": "object",
        "description": "Partial settings update. Send one key/value pair per request.",
        "required": [
          "key",
          "value"
        ],
        "properties": {
          "key": {
            "type": "string",
            "enum": [
              "storage",
              "webhook",
              "database",
              "image",
              "video",
              "addons",
              "watermark"
            ],
            "description": "Settings section to update"
          },
          "value": {
            "type": "object",
            "description": "Section-specific payload. Structure varies by key. See endpoint description."
          }
        }
      },
      "upload": {
        "type": "object",
        "properties": {
          "file": {
            "type": "string"
          }
        }
      }
    },
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "X-FileSpin-Api-Key",
        "description": "API key for programmatic access"
      },
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "JWT token obtained from POST /api/v1/login"
      }
    }
  },
  "externalDocs": {
    "description": "FileSpin Developer Portal",
    "url": "https://developers.filespin.io"
  }
}
