SSpiderIQ
SSpiderIQ

Docs / api-reference/media-library

Media Library

7 endpoints from the published OpenAPI import.

GET/api/v1/dashboard/media/catalog/assets

List Catalog Assets

List the tenant's media assets, newest first (soft-delete aware).

Filters are AND-combined. The effective client_id is resolved by require_content_scoped_user_or_api_client (session user or API client; header/brand/super-admin selection). Use ?format=yaml or ?format=md for agent-friendly responses.

Parameters

NameInTypeRequiredDescription
kindqueryanyfalseFilter by asset class: image | video | doc
folderqueryanyfalseFilter by exact DAM folder path
tagsqueryanyfalseFilter to assets carrying ALL given tags
statusqueryanyfalseFilter by status: pending | processing | ready | failed
storage_tierqueryanyfalseFilter by storage tier: seaweedfs | r2 | peertube
limitqueryintegerfalsePage size (1-500)
offsetqueryintegerfalsePagination offset
formatqueryanyfalseResponse format. json (default) and llm return JSON; yaml returns text/yaml; md returns text/markdown. Any other value is a 422.
Try it
Query

Examples

cURL
curl -X GET 'https://spideriq.ai/api/v1/dashboard/media/catalog/assets' \
  -H 'Authorization: Bearer <token>'
Python
import httpx

resp = httpx.get(
    "https://spideriq.ai/api/v1/dashboard/media/catalog/assets",
    headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())
JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/media/catalog/assets", {
  method: "GET",
  headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);
Go
package main

import (
	"net/http"
)

func main() {
	req, _ := http.NewRequest("GET", "https://spideriq.ai/api/v1/dashboard/media/catalog/assets", nil)
	req.Header.Set("Authorization", "Bearer <token>")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}

Responses

StatusDescription
200Successful Response
422Validation Error
GET/api/v1/dashboard/media/catalog/counts

Count Catalog Assets

Aggregate counts over the tenant's WHOLE catalog (soft-delete aware).

Returns {total, by_kind, by_tier} — the TRUE totals the Library's filter chips need (FX2a). The dashboard previously computed chip counts client-side over a newest-200 page, so anything past the first page was uncounted (the "Images 0" bug when the newest 200 rows were all videos). This server-side surface counts every matching row in one GROUPING SETS pass.

Filters are AND-combined and mirror the list endpoint exactly, so the counts honour the same filter the grid is paging under. The effective client_id is resolved by require_content_scoped_user_or_api_client.

Parameters

NameInTypeRequiredDescription
kindqueryanyfalseFilter by asset class: image | video | doc
folderqueryanyfalseFilter by exact DAM folder path
tagsqueryanyfalseFilter to assets carrying ALL given tags
statusqueryanyfalseFilter by status: pending | processing | ready | failed
storage_tierqueryanyfalseFilter by storage tier: seaweedfs | r2 | peertube
formatqueryanyfalseResponse format. json (default) and llm return JSON; yaml returns text/yaml; md returns text/markdown. Any other value is a 422.
Try it
Query

Examples

cURL
curl -X GET 'https://spideriq.ai/api/v1/dashboard/media/catalog/counts' \
  -H 'Authorization: Bearer <token>'
Python
import httpx

resp = httpx.get(
    "https://spideriq.ai/api/v1/dashboard/media/catalog/counts",
    headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())
JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/media/catalog/counts", {
  method: "GET",
  headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);
Go
package main

import (
	"net/http"
)

func main() {
	req, _ := http.NewRequest("GET", "https://spideriq.ai/api/v1/dashboard/media/catalog/counts", nil)
	req.Header.Set("Authorization", "Bearer <token>")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}

Responses

StatusDescription
200Successful Response
422Validation Error
GET/api/v1/dashboard/media/catalog/search

Search Catalog Assets

Search the tenant's media assets.

