Developers

A small REST API and outbound webhooks to read your games, pull enriched leads, and stream lead events into your own tools. Available on the Scale plan.

Authentication

Create an API key in your dashboard and send it as a bearer token on every request. Keys are shown once at creation — store them securely.

curl https://secret.pics/api/v1/games \
  -H "Authorization: Bearer sp_your_key_here"

A missing or invalid key returns 401. A valid key on a plan without API access returns 403 upgrade_required.

Endpoints

All responses are JSON and scoped to the games you own. Base URL: https://secret.pics/api/v1

GET /games

List your games with headline metrics.

{
  "data": [
    {
      "slug": "summer-quiz",
      "title": "Summer quiz",
      "status": "live",
      "contentRating": "sfw",
      "inviteOnly": false,
      "url": "https://secret.pics/g/summer-quiz",
      "createdAt": "2026-08-01T10:00:00.000Z",
      "stats": { "views": 1240, "players": 380, "completions": 210 }
    }
  ]
}

GET /games/:slug

A single game with its masks and full stats (including the per-mask funnel).

GET /games/:slug/leads

Every captured lead with the answers they gave to each quiz mask — the JSON twin of the CSV export. Answers are keyed by mask reveal order.

{
  "count": 2,
  "data": [
    {
      "email": "alex@example.com",
      "verified": true,
      "capturedAt": "2026-08-02T09:12:00.000Z",
      "verifiedAt": "2026-08-02T09:15:00.000Z",
      "answers": { "1": "Marketing", "2": "50-200" }
    }
  ]
}

Webhooks

Register an HTTPS endpoint in your dashboard and we’ll POST a signed JSON payload when a lead event fires. Two event types today:

  • lead.captured — a player submitted their email at a gate.
  • lead.verified — the player confirmed via the double opt-in link.
{
  "id": "evt_9f3c...",
  "type": "lead.verified",
  "created": 1756809600,
  "data": {
    "game": { "slug": "summer-quiz", "title": "Summer quiz" },
    "email": "alex@example.com",
    "verified": true
  }
}

Verifying signatures

Each delivery carries an X-SecretPics-Signature header of the form t=<unix>,v1=<hex>. Recompute it as an HMAC-SHA256 of `${t}.${rawBody}` using your endpoint’s signing secret and compare:

const [t, v1] = sigHeader.split(',').map(p => p.split('=')[1]);
const expected = crypto.createHmac('sha256', secret)
  .update(`${t}.${rawBody}`).digest('hex');
// constant-time compare expected === v1

Deliveries time out after 8 seconds and are not retried in this version — respond quickly and reconcile with GET /games/:slug/leads if you miss one.

See plans →

← Back to secret.pics

Developers — secret.pics API