SSpiderIQ
SSpiderIQ

Docs / api-reference/media-upload

Media Upload

5 endpoints from the published OpenAPI import.

POST/api/v1/dashboard/media/upload

Upload Media Image

Upload a single image to Cloudflare R2 (storage_tier='r2').

Validates → transcodes to WebP (5 MB cap) → R2 → content_media row → catalogs into media_assets. 201 + {success, media, asset} where media is the legacy record and asset is the catalog row (null only if the non-blocking catalog write missed — the upload still succeeded).

Try it

Examples

cURL
curl -X POST 'https://spideriq.ai/api/v1/dashboard/media/upload' \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{
  "file": "string",
  "folder": "/",
  "alt_text": "string"
}'
Python
import httpx

resp = httpx.post(
    "https://spideriq.ai/api/v1/dashboard/media/upload",
    headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
    json={"file": "string", "folder": "/", "alt_text": "string"},
)
resp.raise_for_status()
print(resp.json())
JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/media/upload", {
  method: "POST",
  headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
  body: JSON.stringify({"file": "string", "folder": "/", "alt_text": "string"})
});
const data = await resp.json();
console.log(data);
Go
package main

import (
	"net/http"
	"strings"
)

func main() {
	body := strings.NewReader(`{"file": "string", "folder": "/", "alt_text": "string"}`)
	req, _ := http.NewRequest("POST", "https://spideriq.ai/api/v1/dashboard/media/upload", 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
201Successful Response
422Validation Error
POST/api/v1/dashboard/media/upload-from-url

Upload Media Image From Url

Host a remote image URL on Cloudflare R2 (storage_tier='r2') — the agent-callable, JSON-only twin of POST /upload.

Agents reaching the content platform via skill_call can't send multipart, and a generated hero image lives at a provider URL (kie.* etc.) that the cover_image_url allowlist rejects. This fetches the URL SSRF-safely and runs the same validate → WebP-transcode → R2 → content_media → catalog pipeline as /upload; the returned media.r2_url is on our allowlisted host, so it then passes straight into createPost / content_update_page.

201 + {success, media, asset} (same shape as /upload). A bad/unreachable URL or non-image body is a 400; an oversized body (>5 MB) is a 413.

Try it

Examples

cURL
curl -X POST 'https://spideriq.ai/api/v1/dashboard/media/upload-from-url' \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{
  "media_url": "string",
  "folder": "/",
  "alt_text": "string"
}'
Python
import httpx

resp = httpx.post(
    "https://spideriq.ai/api/v1/dashboard/media/upload-from-url",
    headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
    json={"media_url": "string", "folder": "/", "alt_text": "string"},
)
resp.raise_for_status()
print(resp.json())
JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/media/upload-from-url", {
  method: "POST",
  headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
  body: JSON.stringify({"media_url": "string", "folder": "/", "alt_text": "string"})
});
const data = await resp.json();
console.log(data);
Go
package main

import (
	"net/http"
	"strings"
)

func main() {
	body := strings.NewReader(`{"media_url": "string", "folder": "/", "alt_text": "string"}`)
	req, _ := http.NewRequest("POST", "https://spideriq.ai/api/v1/dashboard/media/upload-from-url", 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
201Successful Response
422Validation Error
POST/api/v1/dashboard/media/upload-file

Register Media File

Register a NON-IMAGE file on R2 (storage_tier='r2') — press 3.1.

The third media door, and the only one that does not transcode. /upload and the legacy content/media uploader both hard-gate on validate_image() and rewrite everything to WebP, so a media kit's ZIP bundle, SVG/EPS logo variants and PDF brand guide had no way to obtain a content_media row — and therefore no media_id that POST /press/kits/{id}/assets accepts.

The bytes decide the type: the filename extension and the multipart Content-Type are both ignored (audit §12). Raster images are refused here with a 400 pointing at /upload, so nothing skips image validation. Archives are stored and served verbatim — never expanded or inspected server-side.

201 + {success, media, asset}, the same shape as /upload. 400 for an unsupported or image type, 413 over the cap (100 MB for ZIP, 20 MB otherwise).

Try it

Examples

cURL
curl -X POST 'https://spideriq.ai/api/v1/dashboard/media/upload-file' \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{
  "file": "string",
  "folder": "press-kits",
  "alt_text": "string"
}'
Python
import httpx

resp = httpx.post(
    "https://spideriq.ai/api/v1/dashboard/media/upload-file",
    headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
    json={"file": "string", "folder": "press-kits", "alt_text": "string"},
)
resp.raise_for_status()
print(resp.json())
JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/media/upload-file", {
  method: "POST",
  headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
  body: JSON.stringify({"file": "string", "folder": "press-kits", "alt_text": "string"})
});
const data = await resp.json();
console.log(data);
Go
package main