q substring-matches key/folder; tags overlaps (ANY); kind narrows by type. All optional + AND-combined, newest first. Mirrors the 1.1 search surface (metadata containment stays service-only — it needs a typed JSON body; q + tags + kind cover the dashboard discovery path).

Parameters

NameInTypeRequiredDescription
qqueryanyfalseCase-insensitive substring match on key/folder
kindqueryanyfalseFilter by asset class: image | video | doc
tagsqueryanyfalseFilter to assets sharing ANY given tag
limitqueryintegerfalsePage size (1-500)
formatqueryanyfalseResponse format. json (default) and llm return JSON; yaml returns text/yaml; md returns text/markdown. Any other value is a 422.
Try it
Query

Examples

cURL
curl -X GET 'https://spideriq.ai/api/v1/dashboard/media/catalog/search' \
  -H 'Authorization: Bearer <token>'
Python
import httpx

resp = httpx.get(
    "https://spideriq.ai/api/v1/dashboard/media/catalog/search",
    headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())
JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/media/catalog/search", {
  method: "GET",
  headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);
Go
package main

import (
	"net/http"
)

func main() {
	req, _ := http.NewRequest("GET", "https://spideriq.ai/api/v1/dashboard/media/catalog/search", nil)
	req.Header.Set("Authorization", "Bearer <token>")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}

Responses

StatusDescription
200Successful Response
422Validation Error
GET/api/v1/dashboard/media/catalog/assets/{asset_id}

Get Catalog Asset

Fetch a single media asset by id. 404 if it does not exist for the tenant.

Parameters

NameInTypeRequiredDescription
asset_idpathstringtrue
formatqueryanyfalseResponse format. json (default) and llm return JSON; yaml returns text/yaml; md returns text/markdown. Any other value is a 422.
Try it
Query

Examples

cURL
curl -X GET 'https://spideriq.ai/api/v1/dashboard/media/catalog/assets/{asset_id}' \
  -H 'Authorization: Bearer <token>'
Python
import httpx

resp = httpx.get(
    "https://spideriq.ai/api/v1/dashboard/media/catalog/assets/{asset_id}",
    headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())
JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/media/catalog/assets/{asset_id}", {
  method: "GET",
  headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);
Go
package main

import (
	"net/http"
)

func main() {
	req, _ := http.NewRequest("GET", "https://spideriq.ai/api/v1/dashboard/media/catalog/assets/{asset_id}", nil)
	req.Header.Set("Authorization", "Bearer <token>")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}

Responses

StatusDescription
200Successful Response
422Validation Error
PATCH/api/v1/dashboard/media/catalog/assets/{asset_id}

Update Catalog Asset

Patch a media asset's mutable fields (folder / tags / status / metadata).

True PATCH — only the fields present in the body are written. alt_text and metadata both fold into a shallow JSONB merge (editing alt-text preserves content_hash etc.). 200 + the updated asset; 404 if no live asset with that id exists for the tenant.

Parameters

NameInTypeRequiredDescription
asset_idpathstringtrue
Try it
Query

Examples

cURL
curl -X PATCH 'https://spideriq.ai/api/v1/dashboard/media/catalog/assets/{asset_id}' \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{
  "folder": "string",
  "tags": [
    "string"
  ],
  "status": "string",
  "metadata": {},
  "alt_text": "string"
}'
Python
import httpx

resp = httpx.patch(
    "https://spideriq.ai/api/v1/dashboard/media/catalog/assets/{asset_id}",
    headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
    json={"folder": "string", "tags": ["string"], "status": "string", "metadata": {}, "alt_text": "string"},
)
resp.raise_for_status()
print(resp.json())
JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/media/catalog/assets/{asset_id}", {
  method: "PATCH",
  headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
  body: JSON.stringify({"folder": "string", "tags": ["string"], "status": "string", "metadata": {}, "alt_text": "string"})
});
const data = await resp.json();
console.log(data);
Go
package main

import (
	"net/http"
	"strings"
)

