TUBEQUEST / DEVELOPER REFERENCE

Your family.
Your tools.

Read your children's recorded activity, see their questions and answers, and customize what they learn next.

API base URL: https://tubequest-server.onrender.com/api/v1

OpenAPI specification

1. Get your family API key

In TubeQuest, sign in as a parent and open Settings → Integrations → External API key. Generate a key, then send it in the X-API-Key header. It can read and edit only your family. Replacing or revoking it immediately disconnects the old key.

The examples use the server hosting this guide. Use https://tubequest-server.onrender.com in the app's server setting, without an /api suffix. Keep keys in secret storage, never in public website code or URLs.

# Set TUBEQUEST_API_KEY in your environment or secret manager first.
TUBEQUEST_SERVER='https://tubequest-server.onrender.com'
curl --fail-with-body \
  -H "X-API-Key: $TUBEQUEST_API_KEY" \
  "$TUBEQUEST_SERVER/api/v1/children"

The response contains the child IDs used in the paths below.

Import the OpenAPI specification by its URL to resolve its relative /api/v1 server automatically. If you download the JSON file, set your API client's base URL to the full API base URL shown above.

Daily API allowance

External integrations default to 100 requests per parent per day, resetting at midnight UTC. The allowance is shared across that parent's keys and survives key replacement and server restarts. The team can raise an individual allowance. Normal app and parent-portal activity do not use it.

Authenticated requests count even if they fail validation or are retries. Responses include X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset (Unix seconds). Once exhausted, requests stop before the endpoint runs and return 429, Retry-After, and code: API_DAILY_LIMIT_REACHED.

GET /api-usage is unmetered and remains available when the allowance is exhausted. It returns the current day's used, rejected, remaining and limit counts plus the ISO reset time. You can also see usage in the parent portal or the app's External API key screen. Public documentation is unmetered; report-generation limits remain separate.

2. Read activity and answers

Paths below are relative to /api/v1. All requests use GET.

PathWhat you receive
/childrenYour children's profiles and grades.
/children/{childId}/activityVideo opens and completions, questions, answers, searches, and child-related actions.
/children/{childId}/watch-historyVideo details, original search term, open time, completion status and recorded completion time.
/children/{childId}/questionsIssued math and reading questions, choices, expected answers, latest results, and links to source bank entries.
/children/{childId}/questions/{subject}/{questionId}One issued question. Subject is math or reading.
/children/{childId}/questions/{subject}/{questionId}/attemptsRecorded answers, correctness, times, and historical-coverage flags.

Lists of activity, watches, questions, and attempts return { items, total, limit, offset, nextOffset }. Default: 50 records; maximum: 200. Keep requesting offset=nextOffset until it is null.

Filter with from (inclusive) and to (exclusive), using full ISO timestamps. Question lists also accept subject=math|reading and status=unanswered|correct|incorrect. Activity accepts an event type. Set a fixed to before exporting multiple pages.

curl --fail-with-body \
  -H "X-API-Key: $TUBEQUEST_API_KEY" \
  "$TUBEQUEST_SERVER/api/v1/children/$TUBEQUEST_CHILD_ID/questions?subject=reading"

curl --fail-with-body \
  -H "X-API-Key: $TUBEQUEST_API_KEY" \
  "$TUBEQUEST_SERVER/api/v1/children/$TUBEQUEST_CHILD_ID/questions/math/QUESTION_ID/attempts"

3. Customize future questions

Reusable bank entries have different IDs from issued questions. Use an issued question's bankQuestionId when bankQuestionExists is true, or list the current bank first.

MethodPathBody
GET / POST/children/{childId}/math-questionsList, or add {"question":"8 + 9?","correctAnswer":"17"}
PATCH / DELETE/children/{childId}/math-questions/{bankId}Update question/answer, or remove.
GET / POST/children/{childId}/reading-wordsList, or add {"word":"curiosity"}
PATCH / DELETE/children/{childId}/reading-words/{bankId}Update {"word":"discovery"}, or remove.
POST/children/{childId}/reset-questionsReplace both banks from the child's grade templates.
curl --fail-with-body -X PATCH \
  -H "X-API-Key: $TUBEQUEST_API_KEY" \
  -H 'Content-Type: application/json' \
  --data '{"question":"What is 8 + 9?","correctAnswer":"17"}' \
  "$TUBEQUEST_SERVER/api/v1/children/$TUBEQUEST_CHILD_ID/math-questions/BANK_ENTRY_ID"

To change video filtering, PATCH /children/{childId} with {"contentFilterLevel":"unrestricted"}. Options are kids, strict, moderate, and unrestricted. New children default to kids, which combines YouTube strict SafeSearch with its made-for-kids label. Unrestricted disables YouTube SafeSearch; your family’s video, channel and keyword blocks still apply.

To configure voice search, PATCH /children/{childId} with {"voiceSearchEnabled":true} or false. Use null for the grade default: on for Kindergarten and Grade 1, off for older grades. Explicit parent choices survive grade changes. Voice and typed searches use the same content filters.