import (
	"net/http"
	"strings"
)

func main() {
	body := strings.NewReader(`{"file": "string", "folder": "press-kits", "alt_text": "string"}`)
	req, _ := http.NewRequest("POST", "https://spideriq.ai/api/v1/dashboard/media/upload-file", 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
201Successful Response
422Validation Error
POST/api/v1/dashboard/media/upload-batch

Upload Media Batch

Upload one or many files to SeaweedFS (storage_tier='seaweedfs').

Per-file (20 MB / 500 MB video) + batch (500 MB) weight caps and an extension allowlist run BEFORE any upload — a hard violation is a 413 and nothing uploads. Each file catalogs on success. 201 + {success, uploaded, failed, totals} (success is true only when nothing failed).

Try it

Examples

cURL
curl -X POST 'https://spideriq.ai/api/v1/dashboard/media/upload-batch' \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{
  "files": [
    "string"
  ],
  "folder": "string",
  "preserve_filename": false
}'
Python
import httpx

resp = httpx.post(
    "https://spideriq.ai/api/v1/dashboard/media/upload-batch",
    headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
    json={"files": ["string"], "folder": "string", "preserve_filename": false},
)
resp.raise_for_status()
print(resp.json())
JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/media/upload-batch", {
  method: "POST",
  headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
  body: JSON.stringify({"files": ["string"], "folder": "string", "preserve_filename": false})
});
const data = await resp.json();
console.log(data);
Go
package main

import (
	"net/http"
	"strings"
)

func main() {
	body := strings.NewReader(`{"files": ["string"], "folder": "string", "preserve_filename": false}`)
	req, _ := http.NewRequest("POST", "https://spideriq.ai/api/v1/dashboard/media/upload-batch", 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
201Successful Response
422Validation Error
POST/api/v1/dashboard/media/import-video

Import Media Video

Import a remote video into the tenant's PeerTube channel (storage_tier='peertube').

LONG-RUNNING (encode takes minutes) — this does NOT block-wait the encode. The import is accepted (uuid minted, status processing, catalog row written) and returns 202 immediately; the client polls the existing status path (GET /api/v1/media/videos/{uuid}/status) for completion.

202 + {success, peertube_uuid, video_id, status, watch_url, embed_url, player_url, message}. 502 if the upstream import service rejects the kick-off.

Try it

Examples

cURL
curl -X POST 'https://spideriq.ai/api/v1/dashboard/media/import-video' \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{
  "url": "string",
  "title": "string",
  "description": "string",
  "privacy": 2,
  "use_proxy": false
}'
Python
import httpx

resp = httpx.post(
    "https://spideriq.ai/api/v1/dashboard/media/import-video",
    headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
    json={"url": "string", "title": "string", "description": "string", "privacy": 2, "use_proxy": false},
)
resp.raise_for_status()
print(resp.json())
JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/media/import-video", {
  method: "POST",
  headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
  body: JSON.stringify({"url": "string", "title": "string", "description": "string", "privacy": 2, "use_proxy": false})
});
const data = await resp.json();
console.log(data);
Go
package main

import (
	"net/http"
	"strings"
)

func main() {
	body := strings.NewReader(`{"url": "string", "title": "string", "description": "string", "privacy": 2, "use_proxy": false}`)
	req, _ := http.NewRequest("POST", "https://spideriq.ai/api/v1/dashboard/media/import-video", 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
202Successful Response
422Validation Error