Migrating from OpenTDB#
QuizBase is designed for drop-in migration from Open Trivia DB. The endpoints, fields, and category ids map cleanly — most existing clients need only two changes.
The two changes#
- Base URL:
https://opentdb.com/api.php→https://quizbase.runriva.com/api/v1/questions/random - Add auth:
X-API-Key: qb_pk_*header
That’s it for the happy path. The response shape is different — see below — but the semantics are identical.
Field mapping (question)#
| OpenTDB field | QuizBase field | Notes |
|---|---|---|
category (string) | category.name + category.slug + category.id | QuizBase returns a nested object. category.id equals opentdbId when applicable. |
type | type | Same enum: multiple, boolean. QuizBase adds text_input. |
difficulty | difficulty | Same enum: easy, medium, hard. |
question | text | Renamed — question → text. |
correct_answer | correctAnswer | camelCase. |
incorrect_answers | incorrectAnswers | camelCase. |
| — | language | New — ISO 639-1. OpenTDB is English-only. |
| — | id | New — UUID v7. Use for caching/dedup. |
| — | attribution | New — { author, source, license, sourceId, url }. Mandatory to preserve (CC-BY-SA chain). |
| — | tags, subcategories | New — filter-friendly metadata. Both arrays of { slug, label }: slug is the stable filter key (kebab-case), label is the human-readable string in the requested ?lang=. Tags are short concept identifiers, subcategories are broader topic groupings. |
| — | regions | New — array of ISO 3166-1 codes. Optional, present where geographically relevant. |
Envelope mapping#
| OpenTDB | QuizBase |
|---|---|
response_code | ❌ removed — use HTTP status codes + RFC 9457 error body |
results[] | data[] |
| — | meta: { count, requestId, language } |
OpenTDB’s response_code: 1/2/3/4/5 (no results / invalid param / token not found / token empty / rate limit) maps to:
| OpenTDB code | QuizBase response |
|---|---|
0 (success) | 200 + data populated |
1 (no results) | 200 + data: [] |
2 (invalid param) | 400 + RFC 9457 with errors[] |
3/4 (session token) | ❌ not applicable — use exclude=<ids> for de-dup |
5 (rate limit) | 429 + Retry-After header |
Category ids#
OpenTDB uses numeric ids 9–32. QuizBase preserves them on our category table as opentdbId. You can pass either the numeric id or our slug — both work:
# OpenTDB-style numeric id
curl -H "X-API-Key: qb_pk_YOUR_KEY"
"https://quizbase.runriva.com/api/v1/questions/random?amount=5&category=22"
# QuizBase slug
curl -H "X-API-Key: qb_pk_YOUR_KEY"
"https://quizbase.runriva.com/api/v1/questions/random?amount=5&category=geography" Call GET /v1/categories once and build your id↔slug map.
Side-by-side diff#
Session tokens (OpenTDB) → exclude (QuizBase)#
OpenTDB’s session-token system (codes 3/4) prevents repeats in a session. QuizBase replaces it with explicit exclude:
# Fetch 5 questions, excluding those you've already shown
curl -H "X-API-Key: qb_pk_YOUR_KEY"
"https://quizbase.runriva.com/api/v1/questions/random?amount=5&exclude=id1,id2,id3" Max 100 ids per request. Track them client-side.
Rate limits#
OpenTDB is “don’t abuse” without headers. QuizBase uses IETF RateLimit-* headers on every response — measure yourself and respect Retry-After on 429. See Errors and retries.
See also#
- GET /v1/questions/random — full parameter list
- Languages and translations — something OpenTDB never had