Public read API
Programmatic access to the same data the dashboard reads. Available on the Agency plan. JSON over HTTPS, Bearer-token auth, 60 requests/min.
Authentication
Pass your API key in the Authorization header. Generate keys from the API Keys settings page. Keys look like sk_live_….
curl https://stagecraft.gg/api/v1/listings?limit=5 \ -H "Authorization: Bearer sk_live_xxxxxxxxxxxx"
Rate limiting
Each request returns standard headers so you can pace yourself:X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset. When you exceed your quota you get a 429 with a Retry-After header.
Endpoints
Returns your org context, plan, and rate-limit info. Useful for verifying your key works.
Search and filter listings. Mirrors the in-app /search filters.
| Param | Type | Notes |
|---|---|---|
| q | string | Full-text search |
| frameworks | csv | qbcore,qbox,esx,standalone,redm |
| category | string | Exact category match |
| source | string | cfx_marketplace | tebex |
| min_price / max_price | number | Price band (USD) |
| is_free | bool | true|false |
| min_rating | number | 0-5 |
| has_video | bool | true|false |
| sort | string | rating | newest | oldest | price_asc | price_desc | quality |
| limit | number | 1-200, default 50 |
| offset | number | default 0 |
Full listing detail with quality breakdown, daily snapshots (default 90 days), and recent events.
| Param | Type | Notes |
|---|---|---|
| history_days | number | 1-365, default 90 |
Ranked (category × framework) clusters with the same six sub-scores the dashboard exposes (demand / supply gap / price attractiveness / comp weakness / framework gap / momentum).
| Param | Type | Notes |
|---|---|---|
| category | string | Filter to one category |
| framework | string | Filter to one framework |
| include_emerging | bool | Include sub-threshold clusters (default false) |
| limit | number | 1-100, default 30 |
Seller profile + their full portfolio (up to 100 listings).
Time-series view of a seller's catalog: listing count, average price, and quality score per day. Useful for tracking competitor expansion or pricing changes over time.
| Param | Type | Notes |
|---|---|---|
| days | number | 1-365, default 90 |
Daily timeline of a category — listing count, average price, and median quality. Powers the category-level reports.
| Param | Type | Notes |
|---|---|---|
| days | number | 1-365, default 90 |
Bulk CSV dump of listings (Agency only — same data as the listings endpoint, paginated up to 50k rows). Streams gzip; pass `since` to slice by last_seen.
| Param | Type | Notes |
|---|---|---|
| since | ISO 8601 datetime | Only listings updated since (default: 30 days ago) |
| limit | number | 1-50000, default 10000 |
Webhooks
Subscribe a URL to receive real-time events when listings change. Each delivery includes an HMAC-SHA256 signature so you can verify Stagecraft sent it. Available event types: listing.created, listing.removed, price.changed, sale.event.
List your active webhook subscriptions.
Create a new subscription. Returns the signing secret once — store it; it isn't retrievable later.
curl -X POST https://stagecraft.gg/api/v1/webhooks \
-H "Authorization: Bearer sk_live_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.example.com/hooks/stagecraft",
"event_types": ["price.changed", "listing.created"]
}'Fetch or revoke a subscription. DELETE marks it inactive — past deliveries remain auditable.
Verifying signatures
Every POST to your webhook URL carries two headers: X-Stagecraft-Timestamp (unix seconds) and X-Stagecraft-Signature (format t=<ts>,v1=<hex>). Compute HMAC_SHA256(secret, "{ts}.{raw_body}") and compare in constant time. Reject if the timestamp is more than 5 minutes off.
// Node.js receiver
import { createHmac, timingSafeEqual } from 'node:crypto';
function verify(rawBody, header, secret) {
const m = /^t=(\d+),v1=([a-f0-9]+)$/.exec(header || '');
if (!m) return false;
const ts = Number(m[1]);
if (Math.abs(Date.now() / 1000 - ts) > 300) return false;
const expected = createHmac('sha256', secret)
.update(`${ts}.${rawBody}`).digest('hex');
const a = Buffer.from(m[2]);
const b = Buffer.from(expected);
return a.length === b.length && timingSafeEqual(a, b);
}Respond with any 2xx within 10 seconds. Non-2xx responses are retried with exponential backoff; subscriptions disable themselves after sustained failures.
Response shape
Every successful response wraps the payload in a data field:
{
"data": [ ... ],
"pagination": { "total": 487, "limit": 50, "offset": 0, "has_more": true }
}Errors use a consistent shape:
{
"error": {
"code": "rate_limited",
"message": "Rate limit exceeded. Retry in 17s.",
"retry_after": 17
}
}Compliance
The API exposes the same public data the marketplace already publishes — never paid asset files, never buyer emails, never login-walled content. Don't redistribute bulk listing dumps; that violates Cfx PLA §3.1(6) and your Terms of Service. If you need a bulk export for analysis, email help@stagecraft.gg.
Versioning
The API is versioned in the URL (/v1/…). Breaking changes ship as /v2/… with overlap; v1 stays available for at least 12 months after v2 GA.