Developers

Suggency API

A read-only REST API for public bridge, profile, and collection data. Get a key, run one curl, see a 200 in under five minutes.

Overview

Quickstart: https://api.suggency.com/v1/api

  1. 1. Create an API key in your dashboard.
  2. 2. Send it as a Bearer token.
  3. 3. Call an endpoint — start with /stats (no parameters).
curl
curl https://api.suggency.com/v1/api/stats \
  -H "Authorization: Bearer sgy_your_key_here"
javascript
const res = await fetch("https://api.suggency.com/v1/api/stats", {
  headers: { Authorization: "Bearer sgy_your_key_here" },
});
const data = await res.json();
console.log(data);
python
import requests

res = requests.get(
    "https://api.suggency.com/v1/api/stats",
    headers={"Authorization": "Bearer sgy_your_key_here"},
)
print(res.json())

Get your API key

Authentication

API access is granted on approval — request it from your dashboard and, once approved, create a key. Every request needs an API key sent as a Bearer token. Keys are shown only once at creation — store them securely and never embed a key in client-side code.

Rotating keys

Create a new key, deploy it, then revoke the old one. You can hold up to 5 active keys, which is enough to rotate without downtime.

Rate limits

Each key is limited to 60 requests per minute. Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (epoch seconds). A fixed window can allow a brief 2x burst at the boundary. On 429, honor Retry-After.

javascript · retry
async function withRetry(url, opts, tries = 4) {
  for (let i = 0; i < tries; i++) {
    const res = await fetch(url, opts);
    if (res.status !== 429) return res;
    const retryAfter = Number(res.headers.get("Retry-After") ?? 1);
    // Honor Retry-After, add jitter. Never retry a 401.
    await new Promise((r) => setTimeout(r, (retryAfter * 1000) + Math.random() * 250));
  }
  throw new Error("rate limited");
}
python · retry
import time, random, requests

def with_retry(url, headers, tries=4):
    for _ in range(tries):
        res = requests.get(url, headers=headers)
        if res.status_code != 429:
            return res
        retry_after = int(res.headers.get("Retry-After", "1"))
        time.sleep(retry_after + random.uniform(0, 0.25))
    raise RuntimeError("rate limited")

Need a higher limit? Email developers@suggency.com. Note: creating extra keys does not raise your limit.

Errors

Every error returns the same envelope. Codes are a closed set — safe to switch on.

401missing_api_keyNo Authorization header was sent.
401invalid_api_keyThe key was not found.
401key_revokedThe key was revoked.
401key_expiredThe key has passed its expiry.
403insufficient_scopeThe key lacks the required scope.
401api_access_revokedAPI access for this account is not approved.
403api_access_requiredRequest and get API access approved before creating keys.
429rate_limitedToo many requests. Honor Retry-After.
429too_many_invalid_attemptsToo many invalid key attempts from your IP.
404not_foundThe resource does not exist.
400validation_failedA request parameter was invalid.
503service_unavailableTemporary outage. Retry with backoff.
500internal_errorAn unexpected error occurred.

Endpoints

GET/statsScope: read:public

Platform-wide counters (bridges, suggestors, passes).

Example response

{
  "bridges": 128,
  "suggestors": 54,
  "passes": 9203,
  "avg_score": 78.4
}
GET/bridgesScope: read:public

List published bridges (cursor paginated).

Parameters

  • limit integerPage size (default 20, max 100).
  • cursor stringOpaque cursor from next_cursor.
  • category stringFilter by category.
  • q stringFull-text search.

Example response

{
  "data": [
    {
      "id": "br_9xQ2",
      "slug": "best-mirrorless-camera",
      "title": "Best mirrorless camera for travel",
      "category": "tech",
      "published_at": "2026-06-30T10:00:00Z",
      "passes": 342,
      "score": 82,
      "suggestor": { "username": "oguz", "verified": true }
    }
  ],
  "has_more": true,
  "next_cursor": "MjAyNi0wNi0zMHwx"
}
GET/bridges/{slug}Scope: read:public

Fetch a single bridge by slug.

Parameters

  • slug string · requiredBridge slug.

Example response

{
  "id": "br_9xQ2",
  "title": "Best mirrorless camera for travel",
  "suggestion": "The Sony a6700 hits the sweet spot…",
  "category": "tech",
  "domain": "sony.com",
  "passes": 342,
  "suggestor": { "username": "oguz", "verified": true }
}
GET/profiles/{username}Scope: read:public

Public profile with published bridges.

Parameters

  • username string · requiredProfile username.

Example response

{
  "username": "oguz",
  "display_name": "Oğuz",
  "verified": true,
  "total_passes": 5210,
  "bridge_count": 24,
  "bridges": [ { "slug": "best-mirrorless-camera", "passes": 342 } ]
}
GET/meScope: read:me

The authenticated key owner's profile.

Example response

{
  "username": "oguz",
  "total_passes": 5210,
  "bridge_count": 24
}

Playground

Run a live request against the API with your own key. Your key stays in your browser and is never stored.

Every request needs an API key sent as a Bearer token

Versioning

The API is v1 (beta). We add fields without notice, so tolerate unknown fields. Breaking changes are announced in the Changelog with 90 days notice via Deprecation and Sunset headers.

Download OpenAPI

Changelog

  • 2026-07 · v1 (beta)

    Initial release: read-only public API, key management, rate limits, status page.