For correct-answer feedback, PATCH /children/{childId} with {"challengeSuccessMessage":"That is correct!","challengeSuccessAudioEnabled":true}. The message accepts 1–160 characters and appears for one second before video playback resumes. Spoken encouragement is on by default and rotates “Great job!”, “Excellent!”, and “Good answer!” using recordings bundled in the iOS and Android apps. Set the audio field to false for silent feedback. Omitted fields, grade changes, and question resets preserve your choices.

Edits apply to future questions. Already-issued questions and answer history stay intact, including through resets and grade changes. Changing a reading word clears its old audio. Resetting or changing grade replaces custom questions.

4. Learning reports and reviewed suggestions

Use GET /children/{childId}/progress for daily math/reading practice and first-try accuracy. Pass calendar dates from, inclusive through, and an IANA timeZone. Default: seven days; maximum: 90.

POST /children/{childId}/reports with the same fields and an id UUID generates an AI report. Reuse the UUID on retries. A 202 pending response can be polled with GET /children/{childId}/reports/{reportId}. GET the collection to list the latest 50 reports.

Reports include exact metrics, evidence, a narrative and proposed changes. Nothing changes automatically. Submit {"decision":"approve"} or {"decision":"reject"} to POST /children/{childId}/reports/{reportId}/suggestions/{suggestionId}/decision. Approvals apply only to your child, with stale-content checks and an atomic decision record.

Record a view using POST /children/{childId}/reports/{reportId}/view and {"id":"event-uuid"}; reuse that UUID on retries. Polls do not count as views. Reports need a server-side OpenRouter key; charts do not. A family can request up to 10 reports per 24 hours. Full request/response schemas are in the OpenAPI specification.

5. Community blocks

GET /community/blocks returns separate top-ten lists of videos and channels that other parents block, excluding entries in your own video/channel block lists. Each includes a count and a percentage of all parent accounts on this server, including parents with no blocks. Parents count once per item; identities and private reasons are never returned.

POST /community/blocks with an id UUID, videoIds and channelNames adds up to ten of each to your family blocks. At least one item is required. Reuse the same UUID and targets for retries. The operation is atomic and returns the original receipt on retry; it never selects the next batch for you. GET again after success to refresh the suggestions. Unknown or stale targets return 409.

Existing blocks and reasons are preserved. Additions apply to search and replay and can be undone in the app’s blocked-content lists. Each batch of actual additions records one usage event, without duplicate events on retry. Video titles come from public YouTube metadata when available.

What the history can tell you

New answer attempts are retained, including wrong answers followed by corrections. Older questions may contain only their last saved answer: those attempts have legacySnapshot: true and the question has attemptHistoryComplete: false. Earlier overwritten answers cannot be recovered.

Older completion times and source-bank IDs can be null. Video length is not time spent watching. The current app does not upload playback positions, pauses, or replay events. Search text is available for newly recorded search events and for searches already attached to watch records.

Errors return a message: 400 for invalid input, 401 for invalid keys, 403 for wrong roles, 404 for missing or non-owned resources, and 409 for duplicate reading words.

Account levels and IEP practice

Families have a Free, Paid, or Paid Premium level, assigned by team admins. New accounts start Free. GET /account-plan returns {tier, label, features: {iep}}. Only Paid Premium enables IEP uploads, generation, adoption and program clearing. Core features currently remain available at all three levels. Billing is not connected. Use GET /premium to check access and AI availability. In the parent portal, choose a child’s IEP practice link to upload a searchable PDF, Word document or text file, review the extracted goals, and explicitly agree to share them with the configured OpenRouter model.

The API offers the same workflow under /children/{childId}/iep: POST /extract?type=pdf|docx|txt (raw document bytes), POST /plans with a UUID, reviewed text and consent, GET /plans/{planId}, and POST /plans/{planId}/adopt with either a question ID or section name. Sections are math, geometry, algebra and reading. Generation never changes the bank automatically.

To replace the program, fetch GET /program and explicitly confirm POST /program/clear with its current revision, a UUID, and confirmation: "CLEAR". Then adopt the desired proposals. Reusing a completed clear request never removes newer questions. Past learning history is kept. Three new generations are allowed per family per rolling 24 hours. See the OpenAPI specification for request and response schemas.

Raw documents and reviewed input are discarded after processing. Saved plans remain private to the owning family and can be deleted with DELETE /plans/{planId}, including after premium access is disabled. Adopted questions and activity history remain. Comprehension questions appear in the reading bank with passage, prompt, choices and the correct answer available to the parent.

Daily learning reports

Each child can request one learning report per calendar date in the server’s report timezone. Failed attempts count too. Use GET /children/{childId}/reports/allowance for the remaining allowance and next midnight reset. Changing the report period does not reset the limit. Saved reports and suggestion decisions remain available. Unavailable generation returns a saved failed report with a short parent-facing message.