Dashboard Gate
20 endpoints from the published OpenAPI import.
Get Brand Gate Stats
Brand's Gate stats: agent count, requests this month, spend.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
brand_id | path | integer | true |
Try it
Examples
cURL
curl -X GET 'https://spideriq.ai/api/v1/brands/{brand_id}/gate/stats' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.get(
"https://spideriq.ai/api/v1/brands/{brand_id}/gate/stats",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/brands/{brand_id}/gate/stats", {
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/brands/{brand_id}/gate/stats", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
List Brand Agents
List agent tokens belonging to this brand.
Status comes from agent_token_status (the canonical view — revoked > expired > !is_active > active) so this dashboard agrees with Settings → Members → Agents on what's alive. Reading raw agent_tokens.is_active was the root of the "10 Active / 0 active" divergence in gate-keys-coherence-plan.md §1.
created_by is JOINed against Better Auth "user" (user.id is TEXT; SpiderGate LEARNINGS #18). NULL created_by_user_id surfaces as {"name": "System"} — legacy or agent-self-registered tokens have no dashboard operator on the hook.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
brand_id | path | integer | true | |
include_inactive | query | boolean | false |
Try it
Examples
cURL
curl -X GET 'https://spideriq.ai/api/v1/brands/{brand_id}/gate/agents' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.get(
"https://spideriq.ai/api/v1/brands/{brand_id}/gate/agents",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/brands/{brand_id}/gate/agents", {
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/brands/{brand_id}/gate/agents", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
Update Brand Agent
Update agent's budget/models/rate limits. Brand admin required.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
brand_id | path | integer | true | |
token_id | path | string | true |
Try it
Examples
cURL
curl -X PATCH 'https://spideriq.ai/api/v1/brands/{brand_id}/gate/agents/{token_id}' \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
-d '{}'Python
import httpx
resp = httpx.patch(
"https://spideriq.ai/api/v1/brands/{brand_id}/gate/agents/{token_id}",
headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
json={},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/brands/{brand_id}/gate/agents/{token_id}", {
method: "PATCH",
headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
body: JSON.stringify({})
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{}`)
req, _ := http.NewRequest("PATCH", "https://spideriq.ai/api/v1/brands/{brand_id}/gate/agents/{token_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
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
Get Brand Agent Detail
Detailed view of a single agent token: config + usage + recent activity.
Powers the per-key detail page modeled after OpenRouter's API key page — config card, usage cards (today/week/month/total), per-model spend breakdown, and recent activity rows.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
brand_id | path | integer | true | |
token_id | path | string | true |
Try it
Examples
cURL
curl -X GET 'https://spideriq.ai/api/v1/brands/{brand_id}/gate/agents/{token_id}/detail' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.get(
"https://spideriq.ai/api/v1/brands/{brand_id}/gate/agents/{token_id}/detail",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/brands/{brand_id}/gate/agents/{token_id}/detail", {
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/brands/{brand_id}/gate/agents/{token_id}/detail", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
Get Brand Usage
Brand's SpiderGate usage: turns vs attempts, outcome split, cost avoided.
Read-only aggregate over gate_request_logs. Emits no billable event and adds no metered surface, so it is deliberately NOT wired to dispatcher_submission(); the parent spiderGateLlm service is already metered where the spend actually happens.
⚠️ Scoped WHERE brand_id = :brand_id — this is "my spend", NOT capacity. A pooled key serves the whole pool, so a brand-filtered per-key rollup under-counts by 72% (SpiderGate LEARNINGS P2.1). Never reuse these numbers as a quota or headroom input.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
brand_id | path | integer | true | |
from | query | any | false | Window start (inclusive), ISO-8601. Naive values are read as UTC. Pair with to for a real calendar range — e.g. from=2026-08-01T00:00:00Z&to=2026-09-01T00:00:00Z is THIS MONTH, which is not the same window as a rolling 30 days. |
to | query | any | false | Window end (exclusive), ISO-8601. Defaults to now. |
days | query | any | false | DEPRECATED — rolling lookback in days, kept for one release for the shipped dashboard and the gate_usage MCP tool. Use from/to: a lookback cannot express a calendar month. Ignored when from/to are supplied. |
bucket | query | string | false | Grain of the time series in by_bucket. |
compare | query | boolean | false | Also compute the immediately preceding window of identical length and return it under comparison. Doubles the query cost. |
Try it
Examples
cURL
curl -X GET 'https://spideriq.ai/api/v1/brands/{brand_id}/gate/usage' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.get(
"https://spideriq.ai/api/v1/brands/{brand_id}/gate/usage",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/brands/{brand_id}/gate/usage", {
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/brands/{brand_id}/gate/usage", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
Get Gate Providers
List available LLM providers with logos and descriptions. Read-only for clients — no edit capabilities.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
brand_id | path | integer | true |
Try it
Examples
cURL
curl -X GET 'https://spideriq.ai/api/v1/brands/{brand_id}/gate/providers' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.get(
"https://spideriq.ai/api/v1/brands/{brand_id}/gate/providers",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/brands/{brand_id}/gate/providers", {
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/brands/{brand_id}/gate/providers", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
Playground Completions
Proxy chat completions for the Playground UI (dashboard session auth).
Records every refusal, then re-raises it unchanged (STUDIO.1, SQAR2-105), mirroring the public route's wrapper (LOG.1, SQAR2-101).
🔴 Why a wrapper and not a recorder per raise. LOG.1 established that the count of refusal sites is not stable — a recorder bolted onto each site is correct the day it ships and silently incomplete at the next raise. Every exit of this route passes through here by construction.
The three load-bearing properties are LOG.1's, unchanged:
- It changes no decision.
raisere-raises the identical exception. - It cannot fail the request. A recorder that turns a clean 4xx into an opaque 500 is strictly worse than no recorder — hence the inner
try/exceptaround the recording itself, not a trusted promise made in another module. - It does not depend on the engine — one refusal is "engine unavailable".
⚠️ What it does NOT cover, said out loud — three classes:
- A refusal raised by a DEPENDENCY. FastAPI resolves dependencies before calling this function, so
require_tenant_member_or_agent's400 "Please select a client or brand first"never enters thistry. That 400 is exactly what made the owner's 2026-09-02 Fork undiagnosable — it is fixed at source inapi-client.postStream(the Studio now sends the tenant headers), not recorded here. Recording it would mean an app-level handler over a dependency shared by ~20 non-gate routes, which is a different layer. Same boundary LOG.1 drew. - A streaming response that fails mid-body, after the
StreamingResponsehas been returned. The fork/merge lanes are covered separately insideservices.gate.fusion— see_record_lane_refusal. - A fork lane that fails while the whole request succeeds — a 200 with three dead lanes raises nothing here. Also
fusion's job.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
brand_id | path | integer | true |
Try it
Examples
cURL
curl -X POST 'https://spideriq.ai/api/v1/brands/{brand_id}/gate/playground/completions' \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
-d '{}'Python
import httpx
resp = httpx.post(
"https://spideriq.ai/api/v1/brands/{brand_id}/gate/playground/completions",
headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
json={},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/brands/{brand_id}/gate/playground/completions", {
method: "POST",
headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
body: JSON.stringify({})
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{}`)
req, _ := http.NewRequest("POST", "https://spideriq.ai/api/v1/brands/{brand_id}/gate/playground/completions", body)
req.Header.Set("Authorization", "Bearer <token>")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
Playground Media Models
List media-generation models for the ⌘J picker (rich per-model/provider metadata). modality filters to one fine tab; modality_group filters to one coarse tab (image|video|audio); tags requires ALL given facet chips; include_inactive also returns coming_soon/disabled rows (greyed out).
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
brand_id | path | integer | true | |
modality | query | any | false | |
modality_group | query | any | false | |
tags | query | any | false | |
include_inactive | query | boolean | false |
Try it
Examples
cURL
curl -X GET 'https://spideriq.ai/api/v1/brands/{brand_id}/gate/playground/media/models' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.get(
"https://spideriq.ai/api/v1/brands/{brand_id}/gate/playground/media/models",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/brands/{brand_id}/gate/playground/media/models", {
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/brands/{brand_id}/gate/playground/media/models", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
Playground Media Generations
Generate media (image/video/audio) for the Studio and return its stored URL.
Session-authed + brand-scoped; the vault key is resolved server-side and never reaches the browser. body = {model: '<provider>/<model>', prompt, …params}.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
brand_id | path | integer | true |
Try it
Examples
cURL
curl -X POST 'https://spideriq.ai/api/v1/brands/{brand_id}/gate/playground/media/generations' \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
-d '{}'Python
import httpx
resp = httpx.post(
"https://spideriq.ai/api/v1/brands/{brand_id}/gate/playground/media/generations",
headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
json={},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/brands/{brand_id}/gate/playground/media/generations", {
method: "POST",
headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
body: JSON.stringify({})
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{}`)
req, _ := http.NewRequest("POST", "https://spideriq.ai/api/v1/brands/{brand_id}/gate/playground/media/generations", body)
req.Header.Set("Authorization", "Bearer <token>")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
Brand Catalog Models
Enriched LLM/chat catalog for the model browser (Chat/fusion modalities). Session-authed proxy → catalog.get_enriched_catalog (identical shape to the brand-PAT GET /api/gate/v1/catalog/models). Read-only, not metered.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
brand_id | path | integer | true | |
provider | query | any | false | |
search | query | any | false | |
tag | query | any | false | |
fields | query | any | false | |
free_only | query | boolean | false | |
servable_only | query | boolean | false | |
limit | query | integer | false | |
offset | query | integer | false |
Try it
Examples
cURL
curl -X GET 'https://spideriq.ai/api/v1/brands/{brand_id}/gate/catalog/models' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.get(
"https://spideriq.ai/api/v1/brands/{brand_id}/gate/catalog/models",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/brands/{brand_id}/gate/catalog/models", {
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/brands/{brand_id}/gate/catalog/models", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
Brand Catalog Model
Full enriched record for one model — the browser's detail pane (lazy). Session-authed proxy → catalog.get_model_record. 404 when unknown.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
brand_id | path | integer | true | |
model_id | path | string | true |
Try it
Examples
cURL
curl -X GET 'https://spideriq.ai/api/v1/brands/{brand_id}/gate/catalog/models/{model_id}' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.get(
"https://spideriq.ai/api/v1/brands/{brand_id}/gate/catalog/models/{model_id}",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/brands/{brand_id}/gate/catalog/models/{model_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/brands/{brand_id}/gate/catalog/models/{model_id}", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
Brand Catalog Categories
Category taxonomy for the DB-driven chips + score bars (CT.4). Session- authed proxy → catalog.get_categories. Read-only, not metered.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
brand_id | path | integer | true | |
include_inactive | query | boolean | false |
Try it
Examples
cURL
curl -X GET 'https://spideriq.ai/api/v1/brands/{brand_id}/gate/catalog/categories' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.get(
"https://spideriq.ai/api/v1/brands/{brand_id}/gate/catalog/categories",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/brands/{brand_id}/gate/catalog/categories", {
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/brands/{brand_id}/gate/catalog/categories", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
Brand Catalog Leaderboard
Model leaderboard (global, per-task, or per-category via category=). Session-authed proxy → catalog.get_leaderboard. Category mode ranks by the materialised within-category percentile (§13-C). Read-only, not metered.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
brand_id | path | integer | true | |
task_type | query | any | false | |
category | query | any | false | |
sort | query | string | false | |
limit | query | integer | false |
Try it
Examples
cURL
curl -X GET 'https://spideriq.ai/api/v1/brands/{brand_id}/gate/catalog/leaderboard' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.get(
"https://spideriq.ai/api/v1/brands/{brand_id}/gate/catalog/leaderboard",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/brands/{brand_id}/gate/catalog/leaderboard", {
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/brands/{brand_id}/gate/catalog/leaderboard", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
List Model Favorites
This user's ★ favorite models (newest-first). modality optionally scopes to one tab. Read-only, fails open to an empty list.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
brand_id | path | integer | true | |
modality | query | any | false |
Try it
Examples
cURL
curl -X GET 'https://spideriq.ai/api/v1/brands/{brand_id}/gate/favorites' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.get(
"https://spideriq.ai/api/v1/brands/{brand_id}/gate/favorites",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/brands/{brand_id}/gate/favorites", {
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/brands/{brand_id}/gate/favorites", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
Add Model Favorite
Star a model for this user (idempotent). Returns the stored favorite.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
brand_id | path | integer | true |
Try it
Examples
cURL
curl -X POST 'https://spideriq.ai/api/v1/brands/{brand_id}/gate/favorites' \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
-d '{
"spidergate_id": "string",
"modality": "chat"
}'Python
import httpx
resp = httpx.post(
"https://spideriq.ai/api/v1/brands/{brand_id}/gate/favorites",
headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
json={"spidergate_id": "string", "modality": "chat"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/brands/{brand_id}/gate/favorites", {
method: "POST",
headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
body: JSON.stringify({"spidergate_id": "string", "modality": "chat"})
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{"spidergate_id": "string", "modality": "chat"}`)
req, _ := http.NewRequest("POST", "https://spideriq.ai/api/v1/brands/{brand_id}/gate/favorites", body)
req.Header.Set("Authorization", "Bearer <token>")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
201 | Successful Response |
422 | Validation Error |
Remove Model Favorite
Un-star a model for this user (idempotent — 204 whether or not it existed).
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
brand_id | path | integer | true | |
spidergate_id | path | string | true |
Try it
Examples
cURL
curl -X DELETE 'https://spideriq.ai/api/v1/brands/{brand_id}/gate/favorites/{spidergate_id}' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.delete(
"https://spideriq.ai/api/v1/brands/{brand_id}/gate/favorites/{spidergate_id}",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/brands/{brand_id}/gate/favorites/{spidergate_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/brands/{brand_id}/gate/favorites/{spidergate_id}", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
204 | Successful Response |
422 | Validation Error |
Get Brand Gate Capacity
Key pressure + subscription windows for the usage page's right rail.
Two blocks with different scopes, labelled as such in the payload:
key_pressure traffic_scope="pool_wide". Counted with NO brand_id predicate, because a provider counts every request on a key regardless of which tenant caused it and a share_with_pool key serves the whole pool. Never render this as "your usage".
subscription_windows scope="brand_keys". This brand's own keys. Each row is state="measured" with a window_percent float where the tier's request cap and the request counter can be honestly divided, and state="unmeasurable" with window_percent=None where they cannot (GUR-11 gave the division matching units; GUR-16 turned it on).
gauge_available is DERIVED from those rows and is a different question from "here is a number": it says a gauge is drawable somewhere on this panel. It was a hardcoded False until GUR-16, citing a blocker that had already closed.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
brand_id | path | integer | true | |
days | query | integer | false | Lookback window in days |
key_limit | query | integer | false | Max subscription-window rows |
Try it
Examples
cURL
curl -X GET 'https://spideriq.ai/api/v1/brands/{brand_id}/gate/capacity' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.get(
"https://spideriq.ai/api/v1/brands/{brand_id}/gate/capacity",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/brands/{brand_id}/gate/capacity", {
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/brands/{brand_id}/gate/capacity", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
Get Brand Gate Flow
requested alias -> served model -> provider cross-tab for the Sankey.
Brand-scoped: these are this tenant's own requests.
The provider is resolved through integration_id -> api_integrations. It is not gate_request_logs.provider, which carries the litellm wire prefix and stamps MiniMax as openai.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
brand_id | path | integer | true | |
days | query | integer | false | Lookback window in days |
limit | query | integer | false | Max cross-tab rows |
Try it
Examples
cURL
curl -X GET 'https://spideriq.ai/api/v1/brands/{brand_id}/gate/flow' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.get(
"https://spideriq.ai/api/v1/brands/{brand_id}/gate/flow",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/brands/{brand_id}/gate/flow", {
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/brands/{brand_id}/gate/flow", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
Create an agent key directly (dashboard-driven mint)
Mint a new agent token under the given brand.
S2 unification: the identity half now goes through the SAME resolver the email-approval path uses (services.agent_identity.resolve_or_create_agent_user) — so a dashboard mint and a CLI enrollment for the same operator resolve to the SAME agent account, keyed on the opaque agent_ref, and BOTH mint a real OPVS address (block-until-minted). The PAT minted here is therefore the self-identifying form spideriq_pat_<agent_ref>_<secret>, not the legacy shape it used to emit.
The full secret is returned exactly once in the response body. Subsequent reads of the token (list / detail endpoints) only ever see token_prefix.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
brand_id | path | integer | true |
Try it
Examples
cURL
curl -X POST 'https://spideriq.ai/api/v1/brands/{brand_id}/gate/agent-keys' \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
-d '{
"name": "string",
"description": "string",
"photo": "string",
"scopes": [
"string"
],
"allowed_models": [
"string"
],
"free_models_only": false,
"ttl_hours": 720,
"monthly_budget_usd": 0.0,
"soft_budget_usd": 0.0,
"rate_limit_rpm": 0,
"rate_limit_rpd": 0,
"owner_email": "string"
}'Python
import httpx
resp = httpx.post(
"https://spideriq.ai/api/v1/brands/{brand_id}/gate/agent-keys",
headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
json={"name": "string", "description": "string", "photo": "string", "scopes": ["string"], "allowed_models": ["string"], "free_models_only": false, "ttl_hours": 720, "monthly_budget_usd": 0.0, "soft_budget_usd": 0.0, "rate_limit_rpm": 0, "rate_limit_rpd": 0, "owner_email": "string"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/brands/{brand_id}/gate/agent-keys", {
method: "POST",
headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
body: JSON.stringify({"name": "string", "description": "string", "photo": "string", "scopes": ["string"], "allowed_models": ["string"], "free_models_only": false, "ttl_hours": 720, "monthly_budget_usd": 0.0, "soft_budget_usd": 0.0, "rate_limit_rpm": 0, "rate_limit_rpd": 0, "owner_email": "string"})
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{"name": "string", "description": "string", "photo": "string", "scopes": ["string"], "allowed_models": ["string"], "free_models_only": false, "ttl_hours": 720, "monthly_budget_usd": 0.0, "soft_budget_usd": 0.0, "rate_limit_rpm": 0, "rate_limit_rpd": 0, "owner_email": "string"}`)
req, _ := http.NewRequest("POST", "https://spideriq.ai/api/v1/brands/{brand_id}/gate/agent-keys", body)
req.Header.Set("Authorization", "Bearer <token>")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
201 | Successful Response |
422 | Validation Error |
Upload an avatar image for an agent key (≤2 MB)
Upload an avatar image to R2 under agent-avatars/.
MED-01: enforce ~2 MB body cap before reading the full payload. We also validate Content-Type + extension to make sure the operator hasn't pointed a profile picture URL at /etc/shadow or similar.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
brand_id | path | integer | true |
Try it
Examples
cURL
curl -X POST 'https://spideriq.ai/api/v1/brands/{brand_id}/gate/agent-keys/avatar' \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
-d '{
"file": "string"
}'Python
import httpx
resp = httpx.post(
"https://spideriq.ai/api/v1/brands/{brand_id}/gate/agent-keys/avatar",
headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
json={"file": "string"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/brands/{brand_id}/gate/agent-keys/avatar", {
method: "POST",
headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
body: JSON.stringify({"file": "string"})
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{"file": "string"}`)
req, _ := http.NewRequest("POST", "https://spideriq.ai/api/v1/brands/{brand_id}/gate/agent-keys/avatar", body)
req.Header.Set("Authorization", "Bearer <token>")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
413 | Upload exceeds 2 MB limit |
415 | Unsupported image type |
422 | Validation Error |