func main() {
	body := strings.NewReader(`{"folder": "string", "tags": ["string"], "status": "string", "metadata": {}, "alt_text": "string"}`)
	req, _ := http.NewRequest("PATCH", "https://spideriq.ai/api/v1/dashboard/media/catalog/assets/{asset_id}", body)
	req.Header.Set("Authorization", "Bearer <token>")
	req.Header.Set("Content-Type", "application/json")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}

Responses

StatusDescription
200Successful Response
422Validation Error
DELETE/api/v1/dashboard/media/catalog/assets/{asset_id}

Delete Catalog Asset

Soft-delete a media asset (deleted_at = now()). 204 on success, 404 if no live asset with that id exists.

For an R2 image (storage_tier='r2') the delete is COMPLETE, not just observational: an R2 image is dual-written (R2 object + legacy content_media row + this catalog row, all sharing one r2_key), so deleting only the catalog row would orphan the other two — leaving the image visible in the legacy page-image picker and the object billing in R2. We mirror the create and clear the matching content_media row + R2 object (best-effort — a cleanup miss never fails the delete; the catalog row is already hidden). SeaweedFS/PeerTube tiers keep the observational-only behaviour (their bytes live on LLM11, which app/ never mutates — Rule 3).

Parameters

NameInTypeRequiredDescription
asset_idpathstringtrue
Try it
Query

Examples

cURL
curl -X DELETE 'https://spideriq.ai/api/v1/dashboard/media/catalog/assets/{asset_id}' \
  -H 'Authorization: Bearer <token>'
Python
import httpx

resp = httpx.delete(
    "https://spideriq.ai/api/v1/dashboard/media/catalog/assets/{asset_id}",
    headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())
JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/media/catalog/assets/{asset_id}", {
  method: "DELETE",
  headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);
Go
package main

import (
	"net/http"
)

func main() {
	req, _ := http.NewRequest("DELETE", "https://spideriq.ai/api/v1/dashboard/media/catalog/assets/{asset_id}", nil)
	req.Header.Set("Authorization", "Bearer <token>")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}

Responses

StatusDescription
204Successful Response
422Validation Error
GET/api/v1/dashboard/media/catalog/assets/{asset_id}/derivative

Get Asset Derivative

Resolve (or lazily create + cache) an image derivative for this asset.

On the first request for a given spec the image is derived with Pillow and stored in R2 under a deterministic derivatives/{tenant}/{hash}.{ext} key; subsequent identical requests return the cached URL with cache_hit=true and no work. 422 for a non-image asset or one not on the r2 tier (unsupported_source); 404 if the asset doesn't exist for the tenant. Derivatives are an evictable cache regenerable from the original (Rule 7).

Parameters

NameInTypeRequiredDescription
asset_idpathstringtrue
wqueryanyfalseTarget width in px (1-4096)
hqueryanyfalseTarget height in px (1-4096)
fitquerystringfalsecover | contain | fill | crop16x9 | crop1x1 | crop4x3
fmtquerystringfalsewebp | avif | jpeg | png | auto
qqueryintegerfalseEncode quality 1-100 (png ignores it)
Try it
Query

Examples

cURL
curl -X GET 'https://spideriq.ai/api/v1/dashboard/media/catalog/assets/{asset_id}/derivative' \
  -H 'Authorization: Bearer <token>'
Python
import httpx

resp = httpx.get(
    "https://spideriq.ai/api/v1/dashboard/media/catalog/assets/{asset_id}/derivative",
    headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())
JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/media/catalog/assets/{asset_id}/derivative", {
  method: "GET",
  headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);
Go
package main

import (
	"net/http"
)

func main() {
	req, _ := http.NewRequest("GET", "https://spideriq.ai/api/v1/dashboard/media/catalog/assets/{asset_id}/derivative", nil)
	req.Header.Set("Authorization", "Bearer <token>")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}

Responses

StatusDescription
200Successful Response
422Validation Error