[{"data":1,"prerenderedAt":3726},["ShallowReactive",2],{"api-nav":3,"api-guide:\u002Fapi\u002Ftroubleshooting":351,"api-spec:guide:\u002Fapi\u002Ftroubleshooting":3625},[4,28,57,95,115,301,317,331],{"id":5,"title":6,"links":7,"groups":27},"start","Start here",[8,11,15,18,21,24],{"title":9,"to":10},"Overview","\u002Fapi",{"title":12,"to":13,"status":14},"Quickstart","\u002Fapi\u002Fquickstart","available",{"title":16,"to":17,"status":14},"Environments","\u002Fapi\u002Fenvironments",{"title":19,"to":20,"status":14},"Authentication","\u002Fapi\u002Fauthentication",{"title":22,"to":23,"status":14},"Organizations","\u002Fapi\u002Forganizations",{"title":25,"to":26,"status":14},"Permissions","\u002Fapi\u002Fpermissions",[],{"id":29,"title":30,"links":31,"groups":56},"concepts","Concepts",[32,35,38,41,44,47,50,53],{"title":33,"to":34,"status":14},"Requests and responses","\u002Fapi\u002Frequests-and-responses",{"title":36,"to":37,"status":14},"Identifiers","\u002Fapi\u002Fidentifiers",{"title":39,"to":40,"status":14},"Pagination","\u002Fapi\u002Fpagination",{"title":42,"to":43},"Errors","\u002Fapi\u002Ferrors",{"title":45,"to":46,"status":14},"Rate limits","\u002Fapi\u002Frate-limits",{"title":48,"to":49,"status":14},"Retries","\u002Fapi\u002Fretries-and-idempotency",{"title":51,"to":52,"status":14},"Security","\u002Fapi\u002Fsecurity",{"title":54,"to":55,"status":14},"Versioning","\u002Fapi\u002Fversioning",[],{"id":58,"title":59,"links":60,"groups":94},"resources","Guides",[61,64,67,70,73,76,79,82,85,88,91],{"title":62,"to":63,"status":14},"Students","\u002Fapi\u002Fguides\u002Fstudents",{"title":65,"to":66,"status":14},"Bulk registration","\u002Fapi\u002Fguides\u002Fbulk-registration",{"title":68,"to":69,"status":14},"Passwords","\u002Fapi\u002Fguides\u002Fpasswords",{"title":71,"to":72,"status":14},"Supervisors","\u002Fapi\u002Fguides\u002Fsupervisors",{"title":74,"to":75,"status":14},"Reference data","\u002Fapi\u002Fguides\u002Freference-data",{"title":77,"to":78,"status":14},"API account","\u002Fapi\u002Fguides\u002Fapi-account",{"title":80,"to":81,"status":14},"Sign-in links","\u002Fapi\u002Fguides\u002Fsign-in-links",{"title":83,"to":84,"status":14},"Exams","\u002Fapi\u002Fguides\u002Fexams",{"title":86,"to":87,"status":14},"Applications","\u002Fapi\u002Fguides\u002Fapplications",{"title":89,"to":90,"status":14},"Group challenges","\u002Fapi\u002Fguides\u002Fgroup-challenges",{"title":92,"to":93,"status":14},"Certificates and reports","\u002Fapi\u002Fguides\u002Fcertificates-and-reports",[],{"id":96,"title":97,"links":98,"groups":114},"tutorials","Tutorials",[99,102,105,108,111],{"title":100,"to":101,"status":14},"Register and apply","\u002Fapi\u002Ftutorials\u002Fregister-and-apply",{"title":103,"to":104,"status":14},"Send a student to the panel","\u002Fapi\u002Ftutorials\u002Fsend-student-to-panel",{"title":106,"to":107,"status":14},"Change an application","\u002Fapi\u002Ftutorials\u002Fchange-an-application",{"title":109,"to":110,"status":14},"Collect results","\u002Fapi\u002Ftutorials\u002Fcollect-results",{"title":112,"to":113,"status":14},"Token handling","\u002Fapi\u002Ftutorials\u002Ftoken-handling",[],{"id":116,"title":117,"links":118,"groups":125},"reference","Reference",[119,122],{"title":120,"to":121},"All endpoints","\u002Fapi\u002Freference",{"title":123,"to":124},"Sandbox console","\u002Fapi\u002Fconsole",[126,135,145,166,206,212,230,255,271],{"tag":127,"slug":128,"links":129},"Health","health",[130],{"title":131,"to":132,"method":133,"deprecated":134},"Check that the API is up","\u002Fapi\u002Freference\u002Fget-health","GET",false,{"tag":77,"slug":136,"links":137},"api-account",[138,142],{"title":139,"to":140,"method":141,"deprecated":134},"Revoke the token you send, before it expires","\u002Fapi\u002Freference\u002Frevoke-token","POST",{"title":143,"to":144,"method":133,"deprecated":134},"Fetch the API account your token belongs to","\u002Fapi\u002Freference\u002Fget-current-api-account",{"tag":74,"slug":146,"links":147},"reference-data",[148,151,154,157,160,163],{"title":149,"to":150,"method":133,"deprecated":134},"List the countries a student can be registered in","\u002Fapi\u002Freference\u002Flist-countries",{"title":152,"to":153,"method":133,"deprecated":134},"Fetch one country by its id","\u002Fapi\u002Freference\u002Fget-country",{"title":155,"to":156,"method":133,"deprecated":134},"List the grades a student can be registered with","\u002Fapi\u002Freference\u002Flist-grades",{"title":158,"to":159,"method":133,"deprecated":134},"Fetch one grade by its id","\u002Fapi\u002Freference\u002Fget-grade",{"title":161,"to":162,"method":133,"deprecated":134},"List the organizations and their ids","\u002Fapi\u002Freference\u002Flist-organizations",{"title":164,"to":165,"method":133,"deprecated":134},"Fetch one organization by its id","\u002Fapi\u002Freference\u002Fget-organization",{"tag":62,"slug":167,"links":168},"students",[169,172,175,178,181,184,187,191,194,197,200,203],{"title":170,"to":171,"method":133,"deprecated":134},"List your students","\u002Fapi\u002Freference\u002Flist-students",{"title":173,"to":174,"method":141,"deprecated":134},"Register a student","\u002Fapi\u002Freference\u002Fregister-student",{"title":176,"to":177,"method":141,"deprecated":134},"Check a registration without registering the student","\u002Fapi\u002Freference\u002Fcheck-student-registration",{"title":179,"to":180,"method":141,"deprecated":134},"Register many students at once","\u002Fapi\u002Freference\u002Fcreate-student-import",{"title":182,"to":183,"method":133,"deprecated":134},"Follow a batch of students you sent","\u002Fapi\u002Freference\u002Fget-student-import",{"title":185,"to":186,"method":133,"deprecated":134},"Fetch one of your students","\u002Fapi\u002Freference\u002Fget-student",{"title":188,"to":189,"method":190,"deprecated":134},"Update one of your students","\u002Fapi\u002Freference\u002Fupdate-student","PUT",{"title":192,"to":193,"method":190,"deprecated":134},"Set the sign-in password of one of your students","\u002Fapi\u002Freference\u002Fset-student-password",{"title":195,"to":196,"method":133,"deprecated":134},"List your students who can use this organization","\u002Fapi\u002Freference\u002Flist-org-students",{"title":198,"to":199,"method":133,"deprecated":134},"Fetch one of your students, if they can use this organization","\u002Fapi\u002Freference\u002Fget-org-student",{"title":201,"to":202,"method":190,"deprecated":134},"Update one of your students and give them access to this organization","\u002Fapi\u002Freference\u002Fupdate-org-student",{"title":204,"to":205,"method":190,"deprecated":134},"Link one of your students to a supervisor on this organization","\u002Fapi\u002Freference\u002Flink-student-supervisor",{"tag":80,"slug":207,"links":208},"sign-in-links",[209],{"title":210,"to":211,"method":141,"deprecated":134},"Create a single-use sign-in link for one of your students","\u002Fapi\u002Freference\u002Fcreate-signin-link",{"tag":83,"slug":213,"links":214},"exams",[215,218,221,224,227],{"title":216,"to":217,"method":133,"deprecated":134},"List the exams open for applications","\u002Fapi\u002Freference\u002Flist-exams",{"title":219,"to":220,"method":133,"deprecated":134},"List an organization’s exam categories","\u002Fapi\u002Freference\u002Flist-exam-categories",{"title":222,"to":223,"method":133,"deprecated":134},"Fetch one exam category","\u002Fapi\u002Freference\u002Fget-exam-category",{"title":225,"to":226,"method":133,"deprecated":134},"List the exams one of your students can apply to","\u002Fapi\u002Freference\u002Flist-available-exams",{"title":228,"to":229,"method":133,"deprecated":134},"Fetch one exam that is open for applications","\u002Fapi\u002Freference\u002Fget-exam",{"tag":86,"slug":231,"links":232},"applications",[233,236,239,242,245,248,251],{"title":234,"to":235,"method":133,"deprecated":134},"List your students’ applications in this organization","\u002Fapi\u002Freference\u002Flist-applications",{"title":237,"to":238,"method":141,"deprecated":134},"Enter one of your students for an exam","\u002Fapi\u002Freference\u002Fcreate-application",{"title":240,"to":241,"method":133,"deprecated":134},"List your students’ applications for one exam","\u002Fapi\u002Freference\u002Flist-exam-applications",{"title":243,"to":244,"method":133,"deprecated":134},"List one of your students’ applications in this organization","\u002Fapi\u002Freference\u002Flist-student-applications",{"title":246,"to":247,"method":133,"deprecated":134},"Fetch one of your students’ applications","\u002Fapi\u002Freference\u002Fget-application",{"title":249,"to":250,"method":190,"deprecated":134},"Move one of your students’ applications to another exam","\u002Fapi\u002Freference\u002Fmove-application",{"title":252,"to":253,"method":254,"deprecated":134},"Withdraw one of your students from an exam","\u002Fapi\u002Freference\u002Fdelete-application","DELETE",{"tag":256,"slug":257,"links":258},"Documents","documents",[259,262,265,268],{"title":260,"to":261,"method":133,"deprecated":134},"Download a certificate file","\u002Fapi\u002Freference\u002Fdownload-certificate",{"title":263,"to":264,"method":133,"deprecated":134},"List one of your students’ released certificates","\u002Fapi\u002Freference\u002Flist-student-certificates",{"title":266,"to":267,"method":133,"deprecated":134},"Download a result report file","\u002Fapi\u002Freference\u002Fdownload-report",{"title":269,"to":270,"method":133,"deprecated":134},"List one of your students’ released result reports","\u002Fapi\u002Freference\u002Flist-student-reports",{"tag":89,"slug":272,"links":273},"group-challenges",[274,277,280,283,286,289,292,295,298],{"title":275,"to":276,"method":133,"deprecated":134},"List the group challenges an organization runs","\u002Fapi\u002Freference\u002Flist-group-challenges",{"title":278,"to":279,"method":133,"deprecated":134},"Fetch one group challenge","\u002Fapi\u002Freference\u002Fget-group-challenge",{"title":281,"to":282,"method":133,"deprecated":134},"List the groups your students are in for a group challenge","\u002Fapi\u002Freference\u002Flist-group-challenge-groups",{"title":284,"to":285,"method":133,"deprecated":134},"Fetch one group, with its steps and files","\u002Fapi\u002Freference\u002Fget-group-challenge-group",{"title":287,"to":288,"method":133,"deprecated":134},"List what has happened in one group","\u002Fapi\u002Freference\u002Flist-group-challenge-activity",{"title":290,"to":291,"method":141,"deprecated":134},"Send a group’s finished work for one of your students","\u002Fapi\u002Freference\u002Fsubmit-group-challenge-work",{"title":293,"to":294,"method":141,"deprecated":134},"Submit one step of a group for one of your students","\u002Fapi\u002Freference\u002Fsubmit-group-challenge-step",{"title":296,"to":297,"method":133,"deprecated":134},"List your students’ eligibility and groups for a group challenge","\u002Fapi\u002Freference\u002Flist-group-challenge-students",{"title":299,"to":300,"method":133,"deprecated":134},"Fetch one of your students’ eligibility and group for a group challenge","\u002Fapi\u002Freference\u002Fget-group-challenge-student",{"id":302,"title":303,"links":304,"groups":316},"clients","Clients",[305,307,310,313],{"title":9,"to":306,"status":14},"\u002Fapi\u002Fclients",{"title":308,"to":309,"status":14},"Node.js","\u002Fapi\u002Fclients\u002Fnode",{"title":311,"to":312,"status":14},"PHP","\u002Fapi\u002Fclients\u002Fphp",{"title":314,"to":315,"status":14},"Build your own","\u002Fapi\u002Fclients\u002Fbuild-your-own",[],{"id":318,"title":319,"links":320,"groups":330},"agents","AI agents",[321,324,327],{"title":322,"to":323},"AI connections","\u002Fapi\u002Fmcp",{"title":325,"to":326},"What it can do","\u002Fapi\u002Fmcp\u002Ftools",{"title":328,"to":329},"Agent skills","\u002Fapi\u002Fskills",[],{"id":332,"title":333,"links":334,"groups":350},"help","Help",[335,338,341,344,347],{"title":336,"to":337,"status":14},"Glossary","\u002Fapi\u002Fglossary",{"title":339,"to":340,"status":14},"FAQ","\u002Fapi\u002Ffaq",{"title":342,"to":343,"status":14},"Troubleshooting","\u002Fapi\u002Ftroubleshooting",{"title":345,"to":346,"status":14},"Support","\u002Fapi\u002Fsupport",{"title":348,"to":349},"Changelog","\u002Fapi\u002Fchangelog",[],{"id":352,"title":342,"body":353,"description":3608,"extension":3609,"meta":3610,"navTitle":342,"navigation":1038,"operations":3611,"order":3621,"path":343,"section":332,"seo":3622,"status":14,"stem":3623,"__hash__":3624},"apiGuides\u002Fapi\u002Ftroubleshooting.md",{"type":354,"value":355,"toc":3567},"minimark",[356,366,371,374,468,501,504,508,511,666,669,681,685,692,850,853,1291,1294,1765,1778,1788,1792,1797,1800,1923,1932,1936,2006,2010,2015,2183,2190,2194,2206,2226,2238,2242,2246,2249,2308,2330,2334,2339,2343,2354,2358,2368,2384,2388,2531,2535,2538,2637,2646,2650,2656,2660,2665,2669,2715,2723,2728,2735,2739,2742,2818,2821,2873,2877,2883,2887,2913,2917,2920,2965,2970,2974,3024,3029,3033,3036,3040,3043,3063,3073,3077,3091,3095,3098,3131,3147,3151,3154,3182,3186,3189,3241,3250,3254,3350,3362,3366,3382,3401,3406,3410,3416,3507,3510,3540,3547,3563],[357,358,359,360,365],"p",{},"Start with the status code, then find the error code and message below. Each section lists the likely causes in order, most common first, with the fix for each. If you are stuck at the end, the last section says ",[361,362,364],"a",{"href":363},"#what-to-send-support","what to send support",".",[367,368,370],"h2",{"id":369},"read-the-error-first","Read the error first",[357,372,373],{},"Every error has the same shape. Here is a real one, from a request that tried to set a password:",[375,376,381],"pre",{"className":377,"code":378,"language":379,"meta":380,"style":380},"language-json shiki shiki-themes github-light-high-contrast github-dark-high-contrast","{\n  \"error\": {\n    \"code\": \"conflict\",\n    \"message\": \"This student has confirmed their email address, so the password is theirs to change. Send them a sign-in link with POST \u002Fv1\u002F:organizationId\u002Fauth\u002Fsignin.\",\n    \"documentation_url\": \"https:\u002F\u002Fhub.main-team.org\u002Fapi\u002Ferrors#conflict\",\n    \"request_id\": \"7c1e9a52-3f0b-4d8e-9a61-2b5d0c4e8f13\"\n  }\n}\n","json","",[382,383,384,393,403,419,432,445,456,462],"code",{"__ignoreMap":380},[385,386,389],"span",{"class":387,"line":388},"line",1,[385,390,392],{"class":391},"suds8","{\n",[385,394,396,400],{"class":387,"line":395},2,[385,397,399],{"class":398},"sne4z","  \"error\"",[385,401,402],{"class":391},": {\n",[385,404,406,409,412,416],{"class":387,"line":405},3,[385,407,408],{"class":398},"    \"code\"",[385,410,411],{"class":391},": ",[385,413,415],{"class":414},"sT6z2","\"conflict\"",[385,417,418],{"class":391},",\n",[385,420,422,425,427,430],{"class":387,"line":421},4,[385,423,424],{"class":398},"    \"message\"",[385,426,411],{"class":391},[385,428,429],{"class":414},"\"This student has confirmed their email address, so the password is theirs to change. Send them a sign-in link with POST \u002Fv1\u002F:organizationId\u002Fauth\u002Fsignin.\"",[385,431,418],{"class":391},[385,433,435,438,440,443],{"class":387,"line":434},5,[385,436,437],{"class":398},"    \"documentation_url\"",[385,439,411],{"class":391},[385,441,442],{"class":414},"\"https:\u002F\u002Fhub.main-team.org\u002Fapi\u002Ferrors#conflict\"",[385,444,418],{"class":391},[385,446,448,451,453],{"class":387,"line":447},6,[385,449,450],{"class":398},"    \"request_id\"",[385,452,411],{"class":391},[385,454,455],{"class":414},"\"7c1e9a52-3f0b-4d8e-9a61-2b5d0c4e8f13\"\n",[385,457,459],{"class":387,"line":458},7,[385,460,461],{"class":391},"  }\n",[385,463,465],{"class":387,"line":464},8,[385,466,467],{"class":391},"}\n",[469,470,471,481,489],"ul",{},[472,473,474,480],"li",{},[475,476,477,478],"strong",{},"The HTTP status and ",[382,479,382],{}," say what kind of failure this is. Branch your code on these two, never on the message text, because messages can be reworded.",[472,482,483,488],{},[475,484,485],{},[382,486,487],{},"message"," is written for a person. It often names the rule and the fix. The tables below quote messages exactly, so you can search this page for yours.",[472,490,491,496,497,500],{},[475,492,493],{},[382,494,495],{},"request_id"," identifies this one request. It also comes back in the ",[382,498,499],{},"X-Request-Id"," header of every response, successful or not. Log it with the error. Support needs it to find the request.",[357,502,503],{},"The two file downloads are the only operations that do not answer JSON when they succeed. When they fail, they answer with this same JSON error.",[367,505,507],{"id":506},"the-order-the-api-checks-a-request","The order the API checks a request",[357,509,510],{},"The API checks a request in a fixed order and answers with the first problem it finds. This explains why fixing one error can reveal another.",[512,513,514,530],"table",{},[515,516,517],"thead",{},[518,519,520,524,527],"tr",{},[521,522,523],"th",{},"Step",[521,525,526],{},"What is checked",[521,528,529],{},"Refusal",[531,532,533,556,569,582,601,617,630,642],"tbody",{},[518,534,535,539,542],{},[536,537,538],"td",{},"1",[536,540,541],{},"The request body can be read",[536,543,544,547,548,551,552,555],{},[382,545,546],{},"413 payload_too_large",", ",[382,549,550],{},"415 unsupported_media_type",", or ",[382,553,554],{},"400 bad_request"," for malformed JSON",[518,557,558,561,564],{},[536,559,560],{},"2",[536,562,563],{},"The path exists",[536,565,566],{},[382,567,568],{},"404 not_found",[518,570,571,574,577],{},[536,572,573],{},"3",[536,575,576],{},"The token",[536,578,579],{},[382,580,581],{},"401 unauthorized",[518,583,584,587,594],{},[536,585,586],{},"4",[536,588,589,590,593],{},"The ",[382,591,592],{},"{organizationId}"," in the path, if there is one",[536,595,596,547,598],{},[382,597,568],{},[382,599,600],{},"Organization not found!",[518,602,603,606,609],{},[536,604,605],{},"5",[536,607,608],{},"Your roles grant the operation",[536,610,611,547,614],{},[382,612,613],{},"403 forbidden",[382,615,616],{},"Insufficient role permissions",[518,618,619,622,625],{},[536,620,621],{},"6",[536,623,624],{},"The rate limit",[536,626,627],{},[382,628,629],{},"429 too_many_requests",[518,631,632,635,638],{},[536,633,634],{},"7",[536,636,637],{},"The body's fields",[536,639,640],{},[382,641,554],{},[518,643,644,647,650],{},[536,645,646],{},"8",[536,648,649],{},"The operation's own rules: the ids in the path, ownership, open exams, payments",[536,651,652,547,655,547,658,661,662,665],{},[382,653,654],{},"400",[382,656,657],{},"403",[382,659,660],{},"404"," or ",[382,663,664],{},"409",", with a specific message",[357,667,668],{},"Consequences:",[469,670,671,678],{},[472,672,673,674,677],{},"A request without a valid token gets ",[382,675,676],{},"401"," whatever organization id it names, so the API never reveals which organizations exist to someone without a token.",[472,679,680],{},"A request refused at steps 1 to 5 does not count toward your rate limit. A request refused at step 7 or 8 does.",[367,682,684],{"id":683},"status-401-unauthorized","Status 401: unauthorized",[357,686,687,688,691],{},"The message is always ",[382,689,690],{},"Authentication is required or the provided credentials are invalid.",", whatever the reason. Work through these causes in order.",[693,694,695,716,747,764,785,802,818,835,841],"ol",{},[472,696,697,700,701,704,705,708,709,547,712,715],{},[475,698,699],{},"The header."," It must be exactly ",[382,702,703],{},"Authorization: Bearer \u003Ctoken>",": a capital ",[382,706,707],{},"B",", one space, then the token, with no quotes and no line break. ",[382,710,711],{},"bearer",[382,713,714],{},"Token"," and a doubled space are all refused.",[472,717,718,724,725,727,728,731,732,735,736,738,739,742,743,746],{},[475,719,720,723],{},[382,721,722],{},"kid"," is missing or wrong."," The token header must carry ",[382,726,722],{}," with your ",[382,729,730],{},"apiKey"," exactly as issued: ",[382,733,734],{},"key_"," followed by 24 characters. Many libraries add ",[382,737,722],{}," only when asked. In ",[382,740,741],{},"jsonwebtoken",", use the ",[382,744,745],{},"keyid"," option.",[472,748,749,757,758,760,761,763],{},[475,750,751,754,755,365],{},[382,752,753],{},"sub"," does not equal ",[382,756,722],{}," The payload's ",[382,759,753],{}," must be your ",[382,762,730],{}," too.",[472,765,766,775,776,738,778,781,782,365],{},[475,767,768,661,771,774],{},[382,769,770],{},"iat",[382,772,773],{},"exp"," is missing."," Both are required, as whole seconds since the Unix epoch, not milliseconds. Some libraries set ",[382,777,770],{},[382,779,780],{},"jose",", call ",[382,783,784],{},".setIssuedAt()",[472,786,787,790,791,794,795,661,798,801],{},[475,788,789],{},"The lifetime is too long."," ",[382,792,793],{},"exp - iat"," may be at most 3600. ",[382,796,797],{},"expiresIn: '2h'",[382,799,800],{},"'1d'"," produces a token that is refused, even though it has not expired.",[472,803,804,807,808,810,811,813,814,817],{},[475,805,806],{},"Your clock is wrong."," An ",[382,809,770],{}," more than 30 seconds in the future is refused. So is a token more than 30 seconds past its ",[382,812,773],{},". Check the server with ",[382,815,816],{},"date -u"," and keep it synchronized with NTP.",[472,819,820,823,824,827,828,831,832,834],{},[475,821,822],{},"The signature."," The token must be signed with HS256, using the whole ",[382,825,826],{},"apiSecret"," string, including its ",[382,829,830],{},"secret_"," prefix, as the key. Look for secrets read from a file or environment variable with a trailing newline or surrounding quotes, and for tokens signed with the ",[382,833,730],{}," by mistake.",[472,836,837,840],{},[475,838,839],{},"The token was revoked",", or it simply expired while a long job was running. Sign a new one.",[472,842,843,846,847,849],{},[475,844,845],{},"The account is inactive, or was just created or changed."," A deactivated account's tokens stop working within a minute. A brand-new or reactivated account can take up to a minute to start working. If you get ",[382,848,676],{}," right after the operator says it is ready, wait a minute and try again.",[357,851,852],{},"This Node.js script checks a token against rules 2 to 6 without calling the API:",[375,854,858],{"className":855,"code":856,"language":857,"meta":380,"style":380},"language-js shiki shiki-themes github-light-high-contrast github-dark-high-contrast","\u002F\u002F check-token.js — usage: node check-token.js \"$TOKEN\"\nconst token = process.argv[2];\nconst [header, payload] = token\n  .split('.')\n  .slice(0, 2)\n  .map((part) => JSON.parse(Buffer.from(part, 'base64url').toString('utf8')));\nconst now = Math.floor(Date.now() \u002F 1000);\n\nconst checks = {\n  'alg is HS256': header.alg === 'HS256',\n  'kid looks like an apiKey': \u002F^key_[A-Za-z0-9_-]{24}$\u002F.test(header.kid ?? ''),\n  'sub equals kid': payload.sub === header.kid,\n  'iat and exp are whole seconds': Number.isInteger(payload.iat) && Number.isInteger(payload.exp),\n  'exp is after iat': payload.exp > payload.iat,\n  'lifetime is at most 3600 s': payload.exp - payload.iat \u003C= 3600,\n  'iat is not more than 30 s ahead': payload.iat - now \u003C= 30,\n  'not expired (30 s tolerance)': payload.exp + 30 > now,\n};\nfor (const [rule, ok] of Object.entries(checks)) console.log(ok ? 'ok  ' : 'FAIL', rule);\n","js",[382,859,860,866,887,911,929,947,1001,1034,1040,1053,1070,1112,1126,1152,1167,1189,1210,1229,1235],{"__ignoreMap":380},[385,861,862],{"class":387,"line":388},[385,863,865],{"class":864},"sLBg1","\u002F\u002F check-token.js — usage: node check-token.js \"$TOKEN\"\n",[385,867,868,872,876,879,882,884],{"class":387,"line":395},[385,869,871],{"class":870},"sHUrx","const",[385,873,875],{"class":874},"s-5SL"," token",[385,877,878],{"class":870}," =",[385,880,881],{"class":391}," process.argv[",[385,883,560],{"class":874},[385,885,886],{"class":391},"];\n",[385,888,889,891,894,897,899,902,905,908],{"class":387,"line":405},[385,890,871],{"class":870},[385,892,893],{"class":391}," [",[385,895,896],{"class":874},"header",[385,898,547],{"class":391},[385,900,901],{"class":874},"payload",[385,903,904],{"class":391},"] ",[385,906,907],{"class":870},"=",[385,909,910],{"class":391}," token\n",[385,912,913,916,920,923,926],{"class":387,"line":421},[385,914,915],{"class":391},"  .",[385,917,919],{"class":918},"sKwhi","split",[385,921,922],{"class":391},"(",[385,924,925],{"class":414},"'.'",[385,927,928],{"class":391},")\n",[385,930,931,933,936,938,941,943,945],{"class":387,"line":434},[385,932,915],{"class":391},[385,934,935],{"class":918},"slice",[385,937,922],{"class":391},[385,939,940],{"class":874},"0",[385,942,547],{"class":391},[385,944,560],{"class":874},[385,946,928],{"class":391},[385,948,949,951,954,957,961,964,967,970,972,975,978,981,984,987,990,993,995,998],{"class":387,"line":447},[385,950,915],{"class":391},[385,952,953],{"class":918},"map",[385,955,956],{"class":391},"((",[385,958,960],{"class":959},"soyes","part",[385,962,963],{"class":391},") ",[385,965,966],{"class":870},"=>",[385,968,969],{"class":874}," JSON",[385,971,365],{"class":391},[385,973,974],{"class":918},"parse",[385,976,977],{"class":391},"(Buffer.",[385,979,980],{"class":918},"from",[385,982,983],{"class":391},"(part, ",[385,985,986],{"class":414},"'base64url'",[385,988,989],{"class":391},").",[385,991,992],{"class":918},"toString",[385,994,922],{"class":391},[385,996,997],{"class":414},"'utf8'",[385,999,1000],{"class":391},")));\n",[385,1002,1003,1005,1008,1010,1013,1016,1019,1022,1025,1028,1031],{"class":387,"line":458},[385,1004,871],{"class":870},[385,1006,1007],{"class":874}," now",[385,1009,878],{"class":870},[385,1011,1012],{"class":391}," Math.",[385,1014,1015],{"class":918},"floor",[385,1017,1018],{"class":391},"(Date.",[385,1020,1021],{"class":918},"now",[385,1023,1024],{"class":391},"() ",[385,1026,1027],{"class":870},"\u002F",[385,1029,1030],{"class":874}," 1000",[385,1032,1033],{"class":391},");\n",[385,1035,1036],{"class":387,"line":464},[385,1037,1039],{"emptyLinePlaceholder":1038},true,"\n",[385,1041,1043,1045,1048,1050],{"class":387,"line":1042},9,[385,1044,871],{"class":870},[385,1046,1047],{"class":874}," checks",[385,1049,878],{"class":870},[385,1051,1052],{"class":391}," {\n",[385,1054,1056,1059,1062,1065,1068],{"class":387,"line":1055},10,[385,1057,1058],{"class":414},"  'alg is HS256'",[385,1060,1061],{"class":391},": header.alg ",[385,1063,1064],{"class":870},"===",[385,1066,1067],{"class":414}," 'HS256'",[385,1069,418],{"class":391},[385,1071,1073,1076,1079,1082,1085,1087,1090,1093,1095,1097,1100,1103,1106,1109],{"class":387,"line":1072},11,[385,1074,1075],{"class":414},"  'kid looks like an apiKey'",[385,1077,1078],{"class":391},":",[385,1080,1081],{"class":414}," \u002F",[385,1083,1084],{"class":870},"^",[385,1086,734],{"class":414},[385,1088,1089],{"class":874},"[A-Za-z0-9_-]",[385,1091,1092],{"class":870},"{24}$",[385,1094,1027],{"class":414},[385,1096,365],{"class":391},[385,1098,1099],{"class":918},"test",[385,1101,1102],{"class":391},"(header.kid ",[385,1104,1105],{"class":870},"??",[385,1107,1108],{"class":414}," ''",[385,1110,1111],{"class":391},"),\n",[385,1113,1115,1118,1121,1123],{"class":387,"line":1114},12,[385,1116,1117],{"class":414},"  'sub equals kid'",[385,1119,1120],{"class":391},": payload.sub ",[385,1122,1064],{"class":870},[385,1124,1125],{"class":391}," header.kid,\n",[385,1127,1129,1132,1135,1138,1141,1144,1147,1149],{"class":387,"line":1128},13,[385,1130,1131],{"class":414},"  'iat and exp are whole seconds'",[385,1133,1134],{"class":391},": Number.",[385,1136,1137],{"class":918},"isInteger",[385,1139,1140],{"class":391},"(payload.iat) ",[385,1142,1143],{"class":870},"&&",[385,1145,1146],{"class":391}," Number.",[385,1148,1137],{"class":918},[385,1150,1151],{"class":391},"(payload.exp),\n",[385,1153,1155,1158,1161,1164],{"class":387,"line":1154},14,[385,1156,1157],{"class":414},"  'exp is after iat'",[385,1159,1160],{"class":391},": payload.exp ",[385,1162,1163],{"class":870},">",[385,1165,1166],{"class":391}," payload.iat,\n",[385,1168,1170,1173,1175,1178,1181,1184,1187],{"class":387,"line":1169},15,[385,1171,1172],{"class":414},"  'lifetime is at most 3600 s'",[385,1174,1160],{"class":391},[385,1176,1177],{"class":870},"-",[385,1179,1180],{"class":391}," payload.iat ",[385,1182,1183],{"class":870},"\u003C=",[385,1185,1186],{"class":874}," 3600",[385,1188,418],{"class":391},[385,1190,1192,1195,1198,1200,1203,1205,1208],{"class":387,"line":1191},16,[385,1193,1194],{"class":414},"  'iat is not more than 30 s ahead'",[385,1196,1197],{"class":391},": payload.iat ",[385,1199,1177],{"class":870},[385,1201,1202],{"class":391}," now ",[385,1204,1183],{"class":870},[385,1206,1207],{"class":874}," 30",[385,1209,418],{"class":391},[385,1211,1213,1216,1218,1221,1223,1226],{"class":387,"line":1212},17,[385,1214,1215],{"class":414},"  'not expired (30 s tolerance)'",[385,1217,1160],{"class":391},[385,1219,1220],{"class":870},"+",[385,1222,1207],{"class":874},[385,1224,1225],{"class":870}," >",[385,1227,1228],{"class":391}," now,\n",[385,1230,1232],{"class":387,"line":1231},18,[385,1233,1234],{"class":391},"};\n",[385,1236,1238,1241,1244,1246,1248,1251,1253,1256,1258,1261,1264,1267,1270,1273,1276,1279,1282,1285,1288],{"class":387,"line":1237},19,[385,1239,1240],{"class":870},"for",[385,1242,1243],{"class":391}," (",[385,1245,871],{"class":870},[385,1247,893],{"class":391},[385,1249,1250],{"class":874},"rule",[385,1252,547],{"class":391},[385,1254,1255],{"class":874},"ok",[385,1257,904],{"class":391},[385,1259,1260],{"class":870},"of",[385,1262,1263],{"class":391}," Object.",[385,1265,1266],{"class":918},"entries",[385,1268,1269],{"class":391},"(checks)) console.",[385,1271,1272],{"class":918},"log",[385,1274,1275],{"class":391},"(ok ",[385,1277,1278],{"class":870},"?",[385,1280,1281],{"class":414}," 'ok  '",[385,1283,1284],{"class":870}," :",[385,1286,1287],{"class":414}," 'FAIL'",[385,1289,1290],{"class":391},", rule);\n",[357,1292,1293],{},"The same checks in PHP:",[375,1295,1299],{"className":1296,"code":1297,"language":1298,"meta":380,"style":380},"language-php shiki shiki-themes github-light-high-contrast github-dark-high-contrast","\u003C?php\n\u002F\u002F check-token.php — usage: php check-token.php \"$TOKEN\"\n[$h, $p] = array_map(\n    fn (string $part) => json_decode(base64_decode(strtr($part, '-_', '+\u002F')), true),\n    array_slice(explode('.', $argv[1]), 0, 2)\n);\n$now = time();\n$checks = [\n    'alg is HS256' => ($h['alg'] ?? null) === 'HS256',\n    'kid looks like an apiKey' => (bool) preg_match('\u002F^key_[A-Za-z0-9_-]{24}$\u002F', $h['kid'] ?? ''),\n    'sub equals kid' => ($p['sub'] ?? null) === ($h['kid'] ?? null),\n    'iat and exp are whole seconds' => is_int($p['iat'] ?? null) && is_int($p['exp'] ?? null),\n    'exp is after iat' => ($p['exp'] ?? 0) > ($p['iat'] ?? 0),\n    'lifetime is at most 3600 s' => ($p['exp'] ?? 0) - ($p['iat'] ?? 0) \u003C= 3600,\n    'iat is not more than 30 s ahead' => ($p['iat'] ?? 0) - $now \u003C= 30,\n    'not expired (30 s tolerance)' => ($p['exp'] ?? 0) + 30 > $now,\n];\nforeach ($checks as $rule => $ok) echo ($ok ? 'ok   ' : 'FAIL ') . $rule . PHP_EOL;\n","php",[382,1300,1301,1309,1314,1327,1372,1402,1406,1419,1429,1458,1505,1540,1581,1615,1654,1684,1712,1716],{"__ignoreMap":380},[385,1302,1303,1306],{"class":387,"line":388},[385,1304,1305],{"class":870},"\u003C?",[385,1307,1308],{"class":874},"php\n",[385,1310,1311],{"class":387,"line":395},[385,1312,1313],{"class":864},"\u002F\u002F check-token.php — usage: php check-token.php \"$TOKEN\"\n",[385,1315,1316,1319,1321,1324],{"class":387,"line":405},[385,1317,1318],{"class":391},"[$h, $p] ",[385,1320,907],{"class":870},[385,1322,1323],{"class":874}," array_map",[385,1325,1326],{"class":391},"(\n",[385,1328,1329,1332,1334,1337,1340,1343,1345,1348,1350,1353,1356,1359,1361,1364,1367,1370],{"class":387,"line":421},[385,1330,1331],{"class":870},"    fn",[385,1333,1243],{"class":391},[385,1335,1336],{"class":870},"string",[385,1338,1339],{"class":391}," $part) => ",[385,1341,1342],{"class":874},"json_decode",[385,1344,922],{"class":391},[385,1346,1347],{"class":874},"base64_decode",[385,1349,922],{"class":391},[385,1351,1352],{"class":874},"strtr",[385,1354,1355],{"class":391},"($part, ",[385,1357,1358],{"class":414},"'-_'",[385,1360,547],{"class":391},[385,1362,1363],{"class":414},"'+\u002F'",[385,1365,1366],{"class":391},")), ",[385,1368,1369],{"class":874},"true",[385,1371,1111],{"class":391},[385,1373,1374,1377,1379,1382,1384,1386,1389,1391,1394,1396,1398,1400],{"class":387,"line":434},[385,1375,1376],{"class":874},"    array_slice",[385,1378,922],{"class":391},[385,1380,1381],{"class":874},"explode",[385,1383,922],{"class":391},[385,1385,925],{"class":414},[385,1387,1388],{"class":391},", $argv[",[385,1390,538],{"class":874},[385,1392,1393],{"class":391},"]), ",[385,1395,940],{"class":874},[385,1397,547],{"class":391},[385,1399,560],{"class":874},[385,1401,928],{"class":391},[385,1403,1404],{"class":387,"line":447},[385,1405,1033],{"class":391},[385,1407,1408,1411,1413,1416],{"class":387,"line":458},[385,1409,1410],{"class":391},"$now ",[385,1412,907],{"class":870},[385,1414,1415],{"class":874}," time",[385,1417,1418],{"class":391},"();\n",[385,1420,1421,1424,1426],{"class":387,"line":464},[385,1422,1423],{"class":391},"$checks ",[385,1425,907],{"class":870},[385,1427,1428],{"class":391}," [\n",[385,1430,1431,1434,1437,1440,1443,1445,1447,1450,1452,1454,1456],{"class":387,"line":1042},[385,1432,1433],{"class":414},"    'alg is HS256'",[385,1435,1436],{"class":870}," =>",[385,1438,1439],{"class":391}," ($h[",[385,1441,1442],{"class":414},"'alg'",[385,1444,904],{"class":391},[385,1446,1105],{"class":870},[385,1448,1449],{"class":874}," null",[385,1451,963],{"class":391},[385,1453,1064],{"class":870},[385,1455,1067],{"class":414},[385,1457,418],{"class":391},[385,1459,1460,1463,1465,1467,1470,1472,1475,1477,1480,1482,1485,1488,1491,1494,1497,1499,1501,1503],{"class":387,"line":1055},[385,1461,1462],{"class":414},"    'kid looks like an apiKey'",[385,1464,1436],{"class":870},[385,1466,1243],{"class":391},[385,1468,1469],{"class":870},"bool",[385,1471,963],{"class":391},[385,1473,1474],{"class":874},"preg_match",[385,1476,922],{"class":391},[385,1478,1479],{"class":414},"'\u002F",[385,1481,1084],{"class":870},[385,1483,1484],{"class":414},"key_[A-Za-z0-9_-]{24}",[385,1486,1487],{"class":870},"$",[385,1489,1490],{"class":414},"\u002F'",[385,1492,1493],{"class":391},", $h[",[385,1495,1496],{"class":414},"'kid'",[385,1498,904],{"class":391},[385,1500,1105],{"class":870},[385,1502,1108],{"class":414},[385,1504,1111],{"class":391},[385,1506,1507,1510,1512,1515,1518,1520,1522,1524,1526,1528,1530,1532,1534,1536,1538],{"class":387,"line":1072},[385,1508,1509],{"class":414},"    'sub equals kid'",[385,1511,1436],{"class":870},[385,1513,1514],{"class":391}," ($p[",[385,1516,1517],{"class":414},"'sub'",[385,1519,904],{"class":391},[385,1521,1105],{"class":870},[385,1523,1449],{"class":874},[385,1525,963],{"class":391},[385,1527,1064],{"class":870},[385,1529,1439],{"class":391},[385,1531,1496],{"class":414},[385,1533,904],{"class":391},[385,1535,1105],{"class":870},[385,1537,1449],{"class":874},[385,1539,1111],{"class":391},[385,1541,1542,1545,1547,1550,1553,1556,1558,1560,1562,1564,1566,1568,1570,1573,1575,1577,1579],{"class":387,"line":1114},[385,1543,1544],{"class":414},"    'iat and exp are whole seconds'",[385,1546,1436],{"class":870},[385,1548,1549],{"class":874}," is_int",[385,1551,1552],{"class":391},"($p[",[385,1554,1555],{"class":414},"'iat'",[385,1557,904],{"class":391},[385,1559,1105],{"class":870},[385,1561,1449],{"class":874},[385,1563,963],{"class":391},[385,1565,1143],{"class":870},[385,1567,1549],{"class":874},[385,1569,1552],{"class":391},[385,1571,1572],{"class":414},"'exp'",[385,1574,904],{"class":391},[385,1576,1105],{"class":870},[385,1578,1449],{"class":874},[385,1580,1111],{"class":391},[385,1582,1583,1586,1588,1590,1592,1594,1596,1599,1601,1603,1605,1607,1609,1611,1613],{"class":387,"line":1128},[385,1584,1585],{"class":414},"    'exp is after iat'",[385,1587,1436],{"class":870},[385,1589,1514],{"class":391},[385,1591,1572],{"class":414},[385,1593,904],{"class":391},[385,1595,1105],{"class":870},[385,1597,1598],{"class":874}," 0",[385,1600,963],{"class":391},[385,1602,1163],{"class":870},[385,1604,1514],{"class":391},[385,1606,1555],{"class":414},[385,1608,904],{"class":391},[385,1610,1105],{"class":870},[385,1612,1598],{"class":874},[385,1614,1111],{"class":391},[385,1616,1617,1620,1622,1624,1626,1628,1630,1632,1634,1636,1638,1640,1642,1644,1646,1648,1650,1652],{"class":387,"line":1154},[385,1618,1619],{"class":414},"    'lifetime is at most 3600 s'",[385,1621,1436],{"class":870},[385,1623,1514],{"class":391},[385,1625,1572],{"class":414},[385,1627,904],{"class":391},[385,1629,1105],{"class":870},[385,1631,1598],{"class":874},[385,1633,963],{"class":391},[385,1635,1177],{"class":870},[385,1637,1514],{"class":391},[385,1639,1555],{"class":414},[385,1641,904],{"class":391},[385,1643,1105],{"class":870},[385,1645,1598],{"class":874},[385,1647,963],{"class":391},[385,1649,1183],{"class":870},[385,1651,1186],{"class":874},[385,1653,418],{"class":391},[385,1655,1656,1659,1661,1663,1665,1667,1669,1671,1673,1675,1678,1680,1682],{"class":387,"line":1169},[385,1657,1658],{"class":414},"    'iat is not more than 30 s ahead'",[385,1660,1436],{"class":870},[385,1662,1514],{"class":391},[385,1664,1555],{"class":414},[385,1666,904],{"class":391},[385,1668,1105],{"class":870},[385,1670,1598],{"class":874},[385,1672,963],{"class":391},[385,1674,1177],{"class":870},[385,1676,1677],{"class":391}," $now ",[385,1679,1183],{"class":870},[385,1681,1207],{"class":874},[385,1683,418],{"class":391},[385,1685,1686,1689,1691,1693,1695,1697,1699,1701,1703,1705,1707,1709],{"class":387,"line":1191},[385,1687,1688],{"class":414},"    'not expired (30 s tolerance)'",[385,1690,1436],{"class":870},[385,1692,1514],{"class":391},[385,1694,1572],{"class":414},[385,1696,904],{"class":391},[385,1698,1105],{"class":870},[385,1700,1598],{"class":874},[385,1702,963],{"class":391},[385,1704,1220],{"class":870},[385,1706,1207],{"class":874},[385,1708,1225],{"class":870},[385,1710,1711],{"class":391}," $now,\n",[385,1713,1714],{"class":387,"line":1212},[385,1715,886],{"class":391},[385,1717,1718,1721,1724,1727,1730,1732,1735,1738,1741,1743,1746,1748,1751,1753,1755,1757,1759,1762],{"class":387,"line":1231},[385,1719,1720],{"class":870},"foreach",[385,1722,1723],{"class":391}," ($checks ",[385,1725,1726],{"class":870},"as",[385,1728,1729],{"class":391}," $rule ",[385,1731,966],{"class":870},[385,1733,1734],{"class":391}," $ok) ",[385,1736,1737],{"class":874},"echo",[385,1739,1740],{"class":391}," ($ok ",[385,1742,1278],{"class":870},[385,1744,1745],{"class":414}," 'ok   '",[385,1747,1284],{"class":870},[385,1749,1750],{"class":414}," 'FAIL '",[385,1752,963],{"class":391},[385,1754,365],{"class":870},[385,1756,1729],{"class":391},[385,1758,365],{"class":870},[385,1760,1761],{"class":874}," PHP_EOL",[385,1763,1764],{"class":391},";\n",[357,1766,1767,1768,1770,1771,1773,1774,1777],{},"If every check passes and you still get ",[382,1769,676],{},", the likely cause is the signature (rule 7) or the account (rules 8 and 9). Send the ",[382,1772,495],{}," to ",[361,1775,1776],{"href":363},"support",". We can see which check failed. Never send the token itself.",[1779,1780,1782],"callout",{"type":1781},"security",[357,1783,1784,1785,1787],{},"Never paste a token or your ",[382,1786,826],{}," into an online JWT debugger. A token is a working credential until it expires, and the secret signs new ones.",[367,1789,1791],{"id":1790},"status-403-forbidden","Status 403: forbidden",[1793,1794,1796],"h3",{"id":1795},"insufficient-role-permissions","\"Insufficient role permissions\"",[357,1798,1799],{},"Your token is valid, but none of your roles grants this operation on this organization. Retrying or signing a new token will not help.",[693,1801,1802,1821,1855,1878,1892,1905,1917],{},[472,1803,1804,1807,1808,1811,1812,1817,1818,365],{},[475,1805,1806],{},"Find the permission."," Each operation's reference page names the permission it needs, for example ",[382,1809,1810],{},"application\u002Fcreate",". Compare it with your roles. ",[361,1813,1814],{"href":144},[382,1815,1816],{},"GET \u002Fv1\u002Fapi-account\u002Fvalidate-me"," returns them, provided you hold ",[382,1819,1820],{},"api\u002F*",[472,1822,1823,1826,1827,1829,1830,1833,1834,547,1837,547,1840,547,1843,547,1846,1849,1850,661,1853,365],{},[475,1824,1825],{},"Check the target."," An operation with ",[382,1828,592],{}," in its path needs a role whose target is that organization's slug, or ",[382,1831,1832],{},"*",". An operation without one (",[382,1835,1836],{},"\u002Fv1\u002Fstudent",[382,1838,1839],{},"\u002Fv1\u002Fcountry",[382,1841,1842],{},"\u002Fv1\u002Fgrade",[382,1844,1845],{},"\u002Fv1\u002Forganization",[382,1847,1848],{},"\u002Fv1\u002Fapi-account",") needs ",[382,1851,1852],{},"mto",[382,1854,1832],{},[472,1856,1857,1862,1863,1865,1866,547,1868,661,1871,1873,1874,1877],{},[475,1858,1859,1861],{},[382,1860,1820],{}," is its own action."," The two ",[382,1864,1848],{}," operations need ",[382,1867,1820],{},[382,1869,1870],{},"*\u002F*",[382,1872,1832],{},". A role for ",[382,1875,1876],{},"*\u002Fread"," does not grant them.",[472,1879,1880,1885,1886,661,1889,1891],{},[475,1881,1882,1861],{},[382,1883,1884],{},"auth\u002Fsignin"," Sign-in links and passwords need it, and no ",[382,1887,1888],{},"student\u002F*",[382,1890,1820],{}," role implies it.",[472,1893,1894,1901,1902,1904],{},[475,1895,1896,1897,1900],{},"A ",[382,1898,1899],{},"disallow"," role wins."," If any matching role says ",[382,1903,1899],{},", the operation is refused, however many roles allow it.",[472,1906,1907,1913,1914,1916],{},[475,1908,1909,1912],{},[382,1910,1911],{},"authorized"," must be empty or your own account id."," A role whose ",[382,1915,1911],{}," names a different id does nothing for your account.",[472,1918,1919,1922],{},[475,1920,1921],{},"The change is recent."," Role changes take up to a minute to reach every request.",[357,1924,1925,1926,1928,1929,1931],{},"Only an operator can change roles. Tell ",[361,1927,1776],{"href":346}," which operations you need, and see ",[361,1930,25],{"href":26}," for ready-made role sets.",[1793,1933,1935],{"id":1934},"other-403-messages","Other 403 messages",[512,1937,1938,1951],{},[515,1939,1940],{},[518,1941,1942,1945,1948],{},[521,1943,1944],{},"Message",[521,1946,1947],{},"Operation",[521,1949,1950],{},"Cause and fix",[531,1952,1953,1983],{},[518,1954,1955,1960,1967],{},[536,1956,1957],{},[382,1958,1959],{},"Setting a student's password needs the auth\u002Fsignin permission on mto, the same grant a sign-in link needs.",[536,1961,1962],{},[361,1963,1964],{"href":174},[382,1965,1966],{},"registerStudent",[536,1968,1969,1970,1973,1974,1976,1977,1979,1980,1982],{},"You sent ",[382,1971,1972],{},"password"," without holding ",[382,1975,1884],{}," on ",[382,1978,1852],{},". Nothing was created. Leave ",[382,1981,1972],{}," out, or ask for the permission.",[518,1984,1985,1990,1997],{},[536,1986,1987],{},[382,1988,1989],{},"Student is not activated for organization \u003Cslug>.",[536,1991,1992],{},[361,1993,1994],{"href":211},[382,1995,1996],{},"createSigninLink",[536,1998,1999,2000,2005],{},"The student has no access to this organization. Grant it with ",[361,2001,2002],{"href":202},[382,2003,2004],{},"updateOrgStudent",", then create the link again.",[367,2007,2009],{"id":2008},"status-404-not_found","Status 404: not_found",[357,2011,1896,2012,2014],{},[382,2013,660],{}," can come from the path, from the organization, or from the operation itself. The message tells you which.",[512,2016,2017,2029],{},[515,2018,2019],{},[518,2020,2021,2023,2026],{},[521,2022,1944],{},[521,2024,2025],{},"What it means",[521,2027,2028],{},"What to check",[531,2030,2031,2062,2096,2112,2134,2147,2166],{},[518,2032,2033,2037,2046],{},[536,2034,2035],{},[382,2036,600],{},[536,2038,589,2039,2041,2042,2045],{},[382,2040,592],{}," is not one of the organizations ",[382,2043,2044],{},"GET \u002Fv1\u002Forganization"," lists.",[536,2047,2048,2049,2052,2053,2057,2058,2061],{},"Use the ",[382,2050,2051],{},"_id"," from ",[361,2054,2055],{"href":162},[382,2056,2044],{},", never the slug (",[382,2059,2060],{},"stem",") or the name. It must be exactly 24 hexadecimal characters.",[518,2063,2064,2069,2078],{},[536,2065,2066],{},[382,2067,2068],{},"Student not found!",[536,2070,2071,2072,2077],{},"No student with this id belongs to your account, or, on ",[361,2073,2074],{"href":199},[382,2075,2076],{},"getOrgStudent",", the student has no access to that organization.",[536,2079,2080,2081,2083,2084,2087,2088,2091,2092,2095],{},"Use the id that registration returned, the core-record ",[382,2082,2051],{},". On organization data, such as the ",[382,2085,2086],{},"user"," of an application, that id is in ",[382,2089,2090],{},"mainId",". ",[382,2093,2094],{},"user._id"," there is the organization's own id and does not work on student operations.",[518,2097,2098,2103,2106],{},[536,2099,2100],{},[382,2101,2102],{},"Application not found!",[536,2104,2105],{},"No application of your students has this id on this organization. It does not exist there, or it belongs to another account's student.",[536,2107,2108,2109,2111],{},"Application ids belong to one organization. Check that the ",[382,2110,592],{}," is the one you created the application on.",[518,2113,2114,2119,2122],{},[536,2115,2116],{},[382,2117,2118],{},"Not found!",[536,2120,2121],{},"On a download or a supervisor link: one of several checks failed, and the answer never says which.",[536,2123,2124,2125,2129,2130,365],{},"See ",[361,2126,2128],{"href":2127},"#a-certificate-or-report-download-answers-404","Certificate or report download"," and ",[361,2131,2133],{"href":2132},"#the-supervisor-link-always-answers-404","the supervisor link",[518,2135,2136,2141,2144],{},[536,2137,2138],{},[382,2139,2140],{},"Exam not found!",[536,2142,2143],{},"No exam with this id exists on this organization.",[536,2145,2146],{},"Exam ids belong to one organization. Take them from that organization's lists.",[518,2148,2149,2154,2157],{},[536,2150,2151],{},[382,2152,2153],{},"Exam is not open for application, so it is not available through this API.",[536,2155,2156],{},"The exam exists but is closed.",[536,2158,2159,2160,2165],{},"Only exams in ",[361,2161,2162],{"href":217},[382,2163,2164],{},"listExams"," can be read or applied for.",[518,2167,2168,2171,2174],{},[536,2169,2170],{},"A message naming the method and path",[536,2172,2173],{},"The path does not exist.",[536,2175,2176,2177,2180,2181,365],{},"Check the spelling, the ",[382,2178,2179],{},"\u002Fv1"," prefix and the HTTP method against the ",[361,2182,116],{"href":121},[357,2184,2185,2186,2189],{},"An application held by another account's student answers ",[382,2187,2188],{},"404 Application not found!"," on every operation, exactly like an id that does not exist.",[1793,2191,2193],{"id":2192},"the-supervisor-link-always-answers-404","The supervisor link always answers 404",[357,2195,2196,2201,2202,2205],{},[361,2197,2198],{"href":205},[382,2199,2200],{},"linkStudentSupervisor"," answers the same ",[382,2203,2204],{},"404 Not found!"," to every refusal, so the message never says which check failed. Check each of these:",[693,2207,2208,2211,2214,2219],{},[472,2209,2210],{},"The student is yours. Use the student's core-record id.",[472,2212,2213],{},"The student has signed in to this organization at least once, which creates the organization's copy of them.",[472,2215,2216,2217,763],{},"The username is spelled correctly. Leading and trailing spaces are removed and case does not matter. A username made only of spaces is a ",[382,2218,660],{},[472,2220,2221,2222,2225],{},"The account behind the username is a supervisor ",[475,2223,2224],{},"on this organization",". A supervisor on one organization is not automatically a supervisor on another.",[357,2227,2228,2229,2232,2233,2235,2236,365],{},"A body with no ",[382,2230,2231],{},"supervisorUsername",", or an empty one, is ",[382,2234,654],{},", not ",[382,2237,660],{},[367,2239,2241],{"id":2240},"status-400-bad_request","Status 400: bad_request",[1793,2243,2245],{"id":2244},"property-should-not-exist","\"property … should not exist\"",[357,2247,2248],{},"The body carries a field the operation does not accept. The API refuses unknown fields rather than ignoring them, so you never receive a success for a request that did less than you asked.",[469,2250,2251,2280,2293],{},[472,2252,2253,2256,2257,547,2259,547,2261,547,2264,547,2267,547,2270,547,2273,2129,2276,2279],{},[475,2254,2255],{},"Sending a record back."," Fields such as ",[382,2258,2051],{},[382,2260,2090],{},[382,2262,2263],{},"username",[382,2265,2266],{},"fullName",[382,2268,2269],{},"emailConfirmed",[382,2271,2272],{},"supervisor",[382,2274,2275],{},"createdAt",[382,2277,2278],{},"updatedAt"," are read-only. Send only the fields you are changing.",[472,2281,2282,2287,2288,365],{},[475,2283,2284,2286],{},[382,2285,1972],{}," on an update."," Passwords are set only at registration or with ",[361,2289,2290],{"href":193},[382,2291,2292],{},"setStudentPassword",[472,2294,2295,2301,2302,2129,2305,2307],{},[475,2296,2297,2298],{},"Anything on an application besides ",[382,2299,2300],{},"examId"," (to move one) or besides ",[382,2303,2304],{},"studentId",[382,2306,2300],{}," (to create one).",[357,2309,2310,2311,2129,2314,2317,2318,2129,2321,2324,2325,2327,2328,989],{},"Unknown query parameters are ignored. Of the ones an operation reads, ",[382,2312,2313],{},"page",[382,2315,2316],{},"limit"," never cause an error, while the student list filters, ",[382,2319,2320],{},"email",[382,2322,2323],{},"signedIn",", answer ",[382,2326,654],{}," when they cannot be read (see ",[361,2329,62],{"href":63},[1793,2331,2333],{"id":2332},"only-one-problem-is-reported-at-a-time","Only one problem is reported at a time",[357,2335,1896,2336,2338],{},[382,2337,654],{}," names the first problem found. After you fix it, the next request may report another one. Validate on your side, against the field rules in the reference, to catch them all at once.",[1793,2340,2342],{"id":2341},"a-field-you-sent-is-reported-as-missing-or-invalid","A field you sent is reported as missing or invalid",[357,2344,2345,2346,2349,2350,2353],{},"If the message complains about a field you did send, for example ",[382,2347,2348],{},"examId must be a mongodb id",", the API did not read your body as JSON. Send ",[382,2351,2352],{},"Content-Type: application\u002Fjson"," and a JSON body.",[1793,2355,2357],{"id":2356},"invalid-value-for-_id-expected-objectid","\"Invalid value for '_id': expected ObjectId.\"",[357,2359,2360,2361,2363,2364,2367],{},"An id in the path is not 24 hexadecimal characters. The quoted name is the field the id was looked up in: usually ",[382,2362,2051],{},", and ",[382,2365,2366],{},"exam"," on the list of one exam's applications. Common causes are a slug or username where an id belongs, a truncated id, or trailing whitespace.",[357,2369,2370,2371,2373,2374,2377,2378,2381,2382,365],{},"Two ids behave differently. A malformed ",[382,2372,592],{}," answers ",[382,2375,2376],{},"404 Organization not found!",". The certificate and report downloads also accept a ",[382,2379,2380],{},"shortId",", so a malformed id there answers ",[382,2383,2204],{},[1793,2385,2387],{"id":2386},"field-messages","Field messages",[512,2389,2390,2400],{},[515,2391,2392],{},[518,2393,2394,2397],{},[521,2395,2396],{},"Message (examples)",[521,2398,2399],{},"Fix",[531,2401,2402,2415,2431,2441,2461,2475,2489,2499,2511],{},[518,2403,2404,2412],{},[536,2405,2406,547,2409],{},[382,2407,2408],{},"firstName should not be empty",[382,2410,2411],{},"email must be an email",[536,2413,2414],{},"Send the required field with a valid value.",[518,2416,2417,2422],{},[536,2418,2419],{},[382,2420,2421],{},"birth must be a real date in DD\u002FMM\u002FYYYY format",[536,2423,2424,2425,2235,2428,365],{},"Send ",[382,2426,2427],{},"14\u002F05\u002F2011",[382,2429,2430],{},"2011-05-14",[518,2432,2433,2438],{},[536,2434,2435],{},[382,2436,2437],{},"sex must be one of the following values: m, f, n",[536,2439,2440],{},"Use one of the three codes.",[518,2442,2443,2448],{},[536,2444,2445],{},[382,2446,2447],{},"country must be a mongodb id",[536,2449,2450,2453,2454,2052,2456,365],{},[382,2451,2452],{},"country"," takes only an ",[382,2455,2051],{},[361,2457,2458],{"href":150},[382,2459,2460],{},"listCountries",[518,2462,2463,2468],{},[536,2464,2465],{},[382,2466,2467],{},"email2 must be empty",[536,2469,2470,2471,2474],{},"Leave ",[382,2472,2473],{},"email2"," out.",[518,2476,2477,2482],{},[536,2478,2479],{},[382,2480,2481],{},"redirect must be a site-relative path starting with \"\u002F\" (e.g. \"\u002Fdashboard\")",[536,2483,2484,2485,2488],{},"Send a path such as ",[382,2486,2487],{},"\u002Fdashboard",", not a full URL.",[518,2490,2491,2496],{},[536,2492,2493],{},[382,2494,2495],{},"supervisorUsername should not be empty",[536,2497,2498],{},"Send the supervisor's username.",[518,2500,2501,2506],{},[536,2502,2503],{},[382,2504,2505],{},"password must …",[536,2507,2508,2509,365],{},"The message names the rule that failed: at least 5 characters, at most 72 bytes, and no part of the student's name, username or email address. See ",[361,2510,68],{"href":69},[518,2512,2513,2518],{},[536,2514,2515],{},[382,2516,2517],{},"email must be a valid email address",[536,2519,2520,2521,2523,2524,2527,2528,365],{},"On an update, ",[382,2522,2320],{}," was ",[382,2525,2526],{},"null",". Leave it out to keep the current address. An empty string is refused as ",[382,2529,2530],{},"email should not be empty",[1793,2532,2534],{"id":2533},"reference-data-messages","Reference data messages",[357,2536,2537],{},"The API never creates a country, grade, city or school. It looks up what you send, and refuses what it cannot find.",[512,2539,2540,2548],{},[515,2541,2542],{},[518,2543,2544,2546],{},[521,2545,1944],{},[521,2547,2399],{},[531,2549,2550,2564,2588,2600,2610,2625],{},[518,2551,2552,2557],{},[536,2553,2554],{},[382,2555,2556],{},"country is not a known country.",[536,2558,2559,2560,365],{},"The id does not exist, or the country cannot be selected. Use an id from ",[361,2561,2562],{"href":150},[382,2563,2460],{},[518,2565,2566,2571],{},[536,2567,2568],{},[382,2569,2570],{},"grade is not a known grade. This API does not create reference data.",[536,2572,2573,2574,2052,2576,2581,2582,1773,2585,365],{},"Use a grade ",[382,2575,2051],{},[361,2577,2578],{"href":156},[382,2579,2580],{},"listGrades",", or a name from ",[382,2583,2584],{},"\"1\"",[382,2586,2587],{},"\"12\"",[518,2589,2590,2595],{},[536,2591,2592],{},[382,2593,2594],{},"city is not a known city. This API does not create reference data.",[536,2596,2597,2598,365],{},"A city name is looked up within the student's country. Check the spelling and the country, or send the city's ",[382,2599,2051],{},[518,2601,2602,2607],{},[536,2603,2604],{},[382,2605,2606],{},"school is not a known school. This API does not create reference data.",[536,2608,2609],{},"A school name is looked up within the student's country and city. Check all three.",[518,2611,2612,2617],{},[536,2613,2614],{},[382,2615,2616],{},"city was given as a name, which can only be resolved together with country.",[536,2618,2619,2620,2622,2623,365],{},"The student has no country to look the name up in. Send ",[382,2621,2452],{}," in the same request, or the city's ",[382,2624,2051],{},[518,2626,2627,2632],{},[536,2628,2629],{},[382,2630,2631],{},"school was given as a name, which can only be resolved together with country.",[536,2633,2634,2635,365],{},"A school name needs both a country and a city, and the student lacks one of them. Send both in the same request, or the school's ",[382,2636,2051],{},[357,2638,2639,2640,2642,2643],{},"When you send an ",[382,2641,2051],{}," that matches nothing, the message is the short form, for example ",[382,2644,2645],{},"grade is not a known grade.",[1793,2647,2649],{"id":2648},"grade-messages-on-exams-and-applications","Grade messages on exams and applications",[357,2651,2652,2655],{},[382,2653,2654],{},"Student has no grade set, and every exam is restricted to a set of grades. Set one with PUT \u002F:organizationId\u002Fstudent\u002F:studentId before …"," means the student has no grade. Set one on either student update operation, then try again.",[367,2657,2659],{"id":2658},"status-409-conflict","Status 409: conflict",[357,2661,1896,2662,2664],{},[382,2663,664],{}," means the request is well-formed, but the current state of a record blocks it. The message names the rule. None of these clears if you simply retry. Change the input, or do the step the message names first.",[1793,2666,2668],{"id":2667},"students-and-passwords","Students and passwords",[512,2670,2671,2679],{},[515,2672,2673],{},[518,2674,2675,2677],{},[521,2676,1944],{},[521,2678,1950],{},[531,2680,2681,2691,2701],{},[518,2682,2683,2688],{},[536,2684,2685],{},[382,2686,2687],{},"A student with that email is already registered to this account (\u003CstudentId>).",[536,2689,2690],{},"You registered this address before. Fetch or update the student with the id in the message.",[518,2692,2693,2698],{},[536,2694,2695],{},[382,2696,2697],{},"That email address is already registered.",[536,2699,2700],{},"Someone else on the platform uses this address. On an update, it can also be another of your own students. Use a different address.",[518,2702,2703,2708],{},[536,2704,2705],{},[382,2706,2707],{},"This student has confirmed their email address, so the password is theirs to change. …",[536,2709,2710,2711,2714],{},"You can no longer set this student's password. Send them a ",[361,2712,2713],{"href":81},"sign-in link"," instead.",[1793,2716,2718,2719],{"id":2717},"student-has-never-signed-in-to","\"Student has never signed in to ",[2720,2721,2722],"slug",{}," …\"",[357,2724,2725],{},[382,2726,2727],{},"Student has never signed in to \u003Cslug>, so \u003Cslug> holds no record for them. Generate a sign-in link first with POST \u002F:organizationId\u002Fauth\u002Fsignin.",[357,2729,2730,2731,2734],{},"This appears on applications, on a student's application list, and on certificate and report lists. The organization creates its copy of a student the first time the student opens a sign-in link for it. ",[361,2732,2733],{"href":211},"Create a link",", have the student open it in a browser, then try again. Creating the link without opening it is not enough.",[1793,2736,2738],{"id":2737},"creating-or-moving-an-application","Creating or moving an application",[357,2740,2741],{},"The API checks these in order and reports the first that applies.",[512,2743,2744,2752],{},[515,2745,2746],{},[518,2747,2748,2750],{},[521,2749,1944],{},[521,2751,1950],{},[531,2753,2754,2764,2774,2784,2794,2804],{},[518,2755,2756,2761],{},[536,2757,2758],{},[382,2759,2760],{},"Exam is not open for application. Only exams returned by GET \u002F:organizationId\u002Fexam can be applied to.",[536,2762,2763],{},"The session has passed, the category is inactive, or applications are switched off. Pick an exam from the student's available exams.",[518,2765,2766,2771],{},[536,2767,2768],{},[382,2769,2770],{},"Exam is not available for grade \u003Cgrade>. It accepts grade \u003Cgrades>.",[536,2772,2773],{},"The exam does not take the student's grade. Pick another exam, or correct the student's grade if it is wrong.",[518,2775,2776,2781],{},[536,2777,2778],{},[382,2779,2780],{},"Exam is not available in this student’s country. It is offered in \u003Ccountries>.",[536,2782,2783],{},"The exam is restricted to other countries.",[518,2785,2786,2791],{},[536,2787,2788],{},[382,2789,2790],{},"Exam has no language set, so it is not offered to students and cannot be applied to.",[536,2792,2793],{},"This exam cannot be taken by anyone. Pick another.",[518,2795,2796,2801],{},[536,2797,2798],{},[382,2799,2800],{},"Exam is not available to this student. …",[536,2802,2803],{},"Rare. Use the available exams list, which never offers such an exam.",[518,2805,2806,2811],{},[536,2807,2808],{},[382,2809,2810],{},"Student already has an application for \u003Ccategory> on this sitting. Two exams in one category on one date cannot both be sat.",[536,2812,2813,2814,2817],{},"The student holds another exam in this category on this session. To change language, ",[361,2815,2816],{"href":250},"move"," the existing application instead of creating a new one.",[357,2819,2820],{},"Only on a move. The first row is checked before anything else, and the others after the rules above:",[512,2822,2823,2831],{},[515,2824,2825],{},[518,2826,2827,2829],{},[521,2828,1944],{},[521,2830,1950],{},[531,2832,2833,2843,2853,2863],{},[518,2834,2835,2840],{},[536,2836,2837],{},[382,2838,2839],{},"This exam has already been started and can no longer be changed.",[536,2841,2842],{},"The student has started or submitted the exam.",[518,2844,2845,2850],{},[536,2846,2847],{},[382,2848,2849],{},"An application for \u003Ccategory> cannot be moved to that category.",[536,2851,2852],{},"The old exam's category does not allow a switch to the new exam's category.",[518,2854,2855,2860],{},[536,2856,2857],{},[382,2858,2859],{},"Training has already started for this AI Challenge application, so it can no longer be moved.",[536,2861,2862],{},"The student has used part of the AI Challenge's image quota.",[518,2864,2865,2870],{},[536,2866,2867],{},[382,2868,2869],{},"Application has been paid for at \u003Camount>, and that exam costs \u003Cprice>. …",[536,2871,2872],{},"A paid application can move only to an exam with the same price.",[1793,2874,2876],{"id":2875},"deleting-an-application","Deleting an application",[357,2878,2879,2882],{},[382,2880,2881],{},"Application has been paid for and cannot be deleted. Cancelling a paid application requires a refund, which this API does not perform."," The application has a settled payment. Contact the organization about a refund. The API cannot make one.",[367,2884,2886],{"id":2885},"status-413-and-415-payload_too_large-and-unsupported_media_type","Status 413 and 415: payload_too_large and unsupported_media_type",[469,2888,2889,2895],{},[472,2890,2891,2894],{},[475,2892,2893],{},"413",": the JSON body is larger than 100 kB. The request was refused before anything was read or written. No operation needs a body anywhere near that size, so look for a bug that sends too much, such as a whole student list in one request.",[472,2896,2897,2900,2901,2903,2904,547,2907,661,2910,365],{},[475,2898,2899],{},"415",": the body is not UTF-8, or it is compressed in a way the API does not read. Send ",[382,2902,2352],{}," in UTF-8, either uncompressed or with ",[382,2905,2906],{},"Content-Encoding: gzip",[382,2908,2909],{},"deflate",[382,2911,2912],{},"br",[367,2914,2916],{"id":2915},"status-429-too_many_requests","Status 429: too_many_requests",[357,2918,2919],{},"You made more than 100 requests to one operation within 60 seconds.",[693,2921,2922,2931,2937,2943,2956],{},[472,2923,2924,2930],{},[475,2925,2926,2927],{},"Wait for the number of seconds in ",[382,2928,2929],{},"Retry-After"," before sending that operation again. Requests sent sooner are refused too, but they do not extend the wait.",[472,2932,2933,2936],{},[475,2934,2935],{},"Other operations are unaffected."," The limit is counted separately for each operation, so you can keep calling the others.",[472,2938,2939,2942],{},[475,2940,2941],{},"All your servers share the budget."," It belongs to the account, so spreading calls across servers or addresses does not raise it.",[472,2944,2945,2948,2949,2129,2952,2955],{},[475,2946,2947],{},"Pace yourself."," Read ",[382,2950,2951],{},"X-RateLimit-Remaining",[382,2953,2954],{},"X-RateLimit-Reset"," (seconds until the window resets) on each response, and slow down before you reach zero.",[472,2957,2958,2961,2962,2964],{},[475,2959,2960],{},"Fix the loop."," A request that fails validation still counts. A loop that retries a ",[382,2963,654],{}," burns through your budget.",[357,2966,2124,2967,2969],{},[361,2968,45],{"href":46}," for budgeting patterns.",[367,2971,2973],{"id":2972},"status-500-internal_error-timeouts-and-dropped-connections","Status 500: internal_error, timeouts and dropped connections",[469,2975,2976,2994,3014],{},[472,2977,2978,2983,2984,2987,2988,2991,2992,365],{},[475,2979,2980],{},[382,2981,2982],{},"500 internal_error"," is a problem on our side. The message is always ",[382,2985,2986],{},"An unexpected error occurred.",", or a specific one such as ",[382,2989,2990],{},"Could not issue a sign-in token, please retry."," Retry with exponential backoff and jitter, starting at about one second. If it keeps happening, send support the ",[382,2993,495],{},[472,2995,2996,2999,3000],{},[475,2997,2998],{},"A timeout or dropped connection on a write"," leaves you unsure whether it happened. Before you repeat it, check:\n",[469,3001,3002,3008,3011],{},[472,3003,3004,3005,3007],{},"For a registration, send the same request again. If the first attempt went through, the repeat answers ",[382,3006,664],{}," with the new student's id in the message.",[472,3009,3010],{},"For an application, simply repeat. The same student and exam return the existing application.",[472,3012,3013],{},"For a move, fetch the application and look at its exam.",[472,3015,3016,3019,3020,3023],{},[475,3017,3018],{},"A download that stops partway"," is a failed download, even if some bytes arrived. Discard the partial file and try again. Compare against ",[382,3021,3022],{},"Content-Length"," when it is present.",[357,3025,2124,3026,365],{},[361,3027,3028],{"href":49},"Retries and idempotency",[367,3030,3032],{"id":3031},"sign-in-links-that-fail-in-the-browser","Sign-in links that fail in the browser",[357,3034,3035],{},"These problems happen after your API call has succeeded, in the student's browser.",[1793,3037,3039],{"id":3038},"the-student-sees-invalid-or-expired-access-token","The student sees \"Invalid or expired access token\"",[357,3041,3042],{},"A link works once, and for 120 seconds. The student sees this message when:",[693,3044,3045,3051,3057],{},[472,3046,3047,3050],{},[475,3048,3049],{},"The link was already used."," The student opened it twice, for example with a refresh or back button, or a second tab.",[472,3052,3053,3056],{},[475,3054,3055],{},"Something opened it first."," Chat and email link previews, security scanners and browser prefetching all open links, and any of them uses up the link. This is the most common hidden cause when you send links through a messaging tool.",[472,3058,3059,3062],{},[475,3060,3061],{},"It was more than 120 seconds old."," For example, you created it when the page loaded, and the student clicked later.",[357,3064,3065,3066,3069,3070,3072],{},"The fix for all three is the same. Create the link when the student clicks, and answer that click with a ",[382,3067,3068],{},"302"," redirect to the link. Never show the link on a page, send it, or store it. ",[361,3071,103],{"href":104}," has complete Node.js and PHP examples.",[1793,3074,3076],{"id":3075},"the-student-lands-on-the-home-page-instead-of-the-page-i-chose","The student lands on the home page instead of the page I chose",[357,3078,3079,3082,3083,3085,3086,3088,3089,365],{},[382,3080,3081],{},"redirect"," was left out, so the organization's home page was used. Send a path such as ",[382,3084,2487],{},". An empty ",[382,3087,3081],{}," never gets this far: it is refused with ",[382,3090,654],{},[1793,3092,3094],{"id":3093},"the-panel-keeps-asking-the-student-for-an-email-code","The panel keeps asking the student for an email code",[357,3096,3097],{},"The student's email address isn't confirmed. The panel asks for a 6-digit code on every page until it is, My Exams included, so the student can't start an exam before confirming. They can't put it off: the only way out is signing out. A student already inside an exam room is not interrupted. This is expected, and your API call played no part in it. Check, in order:",[693,3099,3100,3110,3125],{},[472,3101,3102,3105,3106,3109],{},[475,3103,3104],{},"The code didn't arrive."," It comes from ",[382,3107,3108],{},"no-reply@main-team.org",", so ask the student to check their spam folder. A code is valid for 15 minutes, and they can ask for a new one after 60 seconds.",[472,3111,3112,3115,3116,3121,3122,3124],{},[475,3113,3114],{},"The address is wrong."," A student can't receive a code at an address that isn't theirs. Correct it with ",[361,3117,3118],{"href":189},[382,3119,3120],{},"PUT \u002Fv1\u002Fstudent\u002F{studentId}",", then send the student a new ",[361,3123,2713],{"href":81},". A student who was already signed in when the address changed is told to sign in again before a code can be sent.",[472,3126,3127,3130],{},[475,3128,3129],{},"You changed the address."," Changing a student's email through the API withdraws its confirmation, so the panel asks again, for the new address, once the student signs in again.",[357,3132,3133,3134,3136,3137,3142,3143,3146],{},"Only the confirmation on the student's core record counts. Read it as ",[382,3135,2269],{}," with ",[361,3138,3139],{"href":186},[382,3140,3141],{},"GET \u002Fv1\u002Fstudent\u002F{studentId}",". The sandbox's panels never ask for a code, because the sandbox sends no emails; see ",[361,3144,16],{"href":3145},"\u002Fapi\u002Fenvironments#sandbox",". Have your students confirm well before an exam day, for example right after their first sign-in.",[1793,3148,3150],{"id":3149},"creating-the-link-is-refused","Creating the link is refused",[357,3152,3153],{},"Look up the answer:",[469,3155,3156,3164,3173],{},[472,3157,3158,3160,3161,365],{},[382,3159,657],{}," \"Student is not activated…\": see ",[361,3162,1935],{"href":3163},"#other-403-messages",[472,3165,3166,3169,3170,365],{},[382,3167,3168],{},"404 Student not found!",": see ",[361,3171,568],{"href":3172},"#status-404-not_found",[472,3174,3175,1976,3177,3169,3179,365],{},[382,3176,654],{},[382,3178,3081],{},[361,3180,2387],{"href":3181},"#field-messages",[367,3183,3185],{"id":3184},"an-exam-i-expect-is-missing","An exam I expect is missing",[357,3187,3188],{},"Work outward from the student:",[693,3190,3191,3202,3215,3225,3231],{},[472,3192,3193,3196,3197,3201],{},[475,3194,3195],{},"Is the exam open?"," It must appear in ",[361,3198,3199],{"href":217},[382,3200,2164],{}," for that organization. If it is not there, it is closed, and nothing else matters.",[472,3203,3204,3207,3208,3211,3212,365],{},[475,3205,3206],{},"Does it accept the student's grade?"," The exam's ",[382,3209,3210],{},"grades"," lists the grades it accepts. Check the student's ",[382,3213,3214],{},"grade",[472,3216,3217,3220,3221,3224],{},[475,3218,3219],{},"Does it accept the student's country?"," If its ",[382,3222,3223],{},"countries"," list is not empty, it must include the student's country. The country is matched by name in the organization's own country list. If the organization has no country of that name, the student is offered only exams with no country restriction.",[472,3226,3227,3230],{},[475,3228,3229],{},"Does it have a language?"," An exam with no language is never offered.",[472,3232,3233,3236,3237,3240],{},[475,3234,3235],{},"Does the student already hold this category on this session?"," A student cannot hold two exams in one category on one date. ",[361,3238,3239],{"href":250},"Move"," the existing application to change language.",[357,3242,3243,3244,3249],{},"The student does not need to have signed in to the organization for ",[361,3245,3246],{"href":226},[382,3247,3248],{},"listAvailableExams"," to work. They do need to have signed in before you can apply.",[367,3251,3253],{"id":3252},"a-list-comes-back-empty","A list comes back empty",[512,3255,3256,3266],{},[515,3257,3258],{},[518,3259,3260,3263],{},[521,3261,3262],{},"List",[521,3264,3265],{},"Why it can be empty",[531,3267,3268,3288,3300,3315,3332],{},[518,3269,3270,3277],{},[536,3271,3272],{},[361,3273,3274],{"href":196},[382,3275,3276],{},"listOrgStudents",[536,3278,3279,3280,3283,3284,3287],{},"Your students' ",[382,3281,3282],{},"activatedPlatformsThisSeason"," hold neither ",[382,3285,3286],{},"common"," nor this organization's slug.",[518,3289,3290,3297],{},[536,3291,3292],{},[361,3293,3294],{"href":235},[382,3295,3296],{},"listApplications",[536,3298,3299],{},"Only your own students' applications are listed, and only for students who have access to this organization and have signed in to it at least once.",[518,3301,3302,3309],{},[536,3303,3304],{},[361,3305,3306],{"href":241},[382,3307,3308],{},"listExamApplications",[536,3310,3311,3312,3314],{},"The same rule as ",[382,3313,3296],{},", for one exam. An exam id from another organization matches nothing.",[518,3316,3317,3329],{},[536,3318,3319,547,3324],{},[361,3320,3321],{"href":264},[382,3322,3323],{},"listStudentCertificates",[361,3325,3326],{"href":270},[382,3327,3328],{},"listStudentReports",[536,3330,3331],{},"Nothing has been released for this student yet. Documents appear only once the organization publishes results.",[518,3333,3334,3337],{},[536,3335,3336],{},"Any list",[536,3338,3339,3341,3342,3345,3346,3349],{},[382,3340,2313],{}," is beyond ",[382,3343,3344],{},"pagination.totalPages",". Past the last page, ",[382,3347,3348],{},"data"," is empty.",[357,3351,1896,3352,3354,3355,661,3357,3359,3360,365],{},[382,3353,2316],{}," above 100 is lowered to 100, and a missing or unreadable ",[382,3356,2313],{},[382,3358,2316],{}," falls back to the default. Neither is an error. See ",[361,3361,39],{"href":40},[367,3363,3365],{"id":3364},"a-certificate-or-report-download-answers-404","A certificate or report download answers 404",[357,3367,3368,2129,3373,3378,3379,3381],{},[361,3369,3370],{"href":261},[382,3371,3372],{},"downloadCertificate",[361,3374,3375],{"href":267},[382,3376,3377],{},"downloadReport"," answer ",[382,3380,2204],{}," in each of these cases, and never say which:",[693,3383,3384,3392,3395,3398],{},[472,3385,3386,3387,661,3389,3391],{},"No certificate or report has this ",[382,3388,2051],{},[382,3390,2380],{}," on this organization.",[472,3393,3394],{},"It is not released yet, or, for a report, it was withdrawn.",[472,3396,3397],{},"It belongs to another account's student.",[472,3399,3400],{},"It has no file attached, or the file is missing.",[357,3402,3403,3404,365],{},"Take ids from the student's list for the same organization. The lists show only released documents, so an id from a list should download. If one does not, send support the ",[382,3405,495],{},[367,3407,3409],{"id":3408},"what-to-send-support","What to send support",[357,3411,3412,3413,3415],{},"Most problems can be solved from one request id. When you write to ",[361,3414,1776],{"href":346},", include:",[512,3417,3418,3428],{},[515,3419,3420],{},[518,3421,3422,3425],{},[521,3423,3424],{},"Include",[521,3426,3427],{},"Example",[531,3429,3430,3445,3455,3468,3486,3494],{},[518,3431,3432,3440],{},[536,3433,589,3434,3436,3437,3439],{},[382,3435,495],{}," from the error, or the ",[382,3438,499],{}," response header",[536,3441,3442],{},[382,3443,3444],{},"7c1e9a52-3f0b-4d8e-9a61-2b5d0c4e8f13",[518,3446,3447,3450],{},[536,3448,3449],{},"The time of the request, in UTC",[536,3451,3452],{},[382,3453,3454],{},"2026-10-02 14:03:27 UTC",[518,3456,3457,3460],{},[536,3458,3459],{},"The operation, by its operationId, plus method and path",[536,3461,3462,547,3465],{},[382,3463,3464],{},"createApplication",[382,3466,3467],{},"POST \u002Fv1\u002F64b7…c3d5\u002Fapplication",[518,3469,3470,3480],{},[536,3471,3472,3473,2129,3476,3479],{},"The status, ",[382,3474,3475],{},"error.code",[382,3477,3478],{},"error.message"," you received",[536,3481,3482,3485],{},[382,3483,3484],{},"409 conflict",", \"Exam is not available for grade 7. …\"",[518,3487,3488,3491],{},[536,3489,3490],{},"What you expected, and what you already checked on this page",[536,3492,3493],{},"\"Expected 201; the exam is in the available list for this student\"",[518,3495,3496,3501],{},[536,3497,3498,3499],{},"Your company name and your ",[382,3500,730],{},[536,3502,3503,3506],{},[382,3504,3505],{},"key_Q2x5…"," (the apiKey is public, so it is fine to share)",[357,3508,3509],{},"Never include:",[469,3511,3512,3520,3530,3535],{},[472,3513,3514,3519],{},[475,3515,3516,3517],{},"your ",[382,3518,826],{},",",[472,3521,3522,3525,3526,3529],{},[475,3523,3524],{},"a token",", including in a pasted ",[382,3527,3528],{},"Authorization"," header or a curl command,",[472,3531,3532,3519],{},[475,3533,3534],{},"a sign-in link URL",[472,3536,3537,365],{},[475,3538,3539],{},"a student's password",[357,3541,3542,3543,3546],{},"A token or link is a working credential. If you have already sent one anywhere, ",[361,3544,3545],{"href":140},"revoke the token",", and treat the link as used. Keep students' personal details out of your message too. Their ids are enough for us to find the records.",[1779,3548,3550],{"type":3549},"note",[357,3551,3552,3553,3555,3556,3559,3560,3562],{},"Sending your own ",[382,3554,499],{}," with each request (letters, digits and ",[382,3557,3558],{},". _ : ; = + \u002F @ -",", up to 256 characters) makes the id in our logs the same as the one in yours, so a single value finds the request on both sides. A value with any other character, or a longer one, is replaced with an id the API generates, and the ",[382,3561,499],{}," response header carries that one.",[3564,3565,3566],"style",{},"html pre.shiki code .suds8, html code.shiki .suds8{--shiki-default:#0E1116;--shiki-dark:#F0F3F6}html pre.shiki code .sne4z, html code.shiki .sne4z{--shiki-default:#024C1A;--shiki-dark:#72F088}html pre.shiki code .sT6z2, html code.shiki .sT6z2{--shiki-default:#032563;--shiki-dark:#ADDCFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sLBg1, html code.shiki .sLBg1{--shiki-default:#66707B;--shiki-dark:#BDC4CC}html pre.shiki code .sHUrx, html code.shiki .sHUrx{--shiki-default:#A0111F;--shiki-dark:#FF9492}html pre.shiki code .s-5SL, html code.shiki .s-5SL{--shiki-default:#023B95;--shiki-dark:#91CBFF}html pre.shiki code .sKwhi, html code.shiki .sKwhi{--shiki-default:#622CBC;--shiki-dark:#DBB7FF}html pre.shiki code .soyes, html code.shiki .soyes{--shiki-default:#702C00;--shiki-dark:#FFB757}",{"title":380,"searchDepth":395,"depth":405,"links":3568},[3569,3570,3571,3572,3576,3579,3588,3595,3596,3597,3598,3604,3605,3606,3607],{"id":369,"depth":395,"text":370},{"id":506,"depth":395,"text":507},{"id":683,"depth":395,"text":684},{"id":1790,"depth":395,"text":1791,"children":3573},[3574,3575],{"id":1795,"depth":405,"text":1796},{"id":1934,"depth":405,"text":1935},{"id":2008,"depth":395,"text":2009,"children":3577},[3578],{"id":2192,"depth":405,"text":2193},{"id":2240,"depth":395,"text":2241,"children":3580},[3581,3582,3583,3584,3585,3586,3587],{"id":2244,"depth":405,"text":2245},{"id":2332,"depth":405,"text":2333},{"id":2341,"depth":405,"text":2342},{"id":2356,"depth":405,"text":2357},{"id":2386,"depth":405,"text":2387},{"id":2533,"depth":405,"text":2534},{"id":2648,"depth":405,"text":2649},{"id":2658,"depth":395,"text":2659,"children":3589},[3590,3591,3593,3594],{"id":2667,"depth":405,"text":2668},{"id":2717,"depth":405,"text":3592},"\"Student has never signed in to  …\"",{"id":2737,"depth":405,"text":2738},{"id":2875,"depth":405,"text":2876},{"id":2885,"depth":395,"text":2886},{"id":2915,"depth":395,"text":2916},{"id":2972,"depth":395,"text":2973},{"id":3031,"depth":395,"text":3032,"children":3599},[3600,3601,3602,3603],{"id":3038,"depth":405,"text":3039},{"id":3075,"depth":405,"text":3076},{"id":3093,"depth":405,"text":3094},{"id":3149,"depth":405,"text":3150},{"id":3184,"depth":395,"text":3185},{"id":3252,"depth":395,"text":3253},{"id":3364,"depth":395,"text":3365},{"id":3408,"depth":395,"text":3409},"Find your symptom, then check its causes in order. Covers every status the API returns, sign-in link failures in the browser, and what to send support.","md",{},[3612,3613,3614,1966,3615,2292,2076,2004,2200,1996,2164,3616,3248,3276,3296,3308,3617,3618,3464,3619,3620,3323,3372,3328,3377],"getCurrentApiAccount","revokeToken","getStudent","updateStudent","getExam","listStudentApplications","getApplication","moveApplication","deleteApplication","30",{"title":342,"description":3608},"api\u002Ftroubleshooting","9pdxIh5jky8Ng2O-m1gyhCTuxZyUp3xzg2bUL4rOc38",[3626,3631,3634,3638,3641,3644,3648,3652,3655,3659,3663,3668,3672,3676,3679,3684,3688,3692,3696,3700,3704,3708,3713,3717,3722],{"operationId":3612,"slug":3627,"method":133,"path":3628,"tag":77,"summary":143,"deprecated":134,"public":134,"permission":3629,"scope":3630,"order":405},"get-current-api-account","\u002Fv1\u002Fapi-account\u002Fvalidate-me","api\u002F*:$org:$ID","flat",{"operationId":3613,"slug":3632,"method":141,"path":3633,"tag":77,"summary":139,"deprecated":134,"public":134,"permission":3629,"scope":3630,"order":395},"revoke-token","\u002Fv1\u002Fapi-account\u002Frevoke-token",{"operationId":3614,"slug":3635,"method":133,"path":3636,"tag":62,"summary":185,"deprecated":134,"public":134,"permission":3637,"scope":3630,"order":1169},"get-student","\u002Fv1\u002Fstudent\u002F{studentId}","student\u002Fread:$org:$ID",{"operationId":1966,"slug":3639,"method":141,"path":1836,"tag":62,"summary":173,"deprecated":134,"public":134,"permission":3640,"scope":3630,"order":1072},"register-student","student\u002Fcreate:$org:$ID",{"operationId":3615,"slug":3642,"method":190,"path":3636,"tag":62,"summary":188,"deprecated":134,"public":134,"permission":3643,"scope":3630,"order":1191},"update-student","student\u002Fupdate:$org:$ID",{"operationId":2292,"slug":3645,"method":190,"path":3646,"tag":62,"summary":192,"deprecated":134,"public":134,"permission":3647,"scope":3630,"order":1212},"set-student-password","\u002Fv1\u002Fstudent\u002F{studentId}\u002Fpassword","auth\u002Fsignin:$org:$ID",{"operationId":2076,"slug":3649,"method":133,"path":3650,"tag":62,"summary":198,"deprecated":134,"public":134,"permission":3637,"scope":3651,"order":1237},"get-org-student","\u002Fv1\u002F{organizationId}\u002Fstudent\u002F{studentId}","organization",{"operationId":2004,"slug":3653,"method":190,"path":3650,"tag":62,"summary":201,"deprecated":134,"public":134,"permission":3643,"scope":3651,"order":3654},"update-org-student",20,{"operationId":2200,"slug":3656,"method":190,"path":3657,"tag":62,"summary":204,"deprecated":134,"public":134,"permission":3643,"scope":3651,"order":3658},"link-student-supervisor","\u002Fv1\u002F{organizationId}\u002Fstudent\u002F{studentId}\u002Fsupervisor",21,{"operationId":1996,"slug":3660,"method":141,"path":3661,"tag":80,"summary":210,"deprecated":134,"public":134,"permission":3647,"scope":3651,"order":3662},"create-signin-link","\u002Fv1\u002F{organizationId}\u002Fauth\u002Fsignin",22,{"operationId":2164,"slug":3664,"method":133,"path":3665,"tag":83,"summary":216,"deprecated":134,"public":134,"permission":3666,"scope":3651,"order":3667},"list-exams","\u002Fv1\u002F{organizationId}\u002Fexam","exam\u002Fread:$org:$ID",23,{"operationId":3616,"slug":3669,"method":133,"path":3670,"tag":83,"summary":228,"deprecated":134,"public":134,"permission":3666,"scope":3651,"order":3671},"get-exam","\u002Fv1\u002F{organizationId}\u002Fexam\u002F{examId}",27,{"operationId":3248,"slug":3673,"method":133,"path":3674,"tag":83,"summary":225,"deprecated":134,"public":134,"permission":3666,"scope":3651,"order":3675},"list-available-exams","\u002Fv1\u002F{organizationId}\u002Fexam\u002Favailable\u002F{studentId}",26,{"operationId":3276,"slug":3677,"method":133,"path":3678,"tag":62,"summary":195,"deprecated":134,"public":134,"permission":3637,"scope":3651,"order":1231},"list-org-students","\u002Fv1\u002F{organizationId}\u002Fstudent",{"operationId":3296,"slug":3680,"method":133,"path":3681,"tag":86,"summary":234,"deprecated":134,"public":134,"permission":3682,"scope":3651,"order":3683},"list-applications","\u002Fv1\u002F{organizationId}\u002Fapplication","application\u002Fread:$org:$ID",28,{"operationId":3308,"slug":3685,"method":133,"path":3686,"tag":86,"summary":240,"deprecated":134,"public":134,"permission":3682,"scope":3651,"order":3687},"list-exam-applications","\u002Fv1\u002F{organizationId}\u002Fapplication\u002Fexam-applications\u002F{examId}",30,{"operationId":3617,"slug":3689,"method":133,"path":3690,"tag":86,"summary":243,"deprecated":134,"public":134,"permission":3682,"scope":3651,"order":3691},"list-student-applications","\u002Fv1\u002F{organizationId}\u002Fapplication\u002Fstudent-applications\u002F{studentId}",31,{"operationId":3618,"slug":3693,"method":133,"path":3694,"tag":86,"summary":246,"deprecated":134,"public":134,"permission":3682,"scope":3651,"order":3695},"get-application","\u002Fv1\u002F{organizationId}\u002Fapplication\u002F{applicationId}",32,{"operationId":3464,"slug":3697,"method":141,"path":3681,"tag":86,"summary":237,"deprecated":134,"public":134,"permission":3698,"scope":3651,"order":3699},"create-application","application\u002Fcreate:$org:$ID",29,{"operationId":3619,"slug":3701,"method":190,"path":3694,"tag":86,"summary":249,"deprecated":134,"public":134,"permission":3702,"scope":3651,"order":3703},"move-application","application\u002Fupdate:$org:$ID",33,{"operationId":3620,"slug":3705,"method":254,"path":3694,"tag":86,"summary":252,"deprecated":134,"public":134,"permission":3706,"scope":3651,"order":3707},"delete-application","application\u002Fdelete:$org:$ID",34,{"operationId":3323,"slug":3709,"method":133,"path":3710,"tag":256,"summary":263,"deprecated":134,"public":134,"permission":3711,"scope":3651,"order":3712},"list-student-certificates","\u002Fv1\u002F{organizationId}\u002Fcertificate\u002F{userId}","certificate\u002Fread:$org:$ID",36,{"operationId":3372,"slug":3714,"method":133,"path":3715,"tag":256,"summary":260,"deprecated":134,"public":134,"permission":3711,"scope":3651,"order":3716},"download-certificate","\u002Fv1\u002F{organizationId}\u002Fcertificate\u002Fdownload\u002F{certificateId}",35,{"operationId":3328,"slug":3718,"method":133,"path":3719,"tag":256,"summary":269,"deprecated":134,"public":134,"permission":3720,"scope":3651,"order":3721},"list-student-reports","\u002Fv1\u002F{organizationId}\u002Freport\u002F{userId}","report\u002Fread:$org:$ID",38,{"operationId":3377,"slug":3723,"method":133,"path":3724,"tag":256,"summary":266,"deprecated":134,"public":134,"permission":3720,"scope":3651,"order":3725},"download-report","\u002Fv1\u002F{organizationId}\u002Freport\u002Fdownload\u002F{reportId}",37,1791554615409]