TUBEQUEST / DEVELOPER REFERENCE
Your family.
Your tools.
Read your children's recorded activity, customize their questions and video controls, and review learning reports and suggestions.
API base URL: https://atypicool.com/api/v1
1. Connect with your family API key
In the parent app, open Settings → Integrations → External API key, or use the parent portal's API access controls. Generate a key and send it in X-API-Key. It can read and edit only your family. Replacing or revoking the key immediately disconnects the old one. Store keys securely, never in public website code or URLs.
# Set TUBEQUEST_API_KEY in your environment or secret manager first.
TUBEQUEST_SERVER='https://atypicool.com'
curl --fail-with-body \
-H "X-API-Key: $TUBEQUEST_API_KEY" \
"$TUBEQUEST_SERVER/api/v1/children"
The response contains your child IDs. All paths below are relative to /api/v1. Import the OpenAPI specification by URL to resolve its relative server automatically. If you download the JSON, set your client's full base URL to the one above. Examples follow the server hosting this guide.
GET /api-key reads the current secret key record; POST /api-key rotates it and DELETE /api-key revokes it. A lost rotation response requires recovery through your signed-in parent app/portal because the old key immediately stops working. These key-authenticated mutations use the ordinary API allowance; the parent session remains available after exhaustion.
POST /children/{childId}/session issues a child {token} for child app routes, sent as Authorization: Bearer …. It has no automatic expiration and remains valid until revoked. It cannot manage parents or other children. Keep that token secret too. Key rotation does not revoke existing child sessions; signing out revokes the current token and a parent password reset invalidates family credentials.
App and admin boundaries: signed-in apps and browsers use /api/parent for the same family functionality; browser writes are restricted to trusted origins. Child search and quiz routes require app sessions. /api/team is restricted to authorized TubeQuest team sessions. A family API key never grants access to another family, team messages, login locations, account-level changes or quota administration—even if its owner is a team member. Browser child-mode handoff requires a parent browser session and is not available to API keys.
2. Child profiles and learning settings
Family opening links: GET /settings reads allowYouTubeLinks (default true). Send PATCH /settings with {"allowYouTubeLinks":false} to restrict opening videos on other sites for all existing and future children, or true to restore them. Parent previews keep their links. This does not change content filtering, questions, history or data retention. Unknown fields and non-boolean values are rejected.
App sessions use the equivalent /api/parent/settings routes. Child apps get the current family permission from authenticated GET /api/mobile/config; do not infer it from a child profile. Refresh configuration before playback and when the app returns to the foreground.
GET /children lists your profiles. POST /children creates a parent-managed child with {"firstName":"Benny","grade":"grade1"} and copies the grade's templates. No child email/password is needed. Use GET /children/{childId} to read a profile and PATCH on that path to update selected fields.
| Field | Values and defaults |
|---|---|
firstName, grade | Name: 1–80 trimmed characters. Grade: kindergarten, grade1 through grade7. |
contentFilterLevel | kids (default), strict, moderate, unrestricted. |
voiceSearchEnabled | true, false, or null for the grade default: on in Kindergarten/Grade 1, off in older grades. |
mathQuestionInterval | Whole number 1–100 video starts between challenges; default 3. |
questionIntervalMinutes | Whole number 1–100 minutes of active foreground playback between challenges; default 5. |
mathQuestionsEnabled, readingQuestionsEnabled, readingComprehensionEnabled | Per-category toggles. Math and listening default on. Comprehension is available/default on in Grades 2–7. Keep at least one available category enabled. |
challengeSuccessMessage, challengeSuccessAudioEnabled | Message: 1–160 trimmed characters, default “That is correct!”. Spoken encouragement defaults on. |
Omitted PATCH fields are preserved. Disabling a question type keeps its bank and history. Moving into Grade 2 or above enables comprehension unless explicitly disabled in that update. Explicit voice settings survive grade edits; null restores the grade default.
Changing grade replaces custom question banks. Other settings do not. Either video count or playback time can trigger a challenge, whichever comes first. A correct answer resets both counters, displays feedback for one second, and resumes the same video. The audio toggle controls the bundled “Great job!”, “Excellent!” and “Good answer!” encouragement.
kids combines YouTube strict SafeSearch with its made-for-kids label. unrestricted disables SafeSearch; family video, channel and keyword blocks still apply. Voice and typed searches use the same restrictions. GET /templates provides grade/template counts. Set challenge intervals on each child; sending mathQuestionInterval to the family PATCH /settings still returns 409 without changing any settings.
3. Read activity and answers
| GET path | What you receive |
|---|---|
/children/{childId}/activity | Videos, questions, answers, searches, parent edits, report reviews and IEP actions. |
/children/{childId}/watch-history | Video details, original search term, open/completion time and the client-reported quiz flag. |
/children/{childId}/questions | Issued question snapshots, choices, expected answers, latest results and source bank IDs. |
/children/{childId}/questions/{subject}/{questionId} | One issued question. Path subject is math or reading. |
/children/{childId}/questions/{subject}/{questionId}/attempts | Recorded answers, correctness, time, learning outcome and historical-coverage flags. |
Lists return {items,total,limit,offset,nextOffset}. Default limit: 50; maximum: 200. Continue with offset=nextOffset until null. Activity, watches and questions sort newest first; attempts sort oldest first.
Filter using full ISO timestamps with from inclusive and to exclusive. Question lists use the time asked; watches use open time; attempts use answer time. Hold to constant across an export. Question lists also accept subject=math|reading|reading_comprehension and status=unanswered|correct|incorrect (latest result). Activity accepts an event type; the OpenAPI specification lists every supported value.
Watch history covers the most recent 29 days (29 × 24 hours from opening a video). Older date filters do not recover expired watches or video-opened/completed activity. Startup/daily cleanup deletes expired watch records and legacy copies of these video events from the active database. Questions, answers, separate search activity, blocks, account totals and saved report snapshots are retained separately. Newly calculated video counts use available history; saved report counts are not rewritten.
reading in a list filter means Listening. Both reading types still use reading in detail/attempt paths; response category and readingKind distinguish them. Comprehension includes the original passage, prompt and skill where recorded. Use bankQuestionId only when bankQuestionExists is true to edit its current source.
curl --fail-with-body \
-H "X-API-Key: $TUBEQUEST_API_KEY" \
"$TUBEQUEST_SERVER/api/v1/children/$TUBEQUEST_CHILD_ID/questions?subject=reading_comprehension&status=incorrect"
Multiple-choice attempts include displayedChoices, correctPosition, and selectedPosition when recorded by the app. Positions start at 1 and follow the displayed order (left to right within a row, then top to bottom). The server verifies the selected answer and calculates the correct position. These fields appear in question attempts, the latest answer, report answers, and answer activity details. Older app versions and typed answers return null; their positions cannot be reconstructed reliably.
Attempts can include attemptNumber and learningOutcome: first_try_correct, correct_after_help, incorrect, question_replaced, or historical answer_revealed. The second mistake now replaces the question without showing its answer; replacement is not a success or reveal. Assisted successes are not independent mastery. Null fields mean that older activity did not record the information.
4. Customize future questions
Reusable bank IDs, template IDs and issued-question IDs are different. List the child's banks before editing. Changes apply to future questions; original issued questions, answers and saved reports stay intact.
| Method | Path | Input or result |
|---|---|---|
| GET / POST | /children/{childId}/math-questions | List, or add {"question":"8 + 9?","correctAnswer":"17"}. |
| PATCH / DELETE | /children/{childId}/math-questions/{bankId} | Update question/answer, or remove. |
| GET / POST | /children/{childId}/reading-words | List, or add a listening word or comprehension question. |
| PATCH / DELETE | /children/{childId}/reading-words/{bankId} | Edit within the current type, or remove. |
| POST | /children/{childId}/reading-words/{bankId}/audio | Prepare listening-word audio; requires an available server audio provider. |
| POST | /children/{childId}/reset-questions | Replace all categories from the current grade's templates. |
| GET / POST | /children/{childId}/question-catalog | Browse templates, or add a reviewed selection. |
| POST | /children/{childId}/questions/bulk-delete | Remove several bank entries together. |
Math accepts integers, decimals, fractions and mixed numbers. Listening input is {"word":"curiosity"}: 1–100 characters and unique within the child's listening bank ignoring capitalization. Changing a word clears its old audio; past questions retain their recordings.
Reading comprehension: create or edit with a nonempty passage (up to 2,000 characters), questionText (up to 1,000), 2–4 distinct answerChoices (up to 100 each), and word matching the exact correct choice. Send all four fields on PATCH. Optional skill, standard, topic and explanation describe the learning purpose. New comprehension entries require Grade 2 or above. A PATCH cannot change an entry's type, and comprehension does not play the correct answer aloud.
{
"word": "The pond",
"questionText": "Where did the frog jump?",
"passage": "A frog sat on a rock. Then it jumped into the pond.",
"answerChoices": ["The tree", "The pond", "The house"]
}
Question catalog: GET returns templates with grades, subjects and inBank flags. POST {"id":"request-uuid","version":1001,"childGrade":"grade2","ids":["template-id"]}, using the version and child grade actually returned by GET. Select 1–1,000 unique IDs. Existing questions are skipped and custom edits are preserved; new questions keep their catalog grade. Comprehension adoption requires Grade 2 or above. The receipt includes added, skipped, mathAdded and readingAdded (both reading types). Reuse the UUID and selection on retries. If grade/catalog changed, refresh and review before a new request.
Delete selected questions: after confirming the selection, POST {"mathIds":["bank-id"],"readingIds":["bank-id"]} to the bulk-delete path. Omit an unused array; use readingIds for either reading type. Select up to 1,000 total entries. The batch is atomic and child-scoped; already removed IDs are skipped safely on retries. The receipt reports deleted, mathDeleted, readingDeleted and alreadyRemoved.
Resetting or changing grade replaces custom questions. Disabling categories, bank edits and deletions preserve recorded history. Do not use resets to add a few templates; use the catalog selection.
5. Block specific videos and channels
Restrictions apply to every child in your family, even when opened from one child's profile.
| Method | Path | Input or result |
|---|---|---|
| GET | /blocked-videos | Blocks with title, channel, thumbnail and detailsSource. |
| POST | /videos/block | {"videoId":"YouTube link or 11-character ID","reason":"Optional note"}. |
| DELETE | /videos/unblock/{videoId} | Remove a direct video block using its normalized ID. |
| GET | /blocked-channels | Family channel blocks. |
| POST | /channels/block | {"channelName":"Example channel","reason":"Optional note"}. |
| DELETE | /channels/unblock/{channelName} | Remove a channel block; URL-encode the name. |
| GET | /blocked-keywords | Family keyword blocks. |
| POST | /keywords/block | {"keywords":"first keyword,second keyword"}. |
| DELETE | /keywords/{keyword} | Remove a keyword; URL-encode it. |
Channel names and keywords are trimmed and lowercased; channel blocks use names, not YouTube channel IDs. Duplicate direct video/channel blocks return 409. Removing a video block does not override another matching channel, keyword or content filter.
detailsSource is youtube, watch_history from your own family, or unavailable. Missing metadata produces nullable display fields while the video stays blocked. Other families' private reasons and history are never exposed.
Community blocks: GET /community/blocks gives separate top-ten lists of videos and channels, excluding your direct blocks. Each percentage uses all parent accounts on this server, including those with no blocks; children are excluded and each parent counts once.
POST to the same path with {"id":"request-uuid","videoIds":["abcdefghijk"],"channelNames":["example channel"]}. Select at most ten of each and at least one total. Submit the exact displayed selection, then GET again for the next lists. Retries with the same UUID/targets return the original {id,addedVideos,addedChannels} receipt. Different targets for a reused UUID, or targets no longer blocked by anyone, return 409. Existing reasons and timestamps are preserved.
6. Learning reports and reviewed suggestions
GET /children/{childId}/progress returns exact metrics, LLM availability and the report allowance. Use calendar dates from and inclusive through, plus an IANA timeZone (default UTC). Default: seven days including today; maximum: 90, ending today or earlier. These calendar fields differ from activity's exclusive ISO to timestamp.
metrics.questionOutcomes provides Math, Listening and Reading comprehension groups with a daily array of firstTry, secondTry, laterTry, unanswered, unknown, assisted and total. Each issued question counts once on its presentation date, using answers known by the period end/snapshot. unanswered means no correct answer, including no submission and replaced questions; unknown means incomplete history. Assisted counts overlap successful buckets and must not be added to totals or treated as independent mastery. Older saved reports may omit this breakdown.
The separate daily practice metrics follow answer dates. First-try accuracy excludes incomplete history and assisted successes; later corrections do not improve it. Null accuracy means no known first attempts. Charts are calculated from records, not by the model.
| Method | Path | Behavior |
|---|---|---|
| GET | /children/{childId}/progress/answers | Answer rows for live metrics, including retries and original questions/passages. |
| GET | /children/{childId}/reports/allowance | Used, pending, remaining and reset information. |
| GET / POST | /children/{childId}/reports | Latest 50 report summaries, or generate with a UUID and calendar range. |
| GET | /children/{childId}/reports/{reportId} | Saved metrics, evidence, narrative and suggestions. |
| GET | /children/{childId}/reports/{reportId}/answers | Answer rows at the report's saved range/cutoff. |
| POST | /children/{childId}/reports/{reportId}/view | {"id":"event-uuid"} explicitly records a view. |
| POST | /children/{childId}/reports/{reportId}/suggestions/{suggestionId}/decision | {"decision":"approve"} or {"decision":"reject"}. |
| POST | /children/{childId}/reports/{reportId}/suggestions/accept-all | {"suggestionIds":["suggestion-uuid"]}, 1–20 unique reviewed IDs. |
Answer lists accept categories=math,reading,reading_comprehension and result=all|correct|incorrect, plus pagination. Omitted categories means all; empty means none. Live requests accept the metrics' range and asOf; preserve the first cutoff across pages. Saved-report answer requests reject custom dates, time zones and cutoffs. Both return {items,total,limit,offset,nextOffset,range,asOf}, and do not call an LLM.
{
"id": "NEW_REQUEST_UUID",
"from": "2026-09-18",
"through": "2026-09-24",
"timeZone": "America/Los_Angeles"
}
Persist the report UUID before POST and allow about 80 seconds plus network/database overhead. On a lost response, GET that report or retry the identical UUID/range. A concurrent retry can return 202 with status: "pending"; poll GET until ready or failed. Inspect the status even on HTTP 200. Failed reports keep their original metrics and a short error message; use a new UUID only for a deliberate new attempt.
Daily learning reports: each child defaults to three successful reports per server calendar date. Failed reports do not consume usage. Pending requests reserve capacity temporarily and expire after three minutes if interrupted. Team admins can adjust the family's per-child limit. The allowance response contains date, now, timeZone, limit, used, pending, remaining, resetAt and reportId. The server's report time zone controls reset, independently of chart/device time zones. Exhaustion returns 429 with code: REPORT_DAILY_LIMIT and allowance.
Reports suggest supported new practice and removals of already mastered questions. Removals need repeated independent success: at least five known first attempts, successful first tries on three days, at least 90% first-try accuracy, the latest three correct, and no incomplete history. Unsupported optional suggestions are omitted without discarding a valid report. Nothing changes until a parent approves.
Individual decisions and Accept all use that parent's family permissions. Accept all submits the explicit suggestions the parent reviewed, applies additions before removals, preserves earlier decisions and skips stale content. Unknown or foreign IDs reject the batch before changes. Retries do not reapply changes, and all reviews/applications are recorded. Deletions preserve learning history; GET polling does not count as a view. Reports require the server's configured OpenRouter provider; charts do not.
7. Account levels and IEP practice
GET /account-plan returns {tier,label,features:{iep}}, with stored tiers free, paid and paid_premium. GET /premium also provides compatible enabled and LLM availability. IEP processing and adoption currently require team-enabled Paid Premium. Parents can still read/delete saved plans after access is removed.
The published Free/Basic/Pro plans describe upcoming subscriptions. Billing, trial enforcement, weekly automatic question updates and Pro-only API restrictions are not live. First-login tracking sets a 14-day initial trial deadline, editable only by the team; it currently does not expire API access.
All paths below start with /children/{childId}/iep.
| Method | Suffix | Input or result |
|---|---|---|
| POST | /extract?type=pdf|docx|txt | Raw document bytes, Content-Type: application/octet-stream, maximum 10 MiB. Returns text for review. |
| GET / POST | /plans | Latest 50 summaries, or {"id":"request-uuid","text":"Reviewed learning goals…","consent":true}. |
| GET / DELETE | /plans/{planId} | Read or delete a saved plan. |
| POST | /plans/{planId}/adopt | {"questionId":"question-uuid"} or {"section":"math"}. |
| GET | /program | Current bank counts and revision. |
| POST | /program/clear | {"id":"request-uuid","revision":"CURRENT_REVISION","confirmation":"CLEAR"}. |
Review extracted text before explicitly agreeing to send it to the configured OpenRouter model. Supply 30–12,000 trimmed characters. Raw documents and reviewed input are discarded after processing. Plan sections are math, geometry, algebra and reading. Reading proposals are comprehension and require a supported grade to adopt. Generation never changes banks automatically.
IEP generation allows three new requests per family per rolling 24 hours, including admitted requests that fail. This is separate from the successful-learning-report limit. Reuse a plan UUID and identical input for network retries, and inspect pending, ready or failed status. Adoption retries never recreate questions removed later. Clearing checks the reviewed revision; retrying a completed clear cannot remove newer questions. Deleting a plan keeps adopted questions/history and does not refund generation usage.
Daily API allowance and errors
External integrations default to 100 requests per parent per UTC day. Team admins can raise an individual allowance. It is shared across the parent's keys and survives key replacement and restarts. Normal app/portal sessions and public documentation do not use it.
Authenticated requests count even when they fail validation or are retries. Responses include X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (Unix seconds). Exhaustion returns 429 before the endpoint runs, Retry-After and code: API_DAILY_LIMIT_REACHED. Check its resetAt or request a higher allowance from the team. Report-generation and IEP limits are separate.
GET /api-usage (also HEAD) remains unmetered and available after exhaustion. It returns day, limit, used, rejected, remaining, resetAt, timeZone, hasOverride and defaultLimit. Report polling and failed generation requests still use the ordinary external API allowance.
Errors return {"message":"…"}, with extra fields for some limits. Common statuses: 400 invalid input; 401 invalid/revoked key; 403 role or entitlement restriction; 404 missing or non-owned resource; 409 duplicate, stale content or reused request ID; 413 oversized document; 415 wrong upload type; 422 unsupported document or oversized history window; 429 quota/concurrency limit; 503 unavailable provider/templates. Honor Retry-After when supplied.
Historical coverage and compatibility
Modern answer attempts retain wrong answers followed by corrections. Older questions may only contain their latest saved answer, marked legacySnapshot: true and attemptHistoryComplete: false. Missing earlier answers cannot be recovered. Older completion times and source-bank IDs can be null.
Video length is not time spent watching. Current apps do not upload continuous playback positions, pauses or replay events. Search text is available only where tracking retained it. Parent activity does not include credentials, login IP/location data, other families' information or team message content.
Prefer child-scoped paginated routes for new integrations. Compatibility GET /watch-history returns a family array with optional userId, ISO from/to and limit 1–500. GET /analytics/math-history requires a child userId and provides the older math-only summary with startDate, endDate, difficulty, isCorrect and limit 1–500. Use progress/report routes for all categories and explicit time zones.