SSpiderIQ
SSpiderIQ

Docs / api-reference/dashboard-gate

Dashboard Gate

20 endpoints from the published OpenAPI import.

GET/api/v1/brands/{brand_id}/gate/stats

Get Brand Gate Stats

Brand's Gate stats: agent count, requests this month, spend.

Parameters

NameInTypeRequiredDescription
brand_idpathintegertrue
Try it
Query

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

StatusDescription
200Successful Response
422Validation Error
GET/api/v1/brands/{brand_id}/gate/agents

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

NameInTypeRequiredDescription
brand_idpathintegertrue
include_inactivequerybooleanfalse
Try it
Query

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

StatusDescription
200Successful Response
422Validation Error
PATCH/api/v1/brands/{brand_id}/gate/agents/{token_id}

Update Brand Agent

Update agent's budget/models/rate limits. Brand admin required.

Parameters

NameInTypeRequiredDescription
brand_idpathintegertrue
token_idpathstringtrue
Try it
Query

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

StatusDescription
200Successful Response
422Validation Error
GET/api/v1/brands/{brand_id}/gate/agents/{token_id}/detail

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

NameInTypeRequiredDescription
brand_idpathintegertrue
token_idpathstringtrue
Try it
Query

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

StatusDescription
200Successful Response
422Validation Error
GET/api/v1/brands/{brand_id}/gate/usage

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

NameInTypeRequiredDescription
brand_idpathintegertrue
fromqueryanyfalseWindow 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.
toqueryanyfalseWindow end (exclusive), ISO-8601. Defaults to now.
daysqueryanyfalseDEPRECATED — 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.
bucketquerystringfalseGrain of the time series in by_bucket.
comparequerybooleanfalseAlso compute the immediately preceding window of identical length and return it under comparison. Doubles the query cost.
Try it
Query

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

StatusDescription
200Successful Response
422Validation Error
GET/api/v1/brands/{brand_id}/gate/providers

Get Gate Providers

List available LLM providers with logos and descriptions. Read-only for clients — no edit capabilities.

Parameters

NameInTypeRequiredDescription
brand_idpathintegertrue
Try it
Query

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

StatusDescription
200Successful Response
422Validation Error
POST/api/v1/brands/{brand_id}/gate/playground/completions

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. raise re-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/except around 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:

  1. A refusal raised by a DEPENDENCY. FastAPI resolves dependencies before calling this function, so require_tenant_member_or_agent's 400 "Please select a client or brand first" never enters this try. That 400 is exactly what made the owner's 2026-09-02 Fork undiagnosable — it is fixed at source in api-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.
  2. A streaming response that fails mid-body, after the StreamingResponse has been returned. The fork/merge lanes are covered separately inside services.gate.fusion — see _record_lane_refusal.
  3. A fork lane that fails while the whole request succeeds — a 200 with three dead lanes raises nothing here. Also fusion's job.

Parameters

NameInTypeRequiredDescription
brand_idpathintegertrue
Try it
Query

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

StatusDescription
200Successful Response
422Validation Error
GET/api/v1/brands/{brand_id}/gate/playground/media/models

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

NameInTypeRequiredDescription
brand_idpathintegertrue
modalityqueryanyfalse
modality_groupqueryanyfalse
tagsqueryanyfalse
include_inactivequerybooleanfalse
Try it
Query

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

StatusDescription
200Successful Response
422Validation Error
POST/api/v1/brands/{brand_id}/gate/playground/media/generations

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

NameInTypeRequiredDescription
brand_idpathintegertrue
Try it
Query

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

StatusDescription
200Successful Response
422Validation Error
GET/api/v1/brands/{brand_id}/gate/catalog/models

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

NameInTypeRequiredDescription
brand_idpathintegertrue
providerqueryanyfalse
searchqueryanyfalse
tagqueryanyfalse
fieldsqueryanyfalse
free_onlyquerybooleanfalse
servable_onlyquerybooleanfalse
limitqueryintegerfalse
offsetqueryintegerfalse
Try it
Query

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

StatusDescription
200Successful Response
422Validation Error
GET/api/v1/brands/{brand_id}/gate/catalog/models/{model_id}

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

NameInTypeRequiredDescription
brand_idpathintegertrue
model_idpathstringtrue
Try it
Query

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

StatusDescription
200Successful Response
422Validation Error
GET/api/v1/brands/{brand_id}/gate/catalog/categories

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

NameInTypeRequiredDescription
brand_idpathintegertrue
include_inactivequerybooleanfalse
Try it
Query

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

StatusDescription
200Successful Response
422Validation Error
GET/api/v1/brands/{brand_id}/gate/catalog/leaderboard

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

NameInTypeRequiredDescription
brand_idpathintegertrue
task_typequeryanyfalse
categoryqueryanyfalse
sortquerystringfalse
limitqueryintegerfalse
Try it
Query

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

StatusDescription
200Successful Response
422Validation Error
GET/api/v1/brands/{brand_id}/gate/favorites

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

NameInTypeRequiredDescription
brand_idpathintegertrue
modalityqueryanyfalse
Try it
Query

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

StatusDescription
200Successful Response
422Validation Error
POST/api/v1/brands/{brand_id}/gate/favorites

Add Model Favorite

Star a model for this user (idempotent). Returns the stored favorite.

Parameters

NameInTypeRequiredDescription
brand_idpathintegertrue
Try it
Query

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

StatusDescription
201Successful Response
422Validation Error
DELETE/api/v1/brands/{brand_id}/gate/favorites/{spidergate_id}

Remove Model Favorite

Un-star a model for this user (idempotent — 204 whether or not it existed).

Parameters

NameInTypeRequiredDescription
brand_idpathintegertrue
spidergate_idpathstringtrue
Try it
Query

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

StatusDescription
204Successful Response
422Validation Error
GET/api/v1/brands/{brand_id}/gate/capacity

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

NameInTypeRequiredDescription
brand_idpathintegertrue
daysqueryintegerfalseLookback window in days
key_limitqueryintegerfalseMax subscription-window rows
Try it
Query

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

StatusDescription
200Successful Response
422Validation Error
GET/api/v1/brands/{brand_id}/gate/flow

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

NameInTypeRequiredDescription
brand_idpathintegertrue
daysqueryintegerfalseLookback window in days
limitqueryintegerfalseMax cross-tab rows
Try it
Query

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

StatusDescription
200Successful Response
422Validation Error
POST/api/v1/brands/{brand_id}/gate/agent-keys

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

NameInTypeRequiredDescription
brand_idpathintegertrue
Try it
Query

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

StatusDescription
201Successful Response
422Validation Error
POST/api/v1/brands/{brand_id}/gate/agent-keys/avatar

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

NameInTypeRequiredDescription
brand_idpathintegertrue
Try it
Query

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

StatusDescription
200Successful Response
413Upload exceeds 2 MB limit
415Unsupported image type
422Validation Error