Skip to content
Command Palette
Search for a command to run...
QuizBase · Docs

GET /v1/questions#

GET /api/v1/questions API key required

Paginated browse of the full question catalog. Use this when you need all matching questions (e.g. building a local cache, a study app, or a data exporter) — not random samples.

Cursor-based pagination using UUID v7 ordering — stable across inserts, no page-number drift.

Parameters#

ParameterTypeDefaultDescription
cursor UUID v7Last `id` from the previous page. Omit for the first page.
limit integer20Page size, max 100.
lang enumenSupported: `en`, `pl`. Strict — any other value returns `400`.
updated_since ISO 8601Only questions with `updatedAt >= this`. Delta-sync pattern.
category integer or slugCategory id (1-24 internal, or 9-32 opentdbId) or slug.
difficulty enum`easy` | `medium` | `hard`
type enumDefault response includes `multiple` and `boolean` only. Pass `?type=text_input` to opt into open-ended questions explicitly.
tags CSV kebab-caseAll-of match (AND). Each returned question echoes tags as `{slug, label}` objects.
tags_any CSV kebab-caseAny-of match (OR), max 10. Use when AND logic is too restrictive.
topic kebab-caseCurated topic slug (resolves through aliases). 2,184 curated topics — see [GET /v1/topics](/docs/api/topics).
topics_any CSV kebab-caseAny-of match (OR) on curated topics, max 10.
subcategory kebab-caseRaw subcategory slug. Single-value filter; prefer `topic`/`topics_any` for OR semantics across many.
quality `high`Pass `quality=high` to exclude questions our internal review flagged for distractor problems.
regions CSV ISO 3166-1All-of match (AND), lowercase 2-letter codes.
source enum`opentdb` | `opentriviaqa` | `mkqa` | `mintaka` | `nq-open` | `kqa-pro` | `entityq` | `quizbase` | …
license SPDXe.g. `CC-BY-SA-4.0`, `MIT`. Filter by license string.
count enumestimateHow to compute total: `estimate` (cheap, ±5-50% via planner stats) → `meta.totalEstimate`; `exact` (slow, 5-9s on full dataset) → `meta.total`; `none` (skip).

Examples#

First page#

Delta sync#

Fetch only questions updated since your last sync:

curl -H "X-API-Key: qb_pk_YOUR_KEY" 
     "https://quizbase.runriva.com/api/v1/questions?lang=pl&updated_since=2026-04-01T00:00:00Z&limit=100"

Persist the highest updatedAt you’ve seen and use it as the next updated_since.

Response#

Response fields#

  • tags / subcategories — both arrays of { slug, label }. The slug is the stable identifier you filter by; the label is a human-readable string in the requested ?lang=. Tags are short identifiers (≤4 words, proper nouns and concepts), subcategories are broader topic groupings (≤4 words, organic). A question typically has 3-5 tags and 3-6 subcategories.
  • category — the top-level category (24 in total). id is the legacy OpenTDB id (9-32). name is localized to ?lang= with English fallback if a translation is missing.
  • translationOf / rootQuestionId — non-null when this row is a translation. translationOf is the direct parent (usually English source), rootQuestionId is the canonical source across translation chains.
  • translator — coarse provenance: "machine" (machine-translated from the source language), "human" (manually translated/edited), "native" (imported as-is from a multilingual upstream source), or null (original-language record, no translation involved). The specific upstream system that produced a machine translation is an implementation detail and not exposed.
  • extensions — forward-compatible container for stable per-source extras. Today exposes subcategories: string[] (also surfaced as the typed top-level subcategories: [{slug, label}]). Future stable fields land here additively. Internal pipeline observability (model versions, prompt versions, run IDs) is not exposed here — that’s audit data we keep server-side.

License metadata in attribution#

The 9-field attribution object gives you everything needed to comply with upstream licenses without consulting external docs:

  • license — the effective applied license string (e.g. CC-BY-SA-4.0 — with 3.0 → 4.0 upgrade for sources where applicable).
  • licenseVersion — the original upstream license version ("3.0", "4.0", or null for MIT). Use this when you need the exact version the upstream record came under.
  • licenseUrl — the canonical license URL (creativecommons.org or opensource.org). null for proprietary records.
  • modifications — array of changes we made on top of the upstream record. Possible values: translated_<lang> (per-language), refined_text (we improved phrasing), quizified (we converted a Q&A pair into a quiz item with distractors). An empty array means we kept the upstream record verbatim.
  • lastModified — ISO timestamp of our last modification (updatedAt). Use this for cache invalidation and updated_since syncs.

If you redistribute records covered by share-alike licenses, build your attribution string using author + licenseUrl + the modifications list.

Stop condition#

When _links.next is absent, you’ve reached the end. Some pages may return fewer than limit rows even mid-stream — do not use “fewer rows than limit” as a stop condition.

Rate limits#

Pagination lets you burn through your quota fast. Consider:

  • Requesting limit=100 (max) to halve request count
  • Using updated_since for incremental syncs after initial fetch
  • Caching on your side — questions don’t change often

Performance#

  • p50 (warm): ~97ms
  • p95: ~112ms (sustained 50 RPS, baseline)
  • p99: ~200ms
  • Last measured: 2026-05-07
  • SLO: p95 < 500ms, error rate < 1%
  • Cursor pagination scales to any catalog size — performance stays flat as you walk forward.
  • ?count=estimate (default) returns in tens of milliseconds. ?count=exact walks the full set (5-9s on the current dataset) — use sparingly, only when you genuinely need an exact total.

See also#