[{"data":1,"prerenderedAt":6113},["ShallowReactive",2],{"api-nav":3,"api-guide:\u002Fapi\u002Fretries-and-idempotency":351,"api-spec:guide:\u002Fapi\u002Fretries-and-idempotency":6048},[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":353,"body":354,"description":6025,"extension":6026,"meta":6027,"navTitle":48,"navigation":1025,"operations":6028,"order":6044,"path":49,"section":29,"seo":6045,"status":14,"stem":6046,"__hash__":6047},"apiGuides\u002Fapi\u002Fretries-and-idempotency.md","Retries and idempotency",{"type":355,"value":356,"toc":6006},"minimark",[357,366,371,533,551,563,567,572,886,889,904,907,1085,1095,1101,1105,1110,1183,1190,1474,1487,1715,1731,1734,1782,1800,1805,2089,2092,2104,2107,2173,2179,2475,2788,2791,2825,2829,2832,2867,2871,2876,3106,3116,3130,3133,3142,3370,3382,3387,3390,3412,3479,3483,3488,3499,3510,3524,3528,3537,3561,3564,3568,3618,3621,3629,3633,3636,3644,3698,3701,3729,3738,3750,3802,3822,3826,3829,3832,3886,3892,3898,3902,3913,3930,3944,3947,3951,3960,4855,5910,5914,6002],[358,359,360,361,365],"p",{},"A request can fail in two different ways. Either the API answers with an error, and you know exactly what happened, or the connection breaks and you don't know whether the API did the work. This page covers every write operation: what happens when you send the same request again, and how to recover from both kinds of failure. The goal is to avoid duplicate students or applications and to avoid burning through your ",[362,363,364],"a",{"href":46},"rate limit",".",[367,368,370],"h2",{"id":369},"the-short-version","The short version",[372,373,374,390],"table",{},[375,376,377],"thead",{},[378,379,380,384,387],"tr",{},[381,382,383],"th",{},"What came back",[381,385,386],{},"Did this request change anything?",[381,388,389],{},"What to do",[391,392,393,408,428,440,452,468,483,499,512],"tbody",{},[378,394,395,402,405],{},[396,397,398],"td",{},[399,400,401],"code",{},"2xx",[396,403,404],{},"Yes, if it was a write",[396,406,407],{},"Nothing more. Store the result.",[378,409,410,422,425],{},[396,411,412,415,416,415,419],{},[399,413,414],{},"400",", ",[399,417,418],{},"413",[399,420,421],{},"415",[396,423,424],{},"No",[396,426,427],{},"Fix the request. Sending it again unchanged gets the same answer.",[378,429,430,435,437],{},[396,431,432],{},[399,433,434],{},"401",[396,436,424],{},[396,438,439],{},"Sign a fresh token and send the request once more. If that also fails, stop and check your token.",[378,441,442,447,449],{},[396,443,444],{},[399,445,446],{},"403",[396,448,424],{},[396,450,451],{},"Don't retry. A permission or an access rule refused it.",[378,453,454,459,461],{},[396,455,456],{},[399,457,458],{},"404",[396,460,424],{},[396,462,463,464,365],{},"Don't retry. After a delete that timed out, see ",[362,465,467],{"href":466},"#deleting-an-application","Deleting an application",[378,469,470,475,477],{},[396,471,472],{},[399,473,474],{},"409",[396,476,424],{},[396,478,479,480,365],{},"Don't retry unchanged. The message names the state that blocks the request; the group challenge submits also say it in ",[399,481,482],{},"error.details.reason",[378,484,485,490,492],{},[396,486,487],{},[399,488,489],{},"429",[396,491,424],{},[396,493,494,495,498],{},"Wait the number of seconds in ",[399,496,497],{},"Retry-After",", then send it again.",[378,500,501,506,509],{},[396,502,503],{},[399,504,505],{},"500",[396,507,508],{},"Maybe",[396,510,511],{},"Retry with backoff if the operation is safe to repeat (next section). Otherwise check first.",[378,513,514,526,528],{},[396,515,516,415,519,415,522,525],{},[399,517,518],{},"502",[399,520,521],{},"503",[399,523,524],{},"504",", a timeout, or a dropped connection",[396,527,508],{},[396,529,530,531,365],{},"Same as ",[399,532,505],{},[534,535,537],"callout",{"type":536},"note",[358,538,539,540,543,544,546,547,550],{},"Every ",[399,541,542],{},"4xx"," is a refusal. The API checks a request completely before it writes anything, so a ",[399,545,542],{}," never leaves a half-done change behind. You only need a \"did it happen?\" check after a ",[399,548,549],{},"5xx"," or when no response arrived.",[358,552,553,554,556,557,559,560,562],{},"A ",[399,555,489],{},", a ",[399,558,434],{},", and a ",[399,561,446],{}," for a missing permission are all refused before the operation starts. That makes them safe to resend for any operation, including ones that are not idempotent, once you have fixed the cause or waited.",[367,564,566],{"id":565},"which-operations-are-safe-to-repeat","Which operations are safe to repeat",[358,568,539,569,571],{},[399,570,133],{}," has no side effects, so you can repeat it freely. This includes the lists, the single reads, the exam picker and the two PDF downloads. The table covers the writes.",[372,573,574,587],{},[375,575,576],{},[378,577,578,581,584],{},[381,579,580],{},"Operation",[381,582,583],{},"What a repeat does",[381,585,586],{},"Safe to retry after a timeout?",[391,588,589,624,654,670,685,703,722,742,769,791,813,840,864],{},[378,590,591,599,614],{},[396,592,593,595,596],{},[362,594,173],{"href":174}," ",[399,597,598],{},"POST \u002Fv1\u002Fstudent",[396,600,601,605,606,609,610,613],{},[602,603,604],"strong",{},"Not idempotent."," If the first attempt worked, the repeat answers ",[399,607,608],{},"409 conflict"," with the new student's ",[399,611,612],{},"_id"," in the message.",[396,615,616,617,619,620,365],{},"Yes, if you handle that ",[399,618,474],{},". See ",[362,621,623],{"href":622},"#registering-a-student","Registering a student",[378,625,626,633,647],{},[396,627,628,595,630],{},[362,629,179],{"href":180},[399,631,632],{},"POST \u002Fv1\u002Fstudent\u002Fimport",[396,634,635,638,639,642,643,646],{},[602,636,637],{},"Idempotent for 24 hours."," The same rows from your account inside a day answer ",[399,640,641],{},"202"," with the import you already have, not a second one, and the ",[399,644,645],{},"message"," says so.",[396,648,649,650,365],{},"Yes. See ",[362,651,653],{"href":652},"#registering-many-students-at-once","Registering many students at once",[378,655,656,664,667],{},[396,657,658,595,661],{},[362,659,660],{"href":189},"Update a student",[399,662,663],{},"PUT \u002Fv1\u002Fstudent\u002F{studentId}",[396,665,666],{},"Same body, same result.",[396,668,669],{},"Yes",[378,671,672,680,683],{},[396,673,674,595,677],{},[362,675,676],{"href":202},"Update an organization student",[399,678,679],{},"PUT \u002Fv1\u002F{organizationId}\u002Fstudent\u002F{studentId}",[396,681,682],{},"Same body, same result. The organization is added to the student's access list only once.",[396,684,669],{},[378,686,687,695,701],{},[396,688,689,595,692],{},[362,690,691],{"href":193},"Set a password",[399,693,694],{},"PUT \u002Fv1\u002Fstudent\u002F{studentId}\u002Fpassword",[396,696,697,698,700],{},"Sets the same password again. Answers ",[399,699,474],{}," if the student confirmed their email address in between.",[396,702,669],{},[378,704,705,713,720],{},[396,706,707,595,710],{},[362,708,709],{"href":205},"Link a supervisor",[399,711,712],{},"PUT \u002Fv1\u002F{organizationId}\u002Fstudent\u002F{studentId}\u002Fsupervisor",[396,714,715,716,719],{},"Links the same supervisor again and answers ",[399,717,718],{},"200"," each time.",[396,721,669],{},[378,723,724,732,735],{},[396,725,726,595,729],{},[362,727,728],{"href":211},"Create a sign-in link",[399,730,731],{},"POST \u002Fv1\u002F{organizationId}\u002Fauth\u002Fsignin",[396,733,734],{},"Mints a new, separate link. The earlier one expires unused.",[396,736,737,738,741],{},"Yes, retry the request. ",[602,739,740],{},"Never"," reopen or resend the link itself.",[378,743,744,752,766],{},[396,745,746,595,749],{},[362,747,748],{"href":238},"Create an application",[399,750,751],{},"POST \u002Fv1\u002F{organizationId}\u002Fapplication",[396,753,754,757,758,761,762,765],{},[602,755,756],{},"Idempotent"," for the same student and exam: ",[399,759,760],{},"201"," the first time, then ",[399,763,764],{},"200 \"Application already exists.\""," with the same application.",[396,767,768],{},"Yes, one attempt at a time",[378,770,771,779,789],{},[396,772,773,595,776],{},[362,774,775],{"href":250},"Move an application",[399,777,778],{},"PUT \u002Fv1\u002F{organizationId}\u002Fapplication\u002F{applicationId}",[396,780,781,784,785,788],{},[602,782,783],{},"Idempotent."," Moving to the exam the application already has answers ",[399,786,787],{},"200 \"Application already uses that exam.\""," and writes nothing.",[396,790,669],{},[378,792,793,801,807],{},[396,794,795,595,798],{},[362,796,797],{"href":253},"Delete an application",[399,799,800],{},"DELETE \u002Fv1\u002F{organizationId}\u002Fapplication\u002F{applicationId}",[396,802,803,804,365],{},"The first call deletes. A repeat answers ",[399,805,806],{},"404 \"Application not found!\"",[396,808,809,810,812],{},"Yes. Treat that ",[399,811,458],{}," as \"already deleted\" if you know the application existed.",[378,814,815,823,834],{},[396,816,817,595,820],{},[362,818,819],{"href":294},"Submit a group challenge step",[399,821,822],{},"POST \u002Fv1\u002F{organizationId}\u002Fgroup-challenge\u002F{challengeId}\u002Fgroup\u002F{groupId}\u002Fstep\u002F{stepId}\u002Fsubmit",[396,824,825,827,828,830,831,788],{},[602,826,783],{}," A step already submitted, by anyone, answers ",[399,829,718],{}," with ",[399,832,833],{},"changed: false",[396,835,649,836,365],{},[362,837,839],{"href":838},"#group-challenge-submits","Group challenge submits",[378,841,842,850,860],{},[396,843,844,595,847],{},[362,845,846],{"href":291},"Send a group's work",[399,848,849],{},"POST \u002Fv1\u002F{organizationId}\u002Fgroup-challenge\u002F{challengeId}\u002Fgroup\u002F{groupId}\u002Ffinal-submit",[396,851,852,854,855,830,857,859],{},[602,853,783],{}," Work already sent answers ",[399,856,718],{},[399,858,833],{},"; nothing is written and no second e-mail goes out.",[396,861,649,862,365],{},[362,863,839],{"href":838},[378,865,866,874,880],{},[396,867,868,595,871],{},[362,869,870],{"href":140},"Revoke a token",[399,872,873],{},"POST \u002Fv1\u002Fapi-account\u002Frevoke-token",[396,875,876,877,879],{},"The first call revokes the token. A repeat with the same token answers ",[399,878,434],{},", because that token is now revoked.",[396,881,882,883,885],{},"Yes. A ",[399,884,434],{}," on the repeat means the first call worked.",[367,887,653],{"id":888},"registering-many-students-at-once",[358,890,891,893,894,896,897,900,901,903],{},[399,892,632],{}," is the one write on this API that is safe to repeat exactly as it is.\nSend the same rows again inside 24 hours and you get ",[399,895,641],{}," with the import you already have —\n",[399,898,899],{},"data._id"," is the id you already had, and the ",[399,902,645],{}," says the batch was already sent.",[358,905,906],{},"So a request whose answer you never saw needs no special handling at all:",[908,909,914],"pre",{"className":910,"code":911,"language":912,"meta":913,"style":913},"language-js shiki shiki-themes github-light-high-contrast github-dark-high-contrast","const send = () =>\n  fetch('https:\u002F\u002Fapi.main-team.org\u002Fv1\u002Fstudent\u002Fimport', {\n    method: 'POST',\n    headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application\u002Fjson' },\n    body: JSON.stringify({ students: rows }),\n  });\n\nlet answer = await send();\nif (answer.status >= 500 || answer.status === 408) answer = await send();\n","js","",[399,915,916,939,955,967,996,1014,1020,1027,1047],{"__ignoreMap":913},[917,918,921,925,929,932,936],"span",{"class":919,"line":920},"line",1,[917,922,924],{"class":923},"sHUrx","const",[917,926,928],{"class":927},"sKwhi"," send",[917,930,931],{"class":923}," =",[917,933,935],{"class":934},"suds8"," () ",[917,937,938],{"class":923},"=>\n",[917,940,942,945,948,952],{"class":919,"line":941},2,[917,943,944],{"class":927},"  fetch",[917,946,947],{"class":934},"(",[917,949,951],{"class":950},"sT6z2","'https:\u002F\u002Fapi.main-team.org\u002Fv1\u002Fstudent\u002Fimport'",[917,953,954],{"class":934},", {\n",[917,956,958,961,964],{"class":919,"line":957},3,[917,959,960],{"class":934},"    method: ",[917,962,963],{"class":950},"'POST'",[917,965,966],{"class":934},",\n",[917,968,970,973,976,979,982,984,987,990,993],{"class":919,"line":969},4,[917,971,972],{"class":934},"    headers: { Authorization: ",[917,974,975],{"class":950},"`Bearer ${",[917,977,978],{"class":934},"token",[917,980,981],{"class":950},"}`",[917,983,415],{"class":934},[917,985,986],{"class":950},"'Content-Type'",[917,988,989],{"class":934},": ",[917,991,992],{"class":950},"'application\u002Fjson'",[917,994,995],{"class":934}," },\n",[917,997,999,1002,1006,1008,1011],{"class":919,"line":998},5,[917,1000,1001],{"class":934},"    body: ",[917,1003,1005],{"class":1004},"s-5SL","JSON",[917,1007,365],{"class":934},[917,1009,1010],{"class":927},"stringify",[917,1012,1013],{"class":934},"({ students: rows }),\n",[917,1015,1017],{"class":919,"line":1016},6,[917,1018,1019],{"class":934},"  });\n",[917,1021,1023],{"class":919,"line":1022},7,[917,1024,1026],{"emptyLinePlaceholder":1025},true,"\n",[917,1028,1030,1033,1036,1039,1042,1044],{"class":919,"line":1029},8,[917,1031,1032],{"class":923},"let",[917,1034,1035],{"class":934}," answer ",[917,1037,1038],{"class":923},"=",[917,1040,1041],{"class":923}," await",[917,1043,928],{"class":927},[917,1045,1046],{"class":934},"();\n",[917,1048,1050,1053,1056,1059,1062,1065,1068,1071,1074,1077,1079,1081,1083],{"class":919,"line":1049},9,[917,1051,1052],{"class":923},"if",[917,1054,1055],{"class":934}," (answer.status ",[917,1057,1058],{"class":923},">=",[917,1060,1061],{"class":1004}," 500",[917,1063,1064],{"class":923}," ||",[917,1066,1067],{"class":934}," answer.status ",[917,1069,1070],{"class":923},"===",[917,1072,1073],{"class":1004}," 408",[917,1075,1076],{"class":934},") answer ",[917,1078,1038],{"class":923},[917,1080,1041],{"class":923},[917,1082,928],{"class":927},[917,1084,1046],{"class":934},[358,1086,1087,1088,1091,1092,1094],{},"\"The same rows\" means the rows themselves: addresses are compared without regard to case or\nsurrounding spaces, and ",[399,1089,1090],{},"clientReference"," is ignored. Change one row and it is a new batch, which\nis refused with ",[399,1093,474],{}," while the first one is still running.",[358,1096,1097,1098,365],{},"The batch itself is all-or-nothing — every student is registered or none is — so there is never a\nhalf-finished import to reconcile after a retry. See ",[362,1099,1100],{"href":66},"Bulk\nregistration",[367,1102,1104],{"id":1103},"creating-an-application","Creating an application",[358,1106,1107,1109],{},[399,1108,751],{}," is idempotent. Applying the same student to the same exam twice is one request sent twice, so the API answers the repeat with the application that already exists instead of creating a second one.",[908,1111,1115],{"className":1112,"code":1113,"language":1114,"meta":913,"style":913},"language-bash shiki shiki-themes github-light-high-contrast github-dark-high-contrast","curl -X POST \"https:\u002F\u002Fapi.main-team.org\u002Fv1\u002F$ORGANIZATION_ID\u002Fapplication\" \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -H \"X-Request-Id: 1f0c2d9e-5b7a-4c3e-8f21-6a9d0b4e7c35.1\" \\\n  -d '{\"studentId\":\"652f1c9b8e4b2a0012a3c4d5\",\"examId\":\"64a1f0b2c9d8e7f600112233\"}'\n","bash",[399,1116,1117,1141,1157,1166,1175],{"__ignoreMap":913},[917,1118,1119,1123,1126,1129,1132,1135,1138],{"class":919,"line":920},[917,1120,1122],{"class":1121},"soyes","curl",[917,1124,1125],{"class":1004}," -X",[917,1127,1128],{"class":950}," POST",[917,1130,1131],{"class":950}," \"https:\u002F\u002Fapi.main-team.org\u002Fv1\u002F",[917,1133,1134],{"class":934},"$ORGANIZATION_ID",[917,1136,1137],{"class":950},"\u002Fapplication\"",[917,1139,1140],{"class":923}," \\\n",[917,1142,1143,1146,1149,1152,1155],{"class":919,"line":941},[917,1144,1145],{"class":1004},"  -H",[917,1147,1148],{"class":950}," \"Authorization: Bearer ",[917,1150,1151],{"class":934},"$TOKEN",[917,1153,1154],{"class":950},"\"",[917,1156,1140],{"class":923},[917,1158,1159,1161,1164],{"class":919,"line":957},[917,1160,1145],{"class":1004},[917,1162,1163],{"class":950}," \"Content-Type: application\u002Fjson\"",[917,1165,1140],{"class":923},[917,1167,1168,1170,1173],{"class":919,"line":969},[917,1169,1145],{"class":1004},[917,1171,1172],{"class":950}," \"X-Request-Id: 1f0c2d9e-5b7a-4c3e-8f21-6a9d0b4e7c35.1\"",[917,1174,1140],{"class":923},[917,1176,1177,1180],{"class":919,"line":998},[917,1178,1179],{"class":1004},"  -d",[917,1181,1182],{"class":950}," '{\"studentId\":\"652f1c9b8e4b2a0012a3c4d5\",\"examId\":\"64a1f0b2c9d8e7f600112233\"}'\n",[358,1184,1185,1186,1189],{},"The first time, the application is created and you get ",[399,1187,1188],{},"201 Created",":",[908,1191,1195],{"className":1192,"code":1193,"language":1194,"meta":913,"style":913},"language-json shiki shiki-themes github-light-high-contrast github-dark-high-contrast","{\n  \"success\": true,\n  \"message\": \"Application created successfully.\",\n  \"data\": {\n    \"_id\": \"66c3e5f7a9b1c2d3e4f50617\",\n    \"exam\": \"64a1f0b2c9d8e7f600112233\",\n    \"user\": \"66a0b1c2d3e4f5a6b7c8d9e0\",\n    \"payment\": \"66c3e5f7a9b1c2d3e4f50618\",\n    \"ExamBucksRedeemed\": false,\n    \"partners\": [],\n    \"definedQuota\": false,\n    \"participated\": false,\n    \"reversable\": false,\n    \"simulationStarted\": false,\n    \"simulationSubmitted\": false,\n    \"simulationV2Enabled\": false,\n    \"isSimulationV2\": false,\n    \"carriedPoints\": 0,\n    \"uuid\": \"3fa-9c1-e07\",\n    \"cameraRecord\": false,\n    \"createdAt\": \"2026-09-15T09:30:02.511Z\",\n    \"updatedAt\": \"2026-09-15T09:30:02.511Z\",\n    \"__v\": 0\n  }\n}\n","json",[399,1196,1197,1202,1215,1227,1235,1247,1259,1271,1283,1295,1304,1316,1328,1340,1352,1364,1376,1388,1401,1414,1426,1439,1451,1462,1468],{"__ignoreMap":913},[917,1198,1199],{"class":919,"line":920},[917,1200,1201],{"class":934},"{\n",[917,1203,1204,1208,1210,1213],{"class":919,"line":941},[917,1205,1207],{"class":1206},"sne4z","  \"success\"",[917,1209,989],{"class":934},[917,1211,1212],{"class":1004},"true",[917,1214,966],{"class":934},[917,1216,1217,1220,1222,1225],{"class":919,"line":957},[917,1218,1219],{"class":1206},"  \"message\"",[917,1221,989],{"class":934},[917,1223,1224],{"class":950},"\"Application created successfully.\"",[917,1226,966],{"class":934},[917,1228,1229,1232],{"class":919,"line":969},[917,1230,1231],{"class":1206},"  \"data\"",[917,1233,1234],{"class":934},": {\n",[917,1236,1237,1240,1242,1245],{"class":919,"line":998},[917,1238,1239],{"class":1206},"    \"_id\"",[917,1241,989],{"class":934},[917,1243,1244],{"class":950},"\"66c3e5f7a9b1c2d3e4f50617\"",[917,1246,966],{"class":934},[917,1248,1249,1252,1254,1257],{"class":919,"line":1016},[917,1250,1251],{"class":1206},"    \"exam\"",[917,1253,989],{"class":934},[917,1255,1256],{"class":950},"\"64a1f0b2c9d8e7f600112233\"",[917,1258,966],{"class":934},[917,1260,1261,1264,1266,1269],{"class":919,"line":1022},[917,1262,1263],{"class":1206},"    \"user\"",[917,1265,989],{"class":934},[917,1267,1268],{"class":950},"\"66a0b1c2d3e4f5a6b7c8d9e0\"",[917,1270,966],{"class":934},[917,1272,1273,1276,1278,1281],{"class":919,"line":1029},[917,1274,1275],{"class":1206},"    \"payment\"",[917,1277,989],{"class":934},[917,1279,1280],{"class":950},"\"66c3e5f7a9b1c2d3e4f50618\"",[917,1282,966],{"class":934},[917,1284,1285,1288,1290,1293],{"class":919,"line":1049},[917,1286,1287],{"class":1206},"    \"ExamBucksRedeemed\"",[917,1289,989],{"class":934},[917,1291,1292],{"class":1004},"false",[917,1294,966],{"class":934},[917,1296,1298,1301],{"class":919,"line":1297},10,[917,1299,1300],{"class":1206},"    \"partners\"",[917,1302,1303],{"class":934},": [],\n",[917,1305,1307,1310,1312,1314],{"class":919,"line":1306},11,[917,1308,1309],{"class":1206},"    \"definedQuota\"",[917,1311,989],{"class":934},[917,1313,1292],{"class":1004},[917,1315,966],{"class":934},[917,1317,1319,1322,1324,1326],{"class":919,"line":1318},12,[917,1320,1321],{"class":1206},"    \"participated\"",[917,1323,989],{"class":934},[917,1325,1292],{"class":1004},[917,1327,966],{"class":934},[917,1329,1331,1334,1336,1338],{"class":919,"line":1330},13,[917,1332,1333],{"class":1206},"    \"reversable\"",[917,1335,989],{"class":934},[917,1337,1292],{"class":1004},[917,1339,966],{"class":934},[917,1341,1343,1346,1348,1350],{"class":919,"line":1342},14,[917,1344,1345],{"class":1206},"    \"simulationStarted\"",[917,1347,989],{"class":934},[917,1349,1292],{"class":1004},[917,1351,966],{"class":934},[917,1353,1355,1358,1360,1362],{"class":919,"line":1354},15,[917,1356,1357],{"class":1206},"    \"simulationSubmitted\"",[917,1359,989],{"class":934},[917,1361,1292],{"class":1004},[917,1363,966],{"class":934},[917,1365,1367,1370,1372,1374],{"class":919,"line":1366},16,[917,1368,1369],{"class":1206},"    \"simulationV2Enabled\"",[917,1371,989],{"class":934},[917,1373,1292],{"class":1004},[917,1375,966],{"class":934},[917,1377,1379,1382,1384,1386],{"class":919,"line":1378},17,[917,1380,1381],{"class":1206},"    \"isSimulationV2\"",[917,1383,989],{"class":934},[917,1385,1292],{"class":1004},[917,1387,966],{"class":934},[917,1389,1391,1394,1396,1399],{"class":919,"line":1390},18,[917,1392,1393],{"class":1206},"    \"carriedPoints\"",[917,1395,989],{"class":934},[917,1397,1398],{"class":1004},"0",[917,1400,966],{"class":934},[917,1402,1404,1407,1409,1412],{"class":919,"line":1403},19,[917,1405,1406],{"class":1206},"    \"uuid\"",[917,1408,989],{"class":934},[917,1410,1411],{"class":950},"\"3fa-9c1-e07\"",[917,1413,966],{"class":934},[917,1415,1417,1420,1422,1424],{"class":919,"line":1416},20,[917,1418,1419],{"class":1206},"    \"cameraRecord\"",[917,1421,989],{"class":934},[917,1423,1292],{"class":1004},[917,1425,966],{"class":934},[917,1427,1429,1432,1434,1437],{"class":919,"line":1428},21,[917,1430,1431],{"class":1206},"    \"createdAt\"",[917,1433,989],{"class":934},[917,1435,1436],{"class":950},"\"2026-09-15T09:30:02.511Z\"",[917,1438,966],{"class":934},[917,1440,1442,1445,1447,1449],{"class":919,"line":1441},22,[917,1443,1444],{"class":1206},"    \"updatedAt\"",[917,1446,989],{"class":934},[917,1448,1436],{"class":950},[917,1450,966],{"class":934},[917,1452,1454,1457,1459],{"class":919,"line":1453},23,[917,1455,1456],{"class":1206},"    \"__v\"",[917,1458,989],{"class":934},[917,1460,1461],{"class":1004},"0\n",[917,1463,1465],{"class":919,"line":1464},24,[917,1466,1467],{"class":934},"  }\n",[917,1469,1471],{"class":919,"line":1470},25,[917,1472,1473],{"class":934},"}\n",[358,1475,1476,1477,1480,1481,1484,1485,1189],{},"Send the same body again and you get ",[399,1478,1479],{},"200 OK",". ",[399,1482,1483],{},"data"," is the same application, with the same ",[399,1486,612],{},[908,1488,1490],{"className":1192,"code":1489,"language":1194,"meta":913,"style":913},"{\n  \"success\": true,\n  \"message\": \"Application already exists.\",\n  \"data\": {\n    \"_id\": \"66c3e5f7a9b1c2d3e4f50617\",\n    \"exam\": \"64a1f0b2c9d8e7f600112233\",\n    \"user\": \"66a0b1c2d3e4f5a6b7c8d9e0\",\n    \"payment\": \"66c3e5f7a9b1c2d3e4f50618\",\n    \"ExamBucksRedeemed\": false,\n    \"partners\": [],\n    \"definedQuota\": false,\n    \"participated\": false,\n    \"reversable\": false,\n    \"simulationStarted\": false,\n    \"simulationSubmitted\": false,\n    \"simulationV2Enabled\": false,\n    \"isSimulationV2\": false,\n    \"carriedPoints\": 0,\n    \"uuid\": \"3fa-9c1-e07\",\n    \"cameraRecord\": false,\n    \"createdAt\": \"2026-09-15T09:30:02.511Z\",\n    \"updatedAt\": \"2026-09-15T09:30:02.511Z\",\n    \"__v\": 0\n  }\n}\n",[399,1491,1492,1496,1506,1517,1523,1533,1543,1553,1563,1573,1579,1589,1599,1609,1619,1629,1639,1649,1659,1669,1679,1689,1699,1707,1711],{"__ignoreMap":913},[917,1493,1494],{"class":919,"line":920},[917,1495,1201],{"class":934},[917,1497,1498,1500,1502,1504],{"class":919,"line":941},[917,1499,1207],{"class":1206},[917,1501,989],{"class":934},[917,1503,1212],{"class":1004},[917,1505,966],{"class":934},[917,1507,1508,1510,1512,1515],{"class":919,"line":957},[917,1509,1219],{"class":1206},[917,1511,989],{"class":934},[917,1513,1514],{"class":950},"\"Application already exists.\"",[917,1516,966],{"class":934},[917,1518,1519,1521],{"class":919,"line":969},[917,1520,1231],{"class":1206},[917,1522,1234],{"class":934},[917,1524,1525,1527,1529,1531],{"class":919,"line":998},[917,1526,1239],{"class":1206},[917,1528,989],{"class":934},[917,1530,1244],{"class":950},[917,1532,966],{"class":934},[917,1534,1535,1537,1539,1541],{"class":919,"line":1016},[917,1536,1251],{"class":1206},[917,1538,989],{"class":934},[917,1540,1256],{"class":950},[917,1542,966],{"class":934},[917,1544,1545,1547,1549,1551],{"class":919,"line":1022},[917,1546,1263],{"class":1206},[917,1548,989],{"class":934},[917,1550,1268],{"class":950},[917,1552,966],{"class":934},[917,1554,1555,1557,1559,1561],{"class":919,"line":1029},[917,1556,1275],{"class":1206},[917,1558,989],{"class":934},[917,1560,1280],{"class":950},[917,1562,966],{"class":934},[917,1564,1565,1567,1569,1571],{"class":919,"line":1049},[917,1566,1287],{"class":1206},[917,1568,989],{"class":934},[917,1570,1292],{"class":1004},[917,1572,966],{"class":934},[917,1574,1575,1577],{"class":919,"line":1297},[917,1576,1300],{"class":1206},[917,1578,1303],{"class":934},[917,1580,1581,1583,1585,1587],{"class":919,"line":1306},[917,1582,1309],{"class":1206},[917,1584,989],{"class":934},[917,1586,1292],{"class":1004},[917,1588,966],{"class":934},[917,1590,1591,1593,1595,1597],{"class":919,"line":1318},[917,1592,1321],{"class":1206},[917,1594,989],{"class":934},[917,1596,1292],{"class":1004},[917,1598,966],{"class":934},[917,1600,1601,1603,1605,1607],{"class":919,"line":1330},[917,1602,1333],{"class":1206},[917,1604,989],{"class":934},[917,1606,1292],{"class":1004},[917,1608,966],{"class":934},[917,1610,1611,1613,1615,1617],{"class":919,"line":1342},[917,1612,1345],{"class":1206},[917,1614,989],{"class":934},[917,1616,1292],{"class":1004},[917,1618,966],{"class":934},[917,1620,1621,1623,1625,1627],{"class":919,"line":1354},[917,1622,1357],{"class":1206},[917,1624,989],{"class":934},[917,1626,1292],{"class":1004},[917,1628,966],{"class":934},[917,1630,1631,1633,1635,1637],{"class":919,"line":1366},[917,1632,1369],{"class":1206},[917,1634,989],{"class":934},[917,1636,1292],{"class":1004},[917,1638,966],{"class":934},[917,1640,1641,1643,1645,1647],{"class":919,"line":1378},[917,1642,1381],{"class":1206},[917,1644,989],{"class":934},[917,1646,1292],{"class":1004},[917,1648,966],{"class":934},[917,1650,1651,1653,1655,1657],{"class":919,"line":1390},[917,1652,1393],{"class":1206},[917,1654,989],{"class":934},[917,1656,1398],{"class":1004},[917,1658,966],{"class":934},[917,1660,1661,1663,1665,1667],{"class":919,"line":1403},[917,1662,1406],{"class":1206},[917,1664,989],{"class":934},[917,1666,1411],{"class":950},[917,1668,966],{"class":934},[917,1670,1671,1673,1675,1677],{"class":919,"line":1416},[917,1672,1419],{"class":1206},[917,1674,989],{"class":934},[917,1676,1292],{"class":1004},[917,1678,966],{"class":934},[917,1680,1681,1683,1685,1687],{"class":919,"line":1428},[917,1682,1431],{"class":1206},[917,1684,989],{"class":934},[917,1686,1436],{"class":950},[917,1688,966],{"class":934},[917,1690,1691,1693,1695,1697],{"class":919,"line":1441},[917,1692,1444],{"class":1206},[917,1694,989],{"class":934},[917,1696,1436],{"class":950},[917,1698,966],{"class":934},[917,1700,1701,1703,1705],{"class":919,"line":1453},[917,1702,1456],{"class":1206},[917,1704,989],{"class":934},[917,1706,1461],{"class":1004},[917,1708,1709],{"class":919,"line":1464},[917,1710,1467],{"class":934},[917,1712,1713],{"class":919,"line":1470},[917,1714,1473],{"class":934},[358,1716,1717,1718,1720,1721,1723,1724,1727,1728,1730],{},"Branch on the status: ",[399,1719,760],{}," means this request created the application, ",[399,1722,718],{}," means it already existed. Both give you the application to store. (",[399,1725,1726],{},"user"," here is the organization's own id for the student. See ",[362,1729,36],{"href":37},".)",[358,1732,1733],{},"The API runs its checks in this order. The first one that fails decides the answer:",[1735,1736,1737,1745,1750,1755,1765,1772,1777],"ol",{},[1738,1739,1740,1741,1744],"li",{},"The student belongs to your account (otherwise ",[399,1742,1743],{},"404 not_found",").",[1738,1746,1747,1748,1744],{},"The student has signed in to this organization at least once (otherwise ",[399,1749,608],{},[1738,1751,1752,1753,1744],{},"The exam exists in this organization (otherwise ",[399,1754,1743],{},[1738,1756,1757,1758,1760,1761,1764],{},"The exam is one the picker would offer this student: open, their grade, their country, a language set (otherwise ",[399,1759,608],{},", or ",[399,1762,1763],{},"400 bad_request"," when the student has no grade).",[1738,1766,1767],{},[602,1768,1769,1770,365],{},"The application already exists: ",[399,1771,1479],{},[1738,1773,1774,1775,1744],{},"The student holds no other exam in the same category on the same sitting (otherwise ",[399,1776,608],{},[1738,1778,1779,1780,365],{},"The application is created: ",[399,1781,1188],{},[534,1783,1785],{"type":1784},"warn",[358,1786,1787,1788,1790,1791,1793,1794,1799],{},"The repeat is recognized at step 5, after the eligibility checks. If the exam has closed since your first attempt, or the student's grade or country has changed, a repeat answers ",[399,1789,608],{}," even though the application exists. When a retry answers ",[399,1792,474],{},", list the student's applications with ",[362,1795,1796],{"href":244},[399,1797,1798],{},"GET \u002Fv1\u002F{organizationId}\u002Fapplication\u002Fstudent-applications\u002F{studentId}"," before you conclude that the first attempt failed.",[534,1801,1802],{"type":1784},[358,1803,1804],{},"Send at most one create for a given student and exam at a time. The API recognizes a repeat only once the earlier request has finished. Two identical requests in flight at the same moment, from two workers say, are not guaranteed to be treated as one. Retry after the previous attempt has completed or timed out, never in parallel with it.",[908,1806,1808],{"className":910,"code":1807,"language":912,"meta":913,"style":913},"\u002F\u002F Apply once, surviving timeouts. callApi is the helper at the end of this page.\nexport async function applyOnce(organizationId, studentId, examId) {\n  const res = await callApi('POST', `\u002F${organizationId}\u002Fapplication`, {\n    body: { studentId, examId },\n    repeatable: true,\n  });\n  const body = await res.json();\n\n  if (res.status === 201) return { created: true, application: body.data };\n  if (res.status === 200) return { created: false, application: body.data };\n\n  if (res.status === 409) {\n    \u002F\u002F The exam may have closed after an earlier attempt succeeded. Look before giving up.\n    const existing = await findApplication(organizationId, studentId, examId);\n    if (existing) return { created: false, application: existing };\n  }\n  throw new Error(`${res.status} ${body.error.code}: ${body.error.message}`);\n}\n",[399,1809,1810,1816,1848,1879,1884,1893,1897,1915,1919,1946,1967,1971,1984,1989,2007,2024,2028,2085],{"__ignoreMap":913},[917,1811,1812],{"class":919,"line":920},[917,1813,1815],{"class":1814},"sLBg1","\u002F\u002F Apply once, surviving timeouts. callApi is the helper at the end of this page.\n",[917,1817,1818,1821,1824,1827,1830,1832,1835,1837,1840,1842,1845],{"class":919,"line":941},[917,1819,1820],{"class":923},"export",[917,1822,1823],{"class":923}," async",[917,1825,1826],{"class":923}," function",[917,1828,1829],{"class":927}," applyOnce",[917,1831,947],{"class":934},[917,1833,1834],{"class":1121},"organizationId",[917,1836,415],{"class":934},[917,1838,1839],{"class":1121},"studentId",[917,1841,415],{"class":934},[917,1843,1844],{"class":1121},"examId",[917,1846,1847],{"class":934},") {\n",[917,1849,1850,1853,1856,1858,1860,1863,1865,1867,1869,1872,1874,1877],{"class":919,"line":957},[917,1851,1852],{"class":923},"  const",[917,1854,1855],{"class":1004}," res",[917,1857,931],{"class":923},[917,1859,1041],{"class":923},[917,1861,1862],{"class":927}," callApi",[917,1864,947],{"class":934},[917,1866,963],{"class":950},[917,1868,415],{"class":934},[917,1870,1871],{"class":950},"`\u002F${",[917,1873,1834],{"class":934},[917,1875,1876],{"class":950},"}\u002Fapplication`",[917,1878,954],{"class":934},[917,1880,1881],{"class":919,"line":969},[917,1882,1883],{"class":934},"    body: { studentId, examId },\n",[917,1885,1886,1889,1891],{"class":919,"line":998},[917,1887,1888],{"class":934},"    repeatable: ",[917,1890,1212],{"class":1004},[917,1892,966],{"class":934},[917,1894,1895],{"class":919,"line":1016},[917,1896,1019],{"class":934},[917,1898,1899,1901,1904,1906,1908,1911,1913],{"class":919,"line":1022},[917,1900,1852],{"class":923},[917,1902,1903],{"class":1004}," body",[917,1905,931],{"class":923},[917,1907,1041],{"class":923},[917,1909,1910],{"class":934}," res.",[917,1912,1194],{"class":927},[917,1914,1046],{"class":934},[917,1916,1917],{"class":919,"line":1029},[917,1918,1026],{"emptyLinePlaceholder":1025},[917,1920,1921,1924,1927,1929,1932,1935,1938,1941,1943],{"class":919,"line":1049},[917,1922,1923],{"class":923},"  if",[917,1925,1926],{"class":934}," (res.status ",[917,1928,1070],{"class":923},[917,1930,1931],{"class":1004}," 201",[917,1933,1934],{"class":934},") ",[917,1936,1937],{"class":923},"return",[917,1939,1940],{"class":934}," { created: ",[917,1942,1212],{"class":1004},[917,1944,1945],{"class":934},", application: body.data };\n",[917,1947,1948,1950,1952,1954,1957,1959,1961,1963,1965],{"class":919,"line":1297},[917,1949,1923],{"class":923},[917,1951,1926],{"class":934},[917,1953,1070],{"class":923},[917,1955,1956],{"class":1004}," 200",[917,1958,1934],{"class":934},[917,1960,1937],{"class":923},[917,1962,1940],{"class":934},[917,1964,1292],{"class":1004},[917,1966,1945],{"class":934},[917,1968,1969],{"class":919,"line":1306},[917,1970,1026],{"emptyLinePlaceholder":1025},[917,1972,1973,1975,1977,1979,1982],{"class":919,"line":1318},[917,1974,1923],{"class":923},[917,1976,1926],{"class":934},[917,1978,1070],{"class":923},[917,1980,1981],{"class":1004}," 409",[917,1983,1847],{"class":934},[917,1985,1986],{"class":919,"line":1330},[917,1987,1988],{"class":1814},"    \u002F\u002F The exam may have closed after an earlier attempt succeeded. Look before giving up.\n",[917,1990,1991,1994,1997,1999,2001,2004],{"class":919,"line":1342},[917,1992,1993],{"class":923},"    const",[917,1995,1996],{"class":1004}," existing",[917,1998,931],{"class":923},[917,2000,1041],{"class":923},[917,2002,2003],{"class":927}," findApplication",[917,2005,2006],{"class":934},"(organizationId, studentId, examId);\n",[917,2008,2009,2012,2015,2017,2019,2021],{"class":919,"line":1354},[917,2010,2011],{"class":923},"    if",[917,2013,2014],{"class":934}," (existing) ",[917,2016,1937],{"class":923},[917,2018,1940],{"class":934},[917,2020,1292],{"class":1004},[917,2022,2023],{"class":934},", application: existing };\n",[917,2025,2026],{"class":919,"line":1366},[917,2027,1467],{"class":934},[917,2029,2030,2033,2036,2039,2041,2044,2047,2049,2052,2055,2058,2060,2063,2065,2067,2070,2072,2074,2076,2078,2080,2082],{"class":919,"line":1378},[917,2031,2032],{"class":923},"  throw",[917,2034,2035],{"class":923}," new",[917,2037,2038],{"class":927}," Error",[917,2040,947],{"class":934},[917,2042,2043],{"class":950},"`${",[917,2045,2046],{"class":934},"res",[917,2048,365],{"class":950},[917,2050,2051],{"class":934},"status",[917,2053,2054],{"class":950},"} ${",[917,2056,2057],{"class":934},"body",[917,2059,365],{"class":950},[917,2061,2062],{"class":934},"error",[917,2064,365],{"class":950},[917,2066,399],{"class":934},[917,2068,2069],{"class":950},"}: ${",[917,2071,2057],{"class":934},[917,2073,365],{"class":950},[917,2075,2062],{"class":934},[917,2077,365],{"class":950},[917,2079,645],{"class":934},[917,2081,981],{"class":950},[917,2083,2084],{"class":934},");\n",[917,2086,2087],{"class":919,"line":1390},[917,2088,1473],{"class":934},[367,2090,623],{"id":2091},"registering-a-student",[358,2093,2094,2096,2097,2100,2101,2103],{},[399,2095,598],{}," is ",[602,2098,2099],{},"not"," idempotent, on purpose. Registering an email address that is already registered is not a repeat, it is two students colliding on one address. So the API refuses it with ",[399,2102,608],{}," rather than returning the existing record as though it had just been created.",[358,2105,2106],{},"That refusal is what you use to recover from a timeout. Send the registration again, and read the answer:",[372,2108,2109,2121],{},[375,2110,2111],{},[378,2112,2113,2116,2119],{},[381,2114,2115],{},"Answer to the second attempt",[381,2117,2118],{},"What it means",[381,2120,389],{},[391,2122,2123,2137,2158],{},[378,2124,2125,2129,2132],{},[396,2126,2127],{},[399,2128,1188],{},[396,2130,2131],{},"The first attempt never landed. This one created the student.",[396,2133,2134,2135,365],{},"Store ",[399,2136,899],{},[378,2138,2139,2146,2149],{},[396,2140,2141,830,2143],{},[399,2142,474],{},[399,2144,2145],{},"A student with that email is already registered to this account (652f1c9b8e4b2a0012a3c4d5).",[396,2147,2148],{},"The first attempt landed, or you had already registered this address. The student is yours either way.",[396,2150,2151,2152,2157],{},"Use the id in the message. Fetch the record with ",[362,2153,2154],{"href":186},[399,2155,2156],{},"GET \u002Fv1\u002Fstudent\u002F{studentId}"," if you need it.",[378,2159,2160,2167,2170],{},[396,2161,2162,830,2164],{},[399,2163,474],{},[399,2165,2166],{},"That email address is already registered.",[396,2168,2169],{},"Another account registered this address. Email addresses are unique across the whole platform.",[396,2171,2172],{},"You cannot use this address. Ask the student for a different one.",[358,2174,2175,2176,2178],{},"The existing student's ",[399,2177,612],{}," appears only in the message, so this is the one place you read it from there. Take the 24-character hex id from between the parentheses:",[908,2180,2182],{"className":910,"code":2181,"language":912,"meta":913,"style":913},"\u002F\u002F Register, or recover the id of a registration that already happened.\nexport async function registerOrRecover(student) {\n  let res;\n  try {\n    res = await callApi('POST', '\u002Fstudent', { body: student, repeatable: false });\n  } catch {\n    \u002F\u002F No answer: the student may exist now. Asking again is safe because of the 409.\n    res = await callApi('POST', '\u002Fstudent', { body: student, repeatable: false });\n  }\n  const body = await res.json();\n\n  if (res.status === 201) return body.data._id;\n  if (res.status === 409) {\n    const yours = \u002F\\(([0-9a-f]{24})\\)\\.?$\u002F.exec(body.error.message);\n    if (yours) return yours[1];\n    throw new Error('This email address belongs to another account.');\n  }\n  throw new Error(`${res.status} ${body.error.code}: ${body.error.message}`);\n}\n",[399,2183,2184,2189,2207,2215,2223,2251,2261,2266,2290,2294,2310,2314,2331,2343,2387,2405,2421,2425,2471],{"__ignoreMap":913},[917,2185,2186],{"class":919,"line":920},[917,2187,2188],{"class":1814},"\u002F\u002F Register, or recover the id of a registration that already happened.\n",[917,2190,2191,2193,2195,2197,2200,2202,2205],{"class":919,"line":941},[917,2192,1820],{"class":923},[917,2194,1823],{"class":923},[917,2196,1826],{"class":923},[917,2198,2199],{"class":927}," registerOrRecover",[917,2201,947],{"class":934},[917,2203,2204],{"class":1121},"student",[917,2206,1847],{"class":934},[917,2208,2209,2212],{"class":919,"line":957},[917,2210,2211],{"class":923},"  let",[917,2213,2214],{"class":934}," res;\n",[917,2216,2217,2220],{"class":919,"line":969},[917,2218,2219],{"class":923},"  try",[917,2221,2222],{"class":934}," {\n",[917,2224,2225,2228,2230,2232,2234,2236,2238,2240,2243,2246,2248],{"class":919,"line":998},[917,2226,2227],{"class":934},"    res ",[917,2229,1038],{"class":923},[917,2231,1041],{"class":923},[917,2233,1862],{"class":927},[917,2235,947],{"class":934},[917,2237,963],{"class":950},[917,2239,415],{"class":934},[917,2241,2242],{"class":950},"'\u002Fstudent'",[917,2244,2245],{"class":934},", { body: student, repeatable: ",[917,2247,1292],{"class":1004},[917,2249,2250],{"class":934}," });\n",[917,2252,2253,2256,2259],{"class":919,"line":1016},[917,2254,2255],{"class":934},"  } ",[917,2257,2258],{"class":923},"catch",[917,2260,2222],{"class":934},[917,2262,2263],{"class":919,"line":1022},[917,2264,2265],{"class":1814},"    \u002F\u002F No answer: the student may exist now. Asking again is safe because of the 409.\n",[917,2267,2268,2270,2272,2274,2276,2278,2280,2282,2284,2286,2288],{"class":919,"line":1029},[917,2269,2227],{"class":934},[917,2271,1038],{"class":923},[917,2273,1041],{"class":923},[917,2275,1862],{"class":927},[917,2277,947],{"class":934},[917,2279,963],{"class":950},[917,2281,415],{"class":934},[917,2283,2242],{"class":950},[917,2285,2245],{"class":934},[917,2287,1292],{"class":1004},[917,2289,2250],{"class":934},[917,2291,2292],{"class":919,"line":1049},[917,2293,1467],{"class":934},[917,2295,2296,2298,2300,2302,2304,2306,2308],{"class":919,"line":1297},[917,2297,1852],{"class":923},[917,2299,1903],{"class":1004},[917,2301,931],{"class":923},[917,2303,1041],{"class":923},[917,2305,1910],{"class":934},[917,2307,1194],{"class":927},[917,2309,1046],{"class":934},[917,2311,2312],{"class":919,"line":1306},[917,2313,1026],{"emptyLinePlaceholder":1025},[917,2315,2316,2318,2320,2322,2324,2326,2328],{"class":919,"line":1318},[917,2317,1923],{"class":923},[917,2319,1926],{"class":934},[917,2321,1070],{"class":923},[917,2323,1931],{"class":1004},[917,2325,1934],{"class":934},[917,2327,1937],{"class":923},[917,2329,2330],{"class":934}," body.data._id;\n",[917,2332,2333,2335,2337,2339,2341],{"class":919,"line":1330},[917,2334,1923],{"class":923},[917,2336,1926],{"class":934},[917,2338,1070],{"class":923},[917,2340,1981],{"class":1004},[917,2342,1847],{"class":934},[917,2344,2345,2347,2350,2352,2355,2359,2361,2364,2367,2370,2373,2376,2379,2381,2384],{"class":919,"line":1342},[917,2346,1993],{"class":923},[917,2348,2349],{"class":1004}," yours",[917,2351,931],{"class":923},[917,2353,2354],{"class":950}," \u002F",[917,2356,2358],{"class":2357},"sJaa3","\\(",[917,2360,947],{"class":950},[917,2362,2363],{"class":1004},"[0-9a-f]",[917,2365,2366],{"class":923},"{24}",[917,2368,2369],{"class":950},")",[917,2371,2372],{"class":2357},"\\)\\.",[917,2374,2375],{"class":923},"?$",[917,2377,2378],{"class":950},"\u002F",[917,2380,365],{"class":934},[917,2382,2383],{"class":927},"exec",[917,2385,2386],{"class":934},"(body.error.message);\n",[917,2388,2389,2391,2394,2396,2399,2402],{"class":919,"line":1354},[917,2390,2011],{"class":923},[917,2392,2393],{"class":934}," (yours) ",[917,2395,1937],{"class":923},[917,2397,2398],{"class":934}," yours[",[917,2400,2401],{"class":1004},"1",[917,2403,2404],{"class":934},"];\n",[917,2406,2407,2410,2412,2414,2416,2419],{"class":919,"line":1366},[917,2408,2409],{"class":923},"    throw",[917,2411,2035],{"class":923},[917,2413,2038],{"class":927},[917,2415,947],{"class":934},[917,2417,2418],{"class":950},"'This email address belongs to another account.'",[917,2420,2084],{"class":934},[917,2422,2423],{"class":919,"line":1378},[917,2424,1467],{"class":934},[917,2426,2427,2429,2431,2433,2435,2437,2439,2441,2443,2445,2447,2449,2451,2453,2455,2457,2459,2461,2463,2465,2467,2469],{"class":919,"line":1390},[917,2428,2032],{"class":923},[917,2430,2035],{"class":923},[917,2432,2038],{"class":927},[917,2434,947],{"class":934},[917,2436,2043],{"class":950},[917,2438,2046],{"class":934},[917,2440,365],{"class":950},[917,2442,2051],{"class":934},[917,2444,2054],{"class":950},[917,2446,2057],{"class":934},[917,2448,365],{"class":950},[917,2450,2062],{"class":934},[917,2452,365],{"class":950},[917,2454,399],{"class":934},[917,2456,2069],{"class":950},[917,2458,2057],{"class":934},[917,2460,365],{"class":950},[917,2462,2062],{"class":934},[917,2464,365],{"class":950},[917,2466,645],{"class":934},[917,2468,981],{"class":950},[917,2470,2084],{"class":934},[917,2472,2473],{"class":919,"line":1403},[917,2474,1473],{"class":934},[908,2476,2480],{"className":2477,"code":2478,"language":2479,"meta":913,"style":913},"language-php shiki shiki-themes github-light-high-contrast github-dark-high-contrast","\u003C?php\n\u002F\u002F Register, or recover the id of a registration that already happened.\nfunction registerOrRecover(array $student): string\n{\n    try {\n        $res = callApi('POST', '\u002Fstudent', $student, false);\n    } catch (RuntimeException $noAnswer) {\n        $res = callApi('POST', '\u002Fstudent', $student, false);\n    }\n\n    if ($res['status'] === 201) {\n        return $res['body']['data']['_id'];\n    }\n    if ($res['status'] === 409) {\n        if (preg_match('\u002F\\(([0-9a-f]{24})\\)\\.?$\u002F', $res['body']['error']['message'], $m)) {\n            return $m[1];\n        }\n        throw new RuntimeException('This email address belongs to another account.');\n    }\n    throw new RuntimeException($res['status'] . ' ' . $res['body']['error']['code']);\n}\n","php",[399,2481,2482,2490,2494,2514,2518,2525,2549,2565,2587,2592,2596,2615,2639,2643,2659,2708,2720,2725,2741,2745,2784],{"__ignoreMap":913},[917,2483,2484,2487],{"class":919,"line":920},[917,2485,2486],{"class":923},"\u003C?",[917,2488,2489],{"class":1004},"php\n",[917,2491,2492],{"class":919,"line":941},[917,2493,2188],{"class":1814},[917,2495,2496,2499,2501,2503,2506,2509,2511],{"class":919,"line":957},[917,2497,2498],{"class":923},"function",[917,2500,2199],{"class":927},[917,2502,947],{"class":934},[917,2504,2505],{"class":923},"array",[917,2507,2508],{"class":934}," $student)",[917,2510,1189],{"class":923},[917,2512,2513],{"class":923}," string\n",[917,2515,2516],{"class":919,"line":969},[917,2517,1201],{"class":934},[917,2519,2520,2523],{"class":919,"line":998},[917,2521,2522],{"class":923},"    try",[917,2524,2222],{"class":934},[917,2526,2527,2530,2532,2534,2536,2538,2540,2542,2545,2547],{"class":919,"line":1016},[917,2528,2529],{"class":934},"        $res ",[917,2531,1038],{"class":923},[917,2533,1862],{"class":927},[917,2535,947],{"class":934},[917,2537,963],{"class":950},[917,2539,415],{"class":934},[917,2541,2242],{"class":950},[917,2543,2544],{"class":934},", $student, ",[917,2546,1292],{"class":1004},[917,2548,2084],{"class":934},[917,2550,2551,2554,2556,2559,2562],{"class":919,"line":1022},[917,2552,2553],{"class":934},"    } ",[917,2555,2258],{"class":923},[917,2557,2558],{"class":934}," (",[917,2560,2561],{"class":1004},"RuntimeException",[917,2563,2564],{"class":934}," $noAnswer) {\n",[917,2566,2567,2569,2571,2573,2575,2577,2579,2581,2583,2585],{"class":919,"line":1029},[917,2568,2529],{"class":934},[917,2570,1038],{"class":923},[917,2572,1862],{"class":927},[917,2574,947],{"class":934},[917,2576,963],{"class":950},[917,2578,415],{"class":934},[917,2580,2242],{"class":950},[917,2582,2544],{"class":934},[917,2584,1292],{"class":1004},[917,2586,2084],{"class":934},[917,2588,2589],{"class":919,"line":1049},[917,2590,2591],{"class":934},"    }\n",[917,2593,2594],{"class":919,"line":1297},[917,2595,1026],{"emptyLinePlaceholder":1025},[917,2597,2598,2600,2603,2606,2609,2611,2613],{"class":919,"line":1306},[917,2599,2011],{"class":923},[917,2601,2602],{"class":934}," ($res[",[917,2604,2605],{"class":950},"'status'",[917,2607,2608],{"class":934},"] ",[917,2610,1070],{"class":923},[917,2612,1931],{"class":1004},[917,2614,1847],{"class":934},[917,2616,2617,2620,2623,2626,2629,2632,2634,2637],{"class":919,"line":1318},[917,2618,2619],{"class":923},"        return",[917,2621,2622],{"class":934}," $res[",[917,2624,2625],{"class":950},"'body'",[917,2627,2628],{"class":934},"][",[917,2630,2631],{"class":950},"'data'",[917,2633,2628],{"class":934},[917,2635,2636],{"class":950},"'_id'",[917,2638,2404],{"class":934},[917,2640,2641],{"class":919,"line":1330},[917,2642,2591],{"class":934},[917,2644,2645,2647,2649,2651,2653,2655,2657],{"class":919,"line":1342},[917,2646,2011],{"class":923},[917,2648,2602],{"class":934},[917,2650,2605],{"class":950},[917,2652,2608],{"class":934},[917,2654,1070],{"class":923},[917,2656,1981],{"class":1004},[917,2658,1847],{"class":934},[917,2660,2661,2664,2666,2669,2671,2674,2676,2679,2681,2684,2687,2690,2693,2695,2697,2700,2702,2705],{"class":919,"line":1354},[917,2662,2663],{"class":923},"        if",[917,2665,2558],{"class":934},[917,2667,2668],{"class":1004},"preg_match",[917,2670,947],{"class":934},[917,2672,2673],{"class":950},"'\u002F",[917,2675,2358],{"class":2357},[917,2677,2678],{"class":950},"([0-9a-f]{24})",[917,2680,2372],{"class":2357},[917,2682,2683],{"class":950},"?",[917,2685,2686],{"class":923},"$",[917,2688,2689],{"class":950},"\u002F'",[917,2691,2692],{"class":934},", $res[",[917,2694,2625],{"class":950},[917,2696,2628],{"class":934},[917,2698,2699],{"class":950},"'error'",[917,2701,2628],{"class":934},[917,2703,2704],{"class":950},"'message'",[917,2706,2707],{"class":934},"], $m)) {\n",[917,2709,2710,2713,2716,2718],{"class":919,"line":1366},[917,2711,2712],{"class":923},"            return",[917,2714,2715],{"class":934}," $m[",[917,2717,2401],{"class":1004},[917,2719,2404],{"class":934},[917,2721,2722],{"class":919,"line":1378},[917,2723,2724],{"class":934},"        }\n",[917,2726,2727,2730,2732,2735,2737,2739],{"class":919,"line":1390},[917,2728,2729],{"class":923},"        throw",[917,2731,2035],{"class":923},[917,2733,2734],{"class":1004}," RuntimeException",[917,2736,947],{"class":934},[917,2738,2418],{"class":950},[917,2740,2084],{"class":934},[917,2742,2743],{"class":919,"line":1403},[917,2744,2591],{"class":934},[917,2746,2747,2749,2751,2753,2756,2758,2760,2762,2765,2768,2770,2772,2774,2776,2778,2781],{"class":919,"line":1416},[917,2748,2409],{"class":923},[917,2750,2035],{"class":923},[917,2752,2734],{"class":1004},[917,2754,2755],{"class":934},"($res[",[917,2757,2605],{"class":950},[917,2759,2608],{"class":934},[917,2761,365],{"class":923},[917,2763,2764],{"class":950}," ' '",[917,2766,2767],{"class":923}," .",[917,2769,2622],{"class":934},[917,2771,2625],{"class":950},[917,2773,2628],{"class":934},[917,2775,2699],{"class":950},[917,2777,2628],{"class":934},[917,2779,2780],{"class":950},"'code'",[917,2782,2783],{"class":934},"]);\n",[917,2785,2786],{"class":919,"line":1428},[917,2787,1473],{"class":934},[358,2789,2790],{},"A few more things matter for registration:",[2792,2793,2794,2802,2815],"ul",{},[1738,2795,2796,2801],{},[602,2797,2798,2799,365],{},"Keep your own mapping from email address to student ",[399,2800,612],{}," No operation looks a student up by email, so the id you store at registration is how you find them again.",[1738,2803,2804,2807,2808,595,2810,2814],{},[602,2805,2806],{},"Register one address from one worker at a time."," If two of your workers register the same new address at the same moment, one of them gets the ",[399,2809,474],{},[2811,2812,2813],"em",{},"without"," an id, as though another account held it.",[1738,2816,2817,2820,2821,2824],{},[602,2818,2819],{},"Allow time for a password."," When the body carries a ",[399,2822,2823],{},"password",", the API hashes it with a deliberately slow algorithm, so the request takes noticeably longer (often more than a second). A 30-second read timeout is comfortable.",[367,2826,2828],{"id":2827},"updating-a-student","Updating a student",[358,2830,2831],{},"Both student updates are partial: send only the fields you are changing, and fields you leave out keep their value. The same body sent twice gives the same result, so both are safe to retry.",[2792,2833,2834,2840,2847,2857],{},[1738,2835,2836,2839],{},[602,2837,2838],{},"Changing the email address withdraws the student's email confirmation",", because nobody has proved the new address yet. A repeat carrying the same new address is not a change, so it doesn't withdraw anything a second time. Re-sending the address a student already has, in any letter case, never withdraws it.",[1738,2841,2842,2846],{},[602,2843,2844],{},[399,2845,679],{}," also adds that organization to the student's access list. A repeat doesn't add it twice.",[1738,2848,2849,2853,2854,2856],{},[602,2850,2851],{},[399,2852,694],{}," sets the same password again on a repeat. If the student confirms their email address between your attempts, the repeat answers ",[399,2855,608],{},". Stop there: the account is the student's now. Like registration, this request takes longer than others because of the password hashing.",[1738,2858,2859,2863,2864,2866],{},[602,2860,2861],{},[399,2862,712],{}," links the same supervisor again and answers ",[399,2865,718],{}," with the same result.",[367,2868,2870],{"id":2869},"moving-an-application","Moving an application",[358,2872,2873,2875],{},[399,2874,778],{}," moves an application to another exam. If the application already points at the exam you send, the API answers without writing anything:",[908,2877,2879],{"className":1192,"code":2878,"language":1194,"meta":913,"style":913},"{\n  \"success\": true,\n  \"message\": \"Application already uses that exam.\",\n  \"data\": {\n    \"_id\": \"66c3e5f7a9b1c2d3e4f50617\",\n    \"exam\": \"64a1f0b2c9d8e7f600445566\",\n    \"user\": \"66a0b1c2d3e4f5a6b7c8d9e0\",\n    \"payment\": \"66c3e5f7a9b1c2d3e4f50618\",\n    \"ExamBucksRedeemed\": false,\n    \"partners\": [],\n    \"definedQuota\": false,\n    \"participated\": false,\n    \"reversable\": false,\n    \"simulationStarted\": false,\n    \"simulationSubmitted\": false,\n    \"simulationV2Enabled\": false,\n    \"isSimulationV2\": false,\n    \"carriedPoints\": 0,\n    \"uuid\": \"3fa-9c1-e07\",\n    \"cameraRecord\": false,\n    \"createdAt\": \"2026-09-15T09:30:02.511Z\",\n    \"updatedAt\": \"2026-09-15T09:41:17.020Z\",\n    \"__v\": 0\n  }\n}\n",[399,2880,2881,2885,2895,2906,2912,2922,2933,2943,2953,2963,2969,2979,2989,2999,3009,3019,3029,3039,3049,3059,3069,3079,3090,3098,3102],{"__ignoreMap":913},[917,2882,2883],{"class":919,"line":920},[917,2884,1201],{"class":934},[917,2886,2887,2889,2891,2893],{"class":919,"line":941},[917,2888,1207],{"class":1206},[917,2890,989],{"class":934},[917,2892,1212],{"class":1004},[917,2894,966],{"class":934},[917,2896,2897,2899,2901,2904],{"class":919,"line":957},[917,2898,1219],{"class":1206},[917,2900,989],{"class":934},[917,2902,2903],{"class":950},"\"Application already uses that exam.\"",[917,2905,966],{"class":934},[917,2907,2908,2910],{"class":919,"line":969},[917,2909,1231],{"class":1206},[917,2911,1234],{"class":934},[917,2913,2914,2916,2918,2920],{"class":919,"line":998},[917,2915,1239],{"class":1206},[917,2917,989],{"class":934},[917,2919,1244],{"class":950},[917,2921,966],{"class":934},[917,2923,2924,2926,2928,2931],{"class":919,"line":1016},[917,2925,1251],{"class":1206},[917,2927,989],{"class":934},[917,2929,2930],{"class":950},"\"64a1f0b2c9d8e7f600445566\"",[917,2932,966],{"class":934},[917,2934,2935,2937,2939,2941],{"class":919,"line":1022},[917,2936,1263],{"class":1206},[917,2938,989],{"class":934},[917,2940,1268],{"class":950},[917,2942,966],{"class":934},[917,2944,2945,2947,2949,2951],{"class":919,"line":1029},[917,2946,1275],{"class":1206},[917,2948,989],{"class":934},[917,2950,1280],{"class":950},[917,2952,966],{"class":934},[917,2954,2955,2957,2959,2961],{"class":919,"line":1049},[917,2956,1287],{"class":1206},[917,2958,989],{"class":934},[917,2960,1292],{"class":1004},[917,2962,966],{"class":934},[917,2964,2965,2967],{"class":919,"line":1297},[917,2966,1300],{"class":1206},[917,2968,1303],{"class":934},[917,2970,2971,2973,2975,2977],{"class":919,"line":1306},[917,2972,1309],{"class":1206},[917,2974,989],{"class":934},[917,2976,1292],{"class":1004},[917,2978,966],{"class":934},[917,2980,2981,2983,2985,2987],{"class":919,"line":1318},[917,2982,1321],{"class":1206},[917,2984,989],{"class":934},[917,2986,1292],{"class":1004},[917,2988,966],{"class":934},[917,2990,2991,2993,2995,2997],{"class":919,"line":1330},[917,2992,1333],{"class":1206},[917,2994,989],{"class":934},[917,2996,1292],{"class":1004},[917,2998,966],{"class":934},[917,3000,3001,3003,3005,3007],{"class":919,"line":1342},[917,3002,1345],{"class":1206},[917,3004,989],{"class":934},[917,3006,1292],{"class":1004},[917,3008,966],{"class":934},[917,3010,3011,3013,3015,3017],{"class":919,"line":1354},[917,3012,1357],{"class":1206},[917,3014,989],{"class":934},[917,3016,1292],{"class":1004},[917,3018,966],{"class":934},[917,3020,3021,3023,3025,3027],{"class":919,"line":1366},[917,3022,1369],{"class":1206},[917,3024,989],{"class":934},[917,3026,1292],{"class":1004},[917,3028,966],{"class":934},[917,3030,3031,3033,3035,3037],{"class":919,"line":1378},[917,3032,1381],{"class":1206},[917,3034,989],{"class":934},[917,3036,1292],{"class":1004},[917,3038,966],{"class":934},[917,3040,3041,3043,3045,3047],{"class":919,"line":1390},[917,3042,1393],{"class":1206},[917,3044,989],{"class":934},[917,3046,1398],{"class":1004},[917,3048,966],{"class":934},[917,3050,3051,3053,3055,3057],{"class":919,"line":1403},[917,3052,1406],{"class":1206},[917,3054,989],{"class":934},[917,3056,1411],{"class":950},[917,3058,966],{"class":934},[917,3060,3061,3063,3065,3067],{"class":919,"line":1416},[917,3062,1419],{"class":1206},[917,3064,989],{"class":934},[917,3066,1292],{"class":1004},[917,3068,966],{"class":934},[917,3070,3071,3073,3075,3077],{"class":919,"line":1428},[917,3072,1431],{"class":1206},[917,3074,989],{"class":934},[917,3076,1436],{"class":950},[917,3078,966],{"class":934},[917,3080,3081,3083,3085,3088],{"class":919,"line":1441},[917,3082,1444],{"class":1206},[917,3084,989],{"class":934},[917,3086,3087],{"class":950},"\"2026-09-15T09:41:17.020Z\"",[917,3089,966],{"class":934},[917,3091,3092,3094,3096],{"class":919,"line":1453},[917,3093,1456],{"class":1206},[917,3095,989],{"class":934},[917,3097,1461],{"class":1004},[917,3099,3100],{"class":919,"line":1464},[917,3101,1467],{"class":934},[917,3103,3104],{"class":919,"line":1470},[917,3105,1473],{"class":934},[358,3107,3108,3109,3112,3113,3115],{},"So after a move that timed out, send it again. ",[399,3110,3111],{},"200 \"Application updated successfully.\""," means the first attempt didn't land and this one did. ",[399,3114,787],{}," means the first one did. Either way the application now has the exam you asked for.",[358,3117,3118,3119,3121,3122,830,3124,3127,3128,365],{},"This check comes before the eligibility rules, so a repeat still answers ",[399,3120,718],{}," if the exam has closed since your first attempt. Only one earlier check can change the answer: once the student has started or handed in the exam, every move of that application answers ",[399,3123,608],{},[399,3125,3126],{},"This exam has already been started and can no longer be changed.",", even a move to the exam it already has. The rules a move has to pass are in ",[362,3129,86],{"href":87},[367,3131,467],{"id":3132},"deleting-an-application",[358,3134,3135,3136,3138,3139,3141],{},"The first ",[399,3137,254],{}," removes the application and answers ",[399,3140,718],{}," with the deleted record:",[908,3143,3145],{"className":1192,"code":3144,"language":1194,"meta":913,"style":913},"{\n  \"success\": true,\n  \"message\": \"Application deleted successfully.\",\n  \"data\": {\n    \"_id\": \"66c3e5f7a9b1c2d3e4f50617\",\n    \"exam\": \"64a1f0b2c9d8e7f600112233\",\n    \"user\": \"66a0b1c2d3e4f5a6b7c8d9e0\",\n    \"payment\": \"66c3e5f7a9b1c2d3e4f50618\",\n    \"ExamBucksRedeemed\": false,\n    \"partners\": [],\n    \"definedQuota\": false,\n    \"participated\": false,\n    \"reversable\": false,\n    \"simulationStarted\": false,\n    \"simulationSubmitted\": false,\n    \"simulationV2Enabled\": false,\n    \"isSimulationV2\": false,\n    \"carriedPoints\": 0,\n    \"uuid\": \"3fa-9c1-e07\",\n    \"cameraRecord\": false,\n    \"createdAt\": \"2026-09-15T09:30:02.511Z\",\n    \"updatedAt\": \"2026-09-15T09:30:02.511Z\",\n    \"__v\": 0\n  }\n}\n",[399,3146,3147,3151,3161,3172,3178,3188,3198,3208,3218,3228,3234,3244,3254,3264,3274,3284,3294,3304,3314,3324,3334,3344,3354,3362,3366],{"__ignoreMap":913},[917,3148,3149],{"class":919,"line":920},[917,3150,1201],{"class":934},[917,3152,3153,3155,3157,3159],{"class":919,"line":941},[917,3154,1207],{"class":1206},[917,3156,989],{"class":934},[917,3158,1212],{"class":1004},[917,3160,966],{"class":934},[917,3162,3163,3165,3167,3170],{"class":919,"line":957},[917,3164,1219],{"class":1206},[917,3166,989],{"class":934},[917,3168,3169],{"class":950},"\"Application deleted successfully.\"",[917,3171,966],{"class":934},[917,3173,3174,3176],{"class":919,"line":969},[917,3175,1231],{"class":1206},[917,3177,1234],{"class":934},[917,3179,3180,3182,3184,3186],{"class":919,"line":998},[917,3181,1239],{"class":1206},[917,3183,989],{"class":934},[917,3185,1244],{"class":950},[917,3187,966],{"class":934},[917,3189,3190,3192,3194,3196],{"class":919,"line":1016},[917,3191,1251],{"class":1206},[917,3193,989],{"class":934},[917,3195,1256],{"class":950},[917,3197,966],{"class":934},[917,3199,3200,3202,3204,3206],{"class":919,"line":1022},[917,3201,1263],{"class":1206},[917,3203,989],{"class":934},[917,3205,1268],{"class":950},[917,3207,966],{"class":934},[917,3209,3210,3212,3214,3216],{"class":919,"line":1029},[917,3211,1275],{"class":1206},[917,3213,989],{"class":934},[917,3215,1280],{"class":950},[917,3217,966],{"class":934},[917,3219,3220,3222,3224,3226],{"class":919,"line":1049},[917,3221,1287],{"class":1206},[917,3223,989],{"class":934},[917,3225,1292],{"class":1004},[917,3227,966],{"class":934},[917,3229,3230,3232],{"class":919,"line":1297},[917,3231,1300],{"class":1206},[917,3233,1303],{"class":934},[917,3235,3236,3238,3240,3242],{"class":919,"line":1306},[917,3237,1309],{"class":1206},[917,3239,989],{"class":934},[917,3241,1292],{"class":1004},[917,3243,966],{"class":934},[917,3245,3246,3248,3250,3252],{"class":919,"line":1318},[917,3247,1321],{"class":1206},[917,3249,989],{"class":934},[917,3251,1292],{"class":1004},[917,3253,966],{"class":934},[917,3255,3256,3258,3260,3262],{"class":919,"line":1330},[917,3257,1333],{"class":1206},[917,3259,989],{"class":934},[917,3261,1292],{"class":1004},[917,3263,966],{"class":934},[917,3265,3266,3268,3270,3272],{"class":919,"line":1342},[917,3267,1345],{"class":1206},[917,3269,989],{"class":934},[917,3271,1292],{"class":1004},[917,3273,966],{"class":934},[917,3275,3276,3278,3280,3282],{"class":919,"line":1354},[917,3277,1357],{"class":1206},[917,3279,989],{"class":934},[917,3281,1292],{"class":1004},[917,3283,966],{"class":934},[917,3285,3286,3288,3290,3292],{"class":919,"line":1366},[917,3287,1369],{"class":1206},[917,3289,989],{"class":934},[917,3291,1292],{"class":1004},[917,3293,966],{"class":934},[917,3295,3296,3298,3300,3302],{"class":919,"line":1378},[917,3297,1381],{"class":1206},[917,3299,989],{"class":934},[917,3301,1292],{"class":1004},[917,3303,966],{"class":934},[917,3305,3306,3308,3310,3312],{"class":919,"line":1390},[917,3307,1393],{"class":1206},[917,3309,989],{"class":934},[917,3311,1398],{"class":1004},[917,3313,966],{"class":934},[917,3315,3316,3318,3320,3322],{"class":919,"line":1403},[917,3317,1406],{"class":1206},[917,3319,989],{"class":934},[917,3321,1411],{"class":950},[917,3323,966],{"class":934},[917,3325,3326,3328,3330,3332],{"class":919,"line":1416},[917,3327,1419],{"class":1206},[917,3329,989],{"class":934},[917,3331,1292],{"class":1004},[917,3333,966],{"class":934},[917,3335,3336,3338,3340,3342],{"class":919,"line":1428},[917,3337,1431],{"class":1206},[917,3339,989],{"class":934},[917,3341,1436],{"class":950},[917,3343,966],{"class":934},[917,3345,3346,3348,3350,3352],{"class":919,"line":1441},[917,3347,1444],{"class":1206},[917,3349,989],{"class":934},[917,3351,1436],{"class":950},[917,3353,966],{"class":934},[917,3355,3356,3358,3360],{"class":919,"line":1453},[917,3357,1456],{"class":1206},[917,3359,989],{"class":934},[917,3361,1461],{"class":1004},[917,3363,3364],{"class":919,"line":1464},[917,3365,1467],{"class":934},[917,3367,3368],{"class":919,"line":1470},[917,3369,1473],{"class":934},[358,3371,3372,3373,830,3375,3378,3379,3381],{},"A repeat answers ",[399,3374,1743],{},[399,3376,3377],{},"Application not found!",". If you got the id from the API and the delete timed out, a ",[399,3380,458],{}," on the retry means the application is gone, most likely because your first attempt worked.",[358,3383,553,3384,3386],{},[399,3385,608],{}," on a delete means the application has been paid for. The API does not delete paid applications, because that would need a refund it cannot make. Retrying won't change that.",[367,3388,839],{"id":3389},"group-challenge-submits",[358,3391,3392,3397,3398,3403,3404,830,3406,3408,3409,1189],{},[362,3393,3394],{"href":294},[399,3395,3396],{},"submitGroupChallengeStep"," and ",[362,3399,3400],{"href":291},[399,3401,3402],{},"submitGroupChallengeWork"," are safe to send again. A submit that already happened — your earlier attempt, a member in the panel, another request — answers ",[399,3405,718],{},[399,3407,833],{},", so after a timeout, send it again and read ",[399,3410,3411],{},"changed",[372,3413,3414,3422],{},[375,3415,3416],{},[378,3417,3418,3420],{},[381,3419,2115],{},[381,3421,2118],{},[391,3423,3424,3436,3447,3462],{},[378,3425,3426,3433],{},[396,3427,3428,415,3430],{},[399,3429,718],{},[399,3431,3432],{},"changed: true",[396,3434,3435],{},"The first attempt never landed; this one did the submit.",[378,3437,3438,3444],{},[396,3439,3440,415,3442],{},[399,3441,718],{},[399,3443,833],{},[396,3445,3446],{},"It was already done, by your first attempt or by someone else. Nothing changed.",[378,3448,3449,3456],{},[396,3450,3451,415,3453],{},[399,3452,521],{},[399,3454,3455],{},"details.reason: busy",[396,3457,3458,3459,3461],{},"Someone was changing the group at that moment; nothing was written. Wait the second in ",[399,3460,497],{}," and send it again.",[378,3463,3464,3468],{},[396,3465,3466],{},[399,3467,474],{},[396,3469,3470,3471,3474,3475,365],{},"The group's state refuses it; ",[399,3472,3473],{},"details.reason"," says why. Don't retry unchanged. See ",[362,3476,3478],{"href":3477},"\u002Fapi\u002Ferrors#conflict","conflict",[367,3480,3482],{"id":3481},"sign-in-links-retry-the-request-never-the-link","Sign-in links: retry the request, never the link",[358,3484,3485,3487],{},[399,3486,731],{}," mints a new link every time you call it. Retrying the request is harmless: any link you didn't use expires on its own after 120 seconds.",[358,3489,3490,3491,3494,3495,3498],{},"The link itself is different. It works ",[602,3492,3493],{},"once",", for ",[602,3496,3497],{},"120 seconds",". Once a browser has opened it, opening it again fails. The student sees an \"Invalid or expired access token\" message instead of their panel. So:",[2792,3500,3501,3504,3507],{},[1738,3502,3503],{},"Never retry a redirect with the same URL. Mint a new link.",[1738,3505,3506],{},"Mint the link when the student clicks, and redirect at once. Don't generate links ahead of time.",[1738,3508,3509],{},"Keep links away from anything that fetches URLs on its own, such as chat previews, email scanners and browser prefetch. A fetch like that uses the link up.",[358,3511,3512,3513,3516,3517,3520,3521,3523],{},"If minting fails with ",[399,3514,3515],{},"500 internal_error"," and the message ",[399,3518,3519],{},"Could not issue a sign-in token, please retry.",", retry straight away. Nothing was issued. See ",[362,3522,80],{"href":81}," for the whole flow.",[367,3525,3527],{"id":3526},"downloads","Downloads",[358,3529,3530,3397,3533,3536],{},[399,3531,3532],{},"GET ...\u002Fcertificate\u002Fdownload\u002F{certificateId}",[399,3534,3535],{},"GET ...\u002Freport\u002Fdownload\u002F{reportId}"," stream a PDF.",[2792,3538,3539,3545,3555],{},[1738,3540,3541,3544],{},[602,3542,3543],{},"An error arrives before any bytes",", as the usual JSON error envelope with its status. Handle it like any other error.",[1738,3546,3547,3550,3551,3554],{},[602,3548,3549],{},"A failure after the file has started"," can't be reported with a status any more, so the API closes the connection early. Your client sees a transfer that ends before ",[399,3552,3553],{},"Content-Length"," bytes (when the header is present) or with a network error. Throw the partial file away and download it again.",[1738,3556,3557,3560],{},[602,3558,3559],{},"Every download starts from the first byte."," The API always sends the whole file and doesn't serve byte ranges, so you can't resume a partial download.",[358,3562,3563],{},"Write to a temporary file and rename it only once the transfer has completed, so a truncated PDF never looks like a finished one.",[367,3565,3567],{"id":3566},"timeouts","Timeouts",[372,3569,3570,3583],{},[375,3571,3572],{},[378,3573,3574,3577,3580],{},[381,3575,3576],{},"Setting",[381,3578,3579],{},"Suggested value",[381,3581,3582],{},"Why",[391,3584,3585,3596,3607],{},[378,3586,3587,3590,3593],{},[396,3588,3589],{},"Connect timeout",[396,3591,3592],{},"5 s",[396,3594,3595],{},"Fail fast when the network is the problem.",[378,3597,3598,3601,3604],{},[396,3599,3600],{},"Read timeout, JSON operations",[396,3602,3603],{},"30 s",[396,3605,3606],{},"Covers the slowest ordinary request, a registration or password change with hashing.",[378,3608,3609,3612,3615],{},[396,3610,3611],{},"Read timeout, downloads",[396,3613,3614],{},"120 s or more, depending on file size",[396,3616,3617],{},"PDFs are streamed.",[358,3619,3620],{},"The API expects to receive your whole request, headers and body, within 30 seconds of you starting to send it. Don't stream request bodies slowly. Reuse connections (HTTP keep-alive) rather than opening a new one for each request.",[534,3622,3623],{"type":536},[358,3624,3625,3626,3628],{},"A timeout is not a failure. It only means you didn't see the answer. Treat it like a ",[399,3627,505],{},": retry if the operation is safe to repeat, and check first if it isn't.",[367,3630,3632],{"id":3631},"backing-off","Backing off",[358,3634,3635],{},"Wait longer after each failed attempt, and add randomness so that many clients (or many workers of yours) don't retry in lockstep:",[908,3637,3642],{"className":3638,"code":3640,"language":3641},[3639],"language-text","delay = random(0.5, 1.0) × min(30 s, 1 s × 2^attempt)\n","text",[399,3643,3640],{"__ignoreMap":913},[372,3645,3646,3656],{},[375,3647,3648],{},[378,3649,3650,3653],{},[381,3651,3652],{},"Attempt that failed",[381,3654,3655],{},"Wait before the next one",[391,3657,3658,3666,3674,3682,3690],{},[378,3659,3660,3663],{},[396,3661,3662],{},"1st",[396,3664,3665],{},"0.5–1 s",[378,3667,3668,3671],{},[396,3669,3670],{},"2nd",[396,3672,3673],{},"1–2 s",[378,3675,3676,3679],{},[396,3677,3678],{},"3rd",[396,3680,3681],{},"2–4 s",[378,3683,3684,3687],{},[396,3685,3686],{},"4th",[396,3688,3689],{},"4–8 s",[378,3691,3692,3695],{},[396,3693,3694],{},"5th",[396,3696,3697],{},"give up and alert",[358,3699,3700],{},"Three rules sit on top of that:",[2792,3702,3703,3714,3720],{},[1738,3704,3705,3710,3711,3713],{},[602,3706,3707,3709],{},[399,3708,497],{}," wins."," On a ",[399,3712,489],{},", wait at least the number of seconds the header gives. A request sent sooner is refused too.",[1738,3715,3716,3719],{},[602,3717,3718],{},"Cap the attempts."," Five in total is plenty. After that, stop and alert a person. Retrying forever turns an outage into a flood.",[1738,3721,3722,3725,3726,3728],{},[602,3723,3724],{},"Pause a whole batch when many requests fail."," If several requests in a row come back ",[399,3727,549],{},", stop the batch. Then check the API in two steps before you resume.",[358,3730,3731,3732,3737],{},"First, ",[362,3733,3734],{"href":132},[399,3735,3736],{},"GET \u002Fv1\u002Fhealth"," tells you whether the API is reachable at all. It needs no token and doesn't count against your rate limit:",[908,3739,3741],{"className":1112,"code":3740,"language":1114,"meta":913,"style":913},"curl https:\u002F\u002Fapi.main-team.org\u002Fv1\u002Fhealth\n",[399,3742,3743],{"__ignoreMap":913},[917,3744,3745,3747],{"class":919,"line":920},[917,3746,1122],{"class":1121},[917,3748,3749],{"class":950}," https:\u002F\u002Fapi.main-team.org\u002Fv1\u002Fhealth\n",[908,3751,3753],{"className":1192,"code":3752,"language":1194,"meta":913,"style":913},"{\n  \"success\": true,\n  \"message\": \"Request completed successfully.\",\n  \"data\": { \"status\": \"ok\" }\n}\n",[399,3754,3755,3759,3769,3780,3798],{"__ignoreMap":913},[917,3756,3757],{"class":919,"line":920},[917,3758,1201],{"class":934},[917,3760,3761,3763,3765,3767],{"class":919,"line":941},[917,3762,1207],{"class":1206},[917,3764,989],{"class":934},[917,3766,1212],{"class":1004},[917,3768,966],{"class":934},[917,3770,3771,3773,3775,3778],{"class":919,"line":957},[917,3772,1219],{"class":1206},[917,3774,989],{"class":934},[917,3776,3777],{"class":950},"\"Request completed successfully.\"",[917,3779,966],{"class":934},[917,3781,3782,3784,3787,3790,3792,3795],{"class":919,"line":969},[917,3783,1231],{"class":1206},[917,3785,3786],{"class":934},": { ",[917,3788,3789],{"class":1206},"\"status\"",[917,3791,989],{"class":934},[917,3793,3794],{"class":950},"\"ok\"",[917,3796,3797],{"class":934}," }\n",[917,3799,3800],{"class":919,"line":998},[917,3801,1473],{"class":934},[358,3803,553,3804,3806,3807,3809,3810,3813,3814,3817,3818,3821],{},[399,3805,718],{}," here only means the API is up and answering. It doesn't check the systems your operations need behind it, so it can answer ",[399,3808,718],{}," while your operations are still failing. Second, once it answers, send one cheap read that your account is allowed, such as ",[399,3811,3812],{},"GET \u002Fv1\u002Fgrade?limit=1"," (needs ",[399,3815,3816],{},"grade\u002Fread"," on ",[399,3819,3820],{},"mto","). Resume the batch when that read succeeds.",[367,3823,3825],{"id":3824},"retries-and-your-rate-limit","Retries and your rate limit",[358,3827,3828],{},"Each API account may make 100 requests per 60 seconds to each operation. One operation's budget is shared by all its calls, whatever ids are in the path and whichever organization they name. Two operations never share a budget.",[358,3830,3831],{},"A retry is a request like any other, so every attempt that reaches an operation counts. A few things work in your favor:",[2792,3833,3834,3847,3863],{},[1738,3835,3836,3837,3839,3840,3842,3843,3846],{},"A request refused for authentication (",[399,3838,434],{},"), for a missing permission (",[399,3841,446],{},") or for an unknown organization (",[399,3844,3845],{},"404 Organization not found!",") is not counted.",[1738,3848,3849,3850,3852,3853,3855,3856,3858,3859,3862],{},"After a ",[399,3851,489],{},", every request to that operation is refused until the ",[399,3854,497],{}," time has passed. The first ",[399,3857,489],{}," says ",[399,3860,3861],{},"Retry-After: 60",", because the block lasts a full 60 seconds from the request that went over the limit. Refusals during the block are not counted and don't extend it, but they don't achieve anything either.",[1738,3864,3865,3866,3868,3869,3871,3872,415,3875,3397,3878,3881,3882,3885],{},"The ",[399,3867,489],{}," response carries ",[399,3870,497],{}," only. The ",[399,3873,3874],{},"X-RateLimit-Limit",[399,3876,3877],{},"X-RateLimit-Remaining",[399,3879,3880],{},"X-RateLimit-Reset"," headers come on the responses that were counted, so read them there to slow down ",[2811,3883,3884],{},"before"," you reach the limit.",[358,3887,3888,3889,3891],{},"The network in front of the API also limits how fast each client address may send requests, whether or not they carry a token. A request refused there gets a ",[399,3890,489],{}," without the API's JSON error envelope. Wait about 10 seconds before you send again, and spread steady high volume over time instead of sending it in bursts.",[358,3893,3894,3895,3897],{},"See ",[362,3896,45],{"href":46}," for client-side throttling patterns.",[367,3899,3901],{"id":3900},"request-ids","Request ids",[358,3903,3904,3905,3908,3909,3912],{},"Every response carries an ",[399,3906,3907],{},"X-Request-Id"," header, and every error body repeats it as ",[399,3910,3911],{},"error.request_id",". Quote it when you ask for help: it is how a request is found.",[358,3914,3915,3916,3919,3920,415,3923,415,3926,3929],{},"You can send your own. The API reuses it if it is 1 to 256 characters of letters, digits and ",[399,3917,3918],{},". _ : ; = + \u002F @ -",". Otherwise the API assigns an id of its own. Don't depend on the format of an id you didn't send. A useful pattern for retries is one id per logical operation plus the attempt number, such as ",[399,3921,3922],{},"1f0c2d9e-5b7a-4c3e-8f21-6a9d0b4e7c35.1",[399,3924,3925],{},".2",[399,3927,3928],{},".3",". Each attempt stays unique, and all attempts of one operation share a prefix you can search for.",[534,3931,3932],{"type":1784},[358,3933,3934,3935,3937,3938,3940,3941,3943],{},"The request id is ",[602,3936,2099],{}," an idempotency key. The API does not deduplicate requests by it. Two ",[399,3939,141],{},"s with the same ",[399,3942,3907],{}," are two requests. Idempotency comes from the operation itself, as described above.",[358,3945,3946],{},"Never put personal data such as an email address or a name into a request id. It is repeated in error bodies and written to logs.",[367,3948,3950],{"id":3949},"a-complete-retry-helper","A complete retry helper",[358,3952,3953,3954,3956,3957,3959],{},"This helper implements everything on this page: backoff with jitter, ",[399,3955,497],{},", a fresh token after a ",[399,3958,434],{},", per-attempt request ids, and no blind retries of operations that aren't safe to repeat.",[908,3961,3963],{"className":910,"code":3962,"language":912,"meta":913,"style":913},"\u002F\u002F api.mjs: Node.js 18+ (global fetch and AbortSignal.timeout)\nimport { randomUUID } from 'node:crypto';\nimport { getToken } from '.\u002Ftoken.mjs'; \u002F\u002F getToken({ forceNew }) returns a signed JWT\n\nconst BASE_URL = 'https:\u002F\u002Fapi.main-team.org\u002Fv1';\nconst RETRY_ON = new Set([500, 502, 503, 504]);\nconst sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\n\nfunction delayMs(attempt, retryAfter) {\n  const seconds = Number(retryAfter);\n  if (retryAfter != null && Number.isFinite(seconds)) {\n    return seconds * 1000 + Math.random() * 1000; \u002F\u002F never sooner than asked\n  }\n  const ceiling = Math.min(30_000, 1_000 * 2 ** attempt);\n  return ceiling \u002F 2 + (Math.random() * ceiling) \u002F 2;\n}\n\n\u002F**\n * repeatable: true when sending the request twice is safe (see the table above).\n * Returns the Response for 2xx and 4xx; throws when attempts run out.\n *\u002F\nexport async function callApi(method, path, { body, repeatable, maxAttempts = 5, timeoutMs = 30_000 } = {}) {\n  const operation = randomUUID();\n  let forceNewToken = false;\n  let lastProblem;\n\n  for (let attempt = 0; attempt \u003C maxAttempts; attempt++) {\n    let res;\n    try {\n      res = await fetch(BASE_URL + path, {\n        method,\n        headers: {\n          Authorization: `Bearer ${getToken({ forceNew: forceNewToken })}`,\n          'Content-Type': 'application\u002Fjson',\n          'X-Request-Id': `${operation}.${attempt + 1}`,\n        },\n        body: body === undefined ? undefined : JSON.stringify(body),\n        signal: AbortSignal.timeout(timeoutMs),\n      });\n    } catch (error) {\n      if (!repeatable) throw error; \u002F\u002F outcome unknown: the caller must check\n      lastProblem = error;\n      await sleep(delayMs(attempt));\n      continue;\n    }\n\n    if (res.status === 401 && !forceNewToken) {\n      forceNewToken = true; \u002F\u002F one more try with a freshly signed token\n      continue;\n    }\n    if (res.status === 429 || (repeatable && RETRY_ON.has(res.status))) {\n      lastProblem = new Error(`HTTP ${res.status} (request ${res.headers.get('x-request-id')})`);\n      await sleep(delayMs(attempt, res.headers.get('retry-after')));\n      continue;\n    }\n    return res;\n  }\n  throw lastProblem;\n}\n",[399,3964,3965,3970,3987,4005,4009,4023,4056,4096,4100,4119,4134,4159,4194,4198,4234,4266,4270,4274,4279,4284,4289,4294,4352,4366,4380,4387,4392,4424,4432,4439,4462,4468,4474,4498,4510,4537,4543,4572,4584,4590,4600,4623,4634,4650,4658,4663,4668,4688,4704,4711,4716,4746,4795,4819,4826,4831,4838,4843,4850],{"__ignoreMap":913},[917,3966,3967],{"class":919,"line":920},[917,3968,3969],{"class":1814},"\u002F\u002F api.mjs: Node.js 18+ (global fetch and AbortSignal.timeout)\n",[917,3971,3972,3975,3978,3981,3984],{"class":919,"line":941},[917,3973,3974],{"class":923},"import",[917,3976,3977],{"class":934}," { randomUUID } ",[917,3979,3980],{"class":923},"from",[917,3982,3983],{"class":950}," 'node:crypto'",[917,3985,3986],{"class":934},";\n",[917,3988,3989,3991,3994,3996,3999,4002],{"class":919,"line":957},[917,3990,3974],{"class":923},[917,3992,3993],{"class":934}," { getToken } ",[917,3995,3980],{"class":923},[917,3997,3998],{"class":950}," '.\u002Ftoken.mjs'",[917,4000,4001],{"class":934},"; ",[917,4003,4004],{"class":1814},"\u002F\u002F getToken({ forceNew }) returns a signed JWT\n",[917,4006,4007],{"class":919,"line":969},[917,4008,1026],{"emptyLinePlaceholder":1025},[917,4010,4011,4013,4016,4018,4021],{"class":919,"line":998},[917,4012,924],{"class":923},[917,4014,4015],{"class":1004}," BASE_URL",[917,4017,931],{"class":923},[917,4019,4020],{"class":950}," 'https:\u002F\u002Fapi.main-team.org\u002Fv1'",[917,4022,3986],{"class":934},[917,4024,4025,4027,4030,4032,4034,4037,4040,4042,4044,4046,4048,4050,4052,4054],{"class":919,"line":1016},[917,4026,924],{"class":923},[917,4028,4029],{"class":1004}," RETRY_ON",[917,4031,931],{"class":923},[917,4033,2035],{"class":923},[917,4035,4036],{"class":927}," Set",[917,4038,4039],{"class":934},"([",[917,4041,505],{"class":1004},[917,4043,415],{"class":934},[917,4045,518],{"class":1004},[917,4047,415],{"class":934},[917,4049,521],{"class":1004},[917,4051,415],{"class":934},[917,4053,524],{"class":1004},[917,4055,2783],{"class":934},[917,4057,4058,4060,4063,4065,4067,4070,4072,4075,4077,4080,4083,4086,4088,4090,4093],{"class":919,"line":1022},[917,4059,924],{"class":923},[917,4061,4062],{"class":927}," sleep",[917,4064,931],{"class":923},[917,4066,2558],{"class":934},[917,4068,4069],{"class":1121},"ms",[917,4071,1934],{"class":934},[917,4073,4074],{"class":923},"=>",[917,4076,2035],{"class":923},[917,4078,4079],{"class":1004}," Promise",[917,4081,4082],{"class":934},"((",[917,4084,4085],{"class":1121},"resolve",[917,4087,1934],{"class":934},[917,4089,4074],{"class":923},[917,4091,4092],{"class":927}," setTimeout",[917,4094,4095],{"class":934},"(resolve, ms));\n",[917,4097,4098],{"class":919,"line":1029},[917,4099,1026],{"emptyLinePlaceholder":1025},[917,4101,4102,4104,4107,4109,4112,4114,4117],{"class":919,"line":1049},[917,4103,2498],{"class":923},[917,4105,4106],{"class":927}," delayMs",[917,4108,947],{"class":934},[917,4110,4111],{"class":1121},"attempt",[917,4113,415],{"class":934},[917,4115,4116],{"class":1121},"retryAfter",[917,4118,1847],{"class":934},[917,4120,4121,4123,4126,4128,4131],{"class":919,"line":1297},[917,4122,1852],{"class":923},[917,4124,4125],{"class":1004}," seconds",[917,4127,931],{"class":923},[917,4129,4130],{"class":927}," Number",[917,4132,4133],{"class":934},"(retryAfter);\n",[917,4135,4136,4138,4141,4144,4147,4150,4153,4156],{"class":919,"line":1306},[917,4137,1923],{"class":923},[917,4139,4140],{"class":934}," (retryAfter ",[917,4142,4143],{"class":923},"!=",[917,4145,4146],{"class":1004}," null",[917,4148,4149],{"class":923}," &&",[917,4151,4152],{"class":934}," Number.",[917,4154,4155],{"class":927},"isFinite",[917,4157,4158],{"class":934},"(seconds)) {\n",[917,4160,4161,4164,4167,4170,4173,4176,4179,4182,4185,4187,4189,4191],{"class":919,"line":1318},[917,4162,4163],{"class":923},"    return",[917,4165,4166],{"class":934}," seconds ",[917,4168,4169],{"class":923},"*",[917,4171,4172],{"class":1004}," 1000",[917,4174,4175],{"class":923}," +",[917,4177,4178],{"class":934}," Math.",[917,4180,4181],{"class":927},"random",[917,4183,4184],{"class":934},"() ",[917,4186,4169],{"class":923},[917,4188,4172],{"class":1004},[917,4190,4001],{"class":934},[917,4192,4193],{"class":1814},"\u002F\u002F never sooner than asked\n",[917,4195,4196],{"class":919,"line":1330},[917,4197,1467],{"class":934},[917,4199,4200,4202,4205,4207,4209,4212,4214,4217,4219,4222,4225,4228,4231],{"class":919,"line":1342},[917,4201,1852],{"class":923},[917,4203,4204],{"class":1004}," ceiling",[917,4206,931],{"class":923},[917,4208,4178],{"class":934},[917,4210,4211],{"class":927},"min",[917,4213,947],{"class":934},[917,4215,4216],{"class":1004},"30_000",[917,4218,415],{"class":934},[917,4220,4221],{"class":1004},"1_000",[917,4223,4224],{"class":923}," *",[917,4226,4227],{"class":1004}," 2",[917,4229,4230],{"class":923}," **",[917,4232,4233],{"class":934}," attempt);\n",[917,4235,4236,4239,4242,4244,4246,4248,4251,4253,4255,4257,4260,4262,4264],{"class":919,"line":1354},[917,4237,4238],{"class":923},"  return",[917,4240,4241],{"class":934}," ceiling ",[917,4243,2378],{"class":923},[917,4245,4227],{"class":1004},[917,4247,4175],{"class":923},[917,4249,4250],{"class":934}," (Math.",[917,4252,4181],{"class":927},[917,4254,4184],{"class":934},[917,4256,4169],{"class":923},[917,4258,4259],{"class":934}," ceiling) ",[917,4261,2378],{"class":923},[917,4263,4227],{"class":1004},[917,4265,3986],{"class":934},[917,4267,4268],{"class":919,"line":1366},[917,4269,1473],{"class":934},[917,4271,4272],{"class":919,"line":1378},[917,4273,1026],{"emptyLinePlaceholder":1025},[917,4275,4276],{"class":919,"line":1390},[917,4277,4278],{"class":1814},"\u002F**\n",[917,4280,4281],{"class":919,"line":1403},[917,4282,4283],{"class":1814}," * repeatable: true when sending the request twice is safe (see the table above).\n",[917,4285,4286],{"class":919,"line":1416},[917,4287,4288],{"class":1814}," * Returns the Response for 2xx and 4xx; throws when attempts run out.\n",[917,4290,4291],{"class":919,"line":1428},[917,4292,4293],{"class":1814}," *\u002F\n",[917,4295,4296,4298,4300,4302,4304,4306,4309,4311,4314,4317,4319,4321,4324,4326,4329,4331,4334,4336,4339,4341,4344,4347,4349],{"class":919,"line":1441},[917,4297,1820],{"class":923},[917,4299,1823],{"class":923},[917,4301,1826],{"class":923},[917,4303,1862],{"class":927},[917,4305,947],{"class":934},[917,4307,4308],{"class":1121},"method",[917,4310,415],{"class":934},[917,4312,4313],{"class":1121},"path",[917,4315,4316],{"class":934},", { ",[917,4318,2057],{"class":1121},[917,4320,415],{"class":934},[917,4322,4323],{"class":1121},"repeatable",[917,4325,415],{"class":934},[917,4327,4328],{"class":1121},"maxAttempts",[917,4330,931],{"class":923},[917,4332,4333],{"class":1004}," 5",[917,4335,415],{"class":934},[917,4337,4338],{"class":1121},"timeoutMs",[917,4340,931],{"class":923},[917,4342,4343],{"class":1004}," 30_000",[917,4345,4346],{"class":934}," } ",[917,4348,1038],{"class":923},[917,4350,4351],{"class":934}," {}) {\n",[917,4353,4354,4356,4359,4361,4364],{"class":919,"line":1453},[917,4355,1852],{"class":923},[917,4357,4358],{"class":1004}," operation",[917,4360,931],{"class":923},[917,4362,4363],{"class":927}," randomUUID",[917,4365,1046],{"class":934},[917,4367,4368,4370,4373,4375,4378],{"class":919,"line":1464},[917,4369,2211],{"class":923},[917,4371,4372],{"class":934}," forceNewToken ",[917,4374,1038],{"class":923},[917,4376,4377],{"class":1004}," false",[917,4379,3986],{"class":934},[917,4381,4382,4384],{"class":919,"line":1470},[917,4383,2211],{"class":923},[917,4385,4386],{"class":934}," lastProblem;\n",[917,4388,4390],{"class":919,"line":4389},26,[917,4391,1026],{"emptyLinePlaceholder":1025},[917,4393,4395,4398,4400,4402,4405,4407,4410,4413,4416,4419,4422],{"class":919,"line":4394},27,[917,4396,4397],{"class":923},"  for",[917,4399,2558],{"class":934},[917,4401,1032],{"class":923},[917,4403,4404],{"class":934}," attempt ",[917,4406,1038],{"class":923},[917,4408,4409],{"class":1004}," 0",[917,4411,4412],{"class":934},"; attempt ",[917,4414,4415],{"class":923},"\u003C",[917,4417,4418],{"class":934}," maxAttempts; attempt",[917,4420,4421],{"class":923},"++",[917,4423,1847],{"class":934},[917,4425,4427,4430],{"class":919,"line":4426},28,[917,4428,4429],{"class":923},"    let",[917,4431,2214],{"class":934},[917,4433,4435,4437],{"class":919,"line":4434},29,[917,4436,2522],{"class":923},[917,4438,2222],{"class":934},[917,4440,4442,4445,4447,4449,4452,4454,4457,4459],{"class":919,"line":4441},30,[917,4443,4444],{"class":934},"      res ",[917,4446,1038],{"class":923},[917,4448,1041],{"class":923},[917,4450,4451],{"class":927}," fetch",[917,4453,947],{"class":934},[917,4455,4456],{"class":1004},"BASE_URL",[917,4458,4175],{"class":923},[917,4460,4461],{"class":934}," path, {\n",[917,4463,4465],{"class":919,"line":4464},31,[917,4466,4467],{"class":934},"        method,\n",[917,4469,4471],{"class":919,"line":4470},32,[917,4472,4473],{"class":934},"        headers: {\n",[917,4475,4477,4480,4482,4485,4488,4491,4494,4496],{"class":919,"line":4476},33,[917,4478,4479],{"class":934},"          Authorization: ",[917,4481,975],{"class":950},[917,4483,4484],{"class":927},"getToken",[917,4486,4487],{"class":950},"({ ",[917,4489,4490],{"class":934},"forceNew: forceNewToken ",[917,4492,4493],{"class":950},"})",[917,4495,981],{"class":950},[917,4497,966],{"class":934},[917,4499,4501,4504,4506,4508],{"class":919,"line":4500},34,[917,4502,4503],{"class":950},"          'Content-Type'",[917,4505,989],{"class":934},[917,4507,992],{"class":950},[917,4509,966],{"class":934},[917,4511,4513,4516,4518,4520,4523,4526,4528,4530,4533,4535],{"class":919,"line":4512},35,[917,4514,4515],{"class":950},"          'X-Request-Id'",[917,4517,989],{"class":934},[917,4519,2043],{"class":950},[917,4521,4522],{"class":934},"operation",[917,4524,4525],{"class":950},"}.${",[917,4527,4111],{"class":934},[917,4529,4175],{"class":923},[917,4531,4532],{"class":1004}," 1",[917,4534,981],{"class":950},[917,4536,966],{"class":934},[917,4538,4540],{"class":919,"line":4539},36,[917,4541,4542],{"class":934},"        },\n",[917,4544,4546,4549,4551,4554,4557,4559,4562,4565,4567,4569],{"class":919,"line":4545},37,[917,4547,4548],{"class":934},"        body: body ",[917,4550,1070],{"class":923},[917,4552,4553],{"class":1004}," undefined",[917,4555,4556],{"class":923}," ?",[917,4558,4553],{"class":1004},[917,4560,4561],{"class":923}," :",[917,4563,4564],{"class":1004}," JSON",[917,4566,365],{"class":934},[917,4568,1010],{"class":927},[917,4570,4571],{"class":934},"(body),\n",[917,4573,4575,4578,4581],{"class":919,"line":4574},38,[917,4576,4577],{"class":934},"        signal: AbortSignal.",[917,4579,4580],{"class":927},"timeout",[917,4582,4583],{"class":934},"(timeoutMs),\n",[917,4585,4587],{"class":919,"line":4586},39,[917,4588,4589],{"class":934},"      });\n",[917,4591,4593,4595,4597],{"class":919,"line":4592},40,[917,4594,2553],{"class":934},[917,4596,2258],{"class":923},[917,4598,4599],{"class":934}," (error) {\n",[917,4601,4603,4606,4608,4611,4614,4617,4620],{"class":919,"line":4602},41,[917,4604,4605],{"class":923},"      if",[917,4607,2558],{"class":934},[917,4609,4610],{"class":923},"!",[917,4612,4613],{"class":934},"repeatable) ",[917,4615,4616],{"class":923},"throw",[917,4618,4619],{"class":934}," error; ",[917,4621,4622],{"class":1814},"\u002F\u002F outcome unknown: the caller must check\n",[917,4624,4626,4629,4631],{"class":919,"line":4625},42,[917,4627,4628],{"class":934},"      lastProblem ",[917,4630,1038],{"class":923},[917,4632,4633],{"class":934}," error;\n",[917,4635,4637,4640,4642,4644,4647],{"class":919,"line":4636},43,[917,4638,4639],{"class":923},"      await",[917,4641,4062],{"class":927},[917,4643,947],{"class":934},[917,4645,4646],{"class":927},"delayMs",[917,4648,4649],{"class":934},"(attempt));\n",[917,4651,4653,4656],{"class":919,"line":4652},44,[917,4654,4655],{"class":923},"      continue",[917,4657,3986],{"class":934},[917,4659,4661],{"class":919,"line":4660},45,[917,4662,2591],{"class":934},[917,4664,4666],{"class":919,"line":4665},46,[917,4667,1026],{"emptyLinePlaceholder":1025},[917,4669,4671,4673,4675,4677,4680,4682,4685],{"class":919,"line":4670},47,[917,4672,2011],{"class":923},[917,4674,1926],{"class":934},[917,4676,1070],{"class":923},[917,4678,4679],{"class":1004}," 401",[917,4681,4149],{"class":923},[917,4683,4684],{"class":923}," !",[917,4686,4687],{"class":934},"forceNewToken) {\n",[917,4689,4691,4694,4696,4699,4701],{"class":919,"line":4690},48,[917,4692,4693],{"class":934},"      forceNewToken ",[917,4695,1038],{"class":923},[917,4697,4698],{"class":1004}," true",[917,4700,4001],{"class":934},[917,4702,4703],{"class":1814},"\u002F\u002F one more try with a freshly signed token\n",[917,4705,4707,4709],{"class":919,"line":4706},49,[917,4708,4655],{"class":923},[917,4710,3986],{"class":934},[917,4712,4714],{"class":919,"line":4713},50,[917,4715,2591],{"class":934},[917,4717,4719,4721,4723,4725,4728,4730,4733,4736,4738,4740,4743],{"class":919,"line":4718},51,[917,4720,2011],{"class":923},[917,4722,1926],{"class":934},[917,4724,1070],{"class":923},[917,4726,4727],{"class":1004}," 429",[917,4729,1064],{"class":923},[917,4731,4732],{"class":934}," (repeatable ",[917,4734,4735],{"class":923},"&&",[917,4737,4029],{"class":1004},[917,4739,365],{"class":934},[917,4741,4742],{"class":927},"has",[917,4744,4745],{"class":934},"(res.status))) {\n",[917,4747,4749,4751,4753,4755,4757,4759,4762,4764,4766,4768,4771,4773,4775,4778,4780,4783,4785,4788,4790,4793],{"class":919,"line":4748},52,[917,4750,4628],{"class":934},[917,4752,1038],{"class":923},[917,4754,2035],{"class":923},[917,4756,2038],{"class":927},[917,4758,947],{"class":934},[917,4760,4761],{"class":950},"`HTTP ${",[917,4763,2046],{"class":934},[917,4765,365],{"class":950},[917,4767,2051],{"class":934},[917,4769,4770],{"class":950},"} (request ${",[917,4772,2046],{"class":934},[917,4774,365],{"class":950},[917,4776,4777],{"class":934},"headers",[917,4779,365],{"class":950},[917,4781,4782],{"class":927},"get",[917,4784,947],{"class":950},[917,4786,4787],{"class":950},"'x-request-id'",[917,4789,2369],{"class":950},[917,4791,4792],{"class":950},"})`",[917,4794,2084],{"class":934},[917,4796,4798,4800,4802,4804,4806,4809,4811,4813,4816],{"class":919,"line":4797},53,[917,4799,4639],{"class":923},[917,4801,4062],{"class":927},[917,4803,947],{"class":934},[917,4805,4646],{"class":927},[917,4807,4808],{"class":934},"(attempt, res.headers.",[917,4810,4782],{"class":927},[917,4812,947],{"class":934},[917,4814,4815],{"class":950},"'retry-after'",[917,4817,4818],{"class":934},")));\n",[917,4820,4822,4824],{"class":919,"line":4821},54,[917,4823,4655],{"class":923},[917,4825,3986],{"class":934},[917,4827,4829],{"class":919,"line":4828},55,[917,4830,2591],{"class":934},[917,4832,4834,4836],{"class":919,"line":4833},56,[917,4835,4163],{"class":923},[917,4837,2214],{"class":934},[917,4839,4841],{"class":919,"line":4840},57,[917,4842,1467],{"class":934},[917,4844,4846,4848],{"class":919,"line":4845},58,[917,4847,2032],{"class":923},[917,4849,4386],{"class":934},[917,4851,4853],{"class":919,"line":4852},59,[917,4854,1473],{"class":934},[908,4856,4858],{"className":2477,"code":4857,"language":2479,"meta":913,"style":913},"\u003C?php\n\u002F\u002F api.php: PHP 8.1+ with ext-curl and ext-json. apiToken(bool $forceNew) returns a signed JWT.\n\nfunction backoffMicroseconds(int $attempt, ?string $retryAfter): int\n{\n    $jitter = mt_rand() \u002F mt_getrandmax();\n    if ($retryAfter !== null && is_numeric($retryAfter)) {\n        return (int) (((float) $retryAfter + $jitter) * 1_000_000); \u002F\u002F never sooner than asked\n    }\n    $ceilingMs = min(30_000, 1_000 * (2 ** $attempt));\n    return (int) (($ceilingMs \u002F 2 + $jitter * $ceilingMs \u002F 2) * 1_000);\n}\n\n\u002F** @return array{status:int, headers:array\u003Cstring,string>, body:mixed} *\u002F\nfunction callApi(string $method, string $path, ?array $body, bool $repeatable, int $maxAttempts = 5): array\n{\n    $operation = bin2hex(random_bytes(16));\n    $forceNewToken = false;\n    $lastProblem = 'no attempt made';\n\n    for ($attempt = 0; $attempt \u003C $maxAttempts; $attempt++) {\n        $headers = [];\n        $ch = curl_init('https:\u002F\u002Fapi.main-team.org\u002Fv1' . $path);\n        curl_setopt_array($ch, [\n            CURLOPT_CUSTOMREQUEST => $method,\n            CURLOPT_RETURNTRANSFER => true,\n            CURLOPT_CONNECTTIMEOUT => 5,\n            CURLOPT_TIMEOUT => 30,\n            CURLOPT_HTTPHEADER => [\n                'Authorization: Bearer ' . apiToken($forceNewToken),\n                'Content-Type: application\u002Fjson',\n                'X-Request-Id: ' . $operation . '.' . ($attempt + 1),\n            ],\n            CURLOPT_HEADERFUNCTION => function ($ch, string $line) use (&$headers): int {\n                $parts = explode(':', $line, 2);\n                if (count($parts) === 2) {\n                    $headers[strtolower(trim($parts[0]))] = trim($parts[1]);\n                }\n                return strlen($line);\n            },\n        ]);\n        if ($body !== null) {\n            curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body, JSON_THROW_ON_ERROR));\n        }\n        $raw = curl_exec($ch);\n        $status = (int) curl_getinfo($ch, CURLINFO_RESPONSE_CODE);\n        $error = curl_error($ch);\n        curl_close($ch);\n\n        if ($raw === false) {\n            if (!$repeatable) {\n                throw new RuntimeException('No answer (' . $error . '); check before retrying.');\n            }\n            $lastProblem = $error;\n            usleep(backoffMicroseconds($attempt, null));\n            continue;\n        }\n        if ($status === 401 && !$forceNewToken) {\n            $forceNewToken = true;\n            continue;\n        }\n        if ($status === 429 || ($repeatable && in_array($status, [500, 502, 503, 504], true))) {\n            $lastProblem = 'HTTP ' . $status . ' (request ' . ($headers['x-request-id'] ?? '-') . ')';\n            usleep(backoffMicroseconds($attempt, $headers['retry-after'] ?? null));\n            continue;\n        }\n        return ['status' => $status, 'headers' => $headers, 'body' => json_decode($raw, true)];\n    }\n    throw new RuntimeException('Gave up: ' . $lastProblem);\n}\n",[399,4859,4860,4866,4871,4875,4901,4905,4924,4944,4977,4981,5011,5049,5053,5057,5080,5127,5131,5154,5165,5177,5181,5205,5215,5235,5243,5254,5265,5276,5288,5298,5311,5318,5344,5349,5384,5406,5425,5457,5462,5473,5478,5483,5496,5520,5524,5537,5560,5572,5579,5583,5596,5608,5634,5639,5649,5667,5674,5678,5696,5707,5714,5719,5765,5809,5831,5838,5843,5881,5886,5905],{"__ignoreMap":913},[917,4861,4862,4864],{"class":919,"line":920},[917,4863,2486],{"class":923},[917,4865,2489],{"class":1004},[917,4867,4868],{"class":919,"line":941},[917,4869,4870],{"class":1814},"\u002F\u002F api.php: PHP 8.1+ with ext-curl and ext-json. apiToken(bool $forceNew) returns a signed JWT.\n",[917,4872,4873],{"class":919,"line":957},[917,4874,1026],{"emptyLinePlaceholder":1025},[917,4876,4877,4879,4882,4884,4887,4890,4893,4896,4898],{"class":919,"line":969},[917,4878,2498],{"class":923},[917,4880,4881],{"class":927}," backoffMicroseconds",[917,4883,947],{"class":934},[917,4885,4886],{"class":923},"int",[917,4888,4889],{"class":934}," $attempt, ",[917,4891,4892],{"class":923},"?string",[917,4894,4895],{"class":934}," $retryAfter)",[917,4897,1189],{"class":923},[917,4899,4900],{"class":923}," int\n",[917,4902,4903],{"class":919,"line":998},[917,4904,1201],{"class":934},[917,4906,4907,4910,4912,4915,4917,4919,4922],{"class":919,"line":1016},[917,4908,4909],{"class":934},"    $jitter ",[917,4911,1038],{"class":923},[917,4913,4914],{"class":1004}," mt_rand",[917,4916,4184],{"class":934},[917,4918,2378],{"class":923},[917,4920,4921],{"class":1004}," mt_getrandmax",[917,4923,1046],{"class":934},[917,4925,4926,4928,4931,4934,4936,4938,4941],{"class":919,"line":1022},[917,4927,2011],{"class":923},[917,4929,4930],{"class":934}," ($retryAfter ",[917,4932,4933],{"class":923},"!==",[917,4935,4146],{"class":1004},[917,4937,4149],{"class":923},[917,4939,4940],{"class":1004}," is_numeric",[917,4942,4943],{"class":934},"($retryAfter)) {\n",[917,4945,4946,4948,4950,4952,4955,4958,4961,4964,4967,4969,4972,4975],{"class":919,"line":1029},[917,4947,2619],{"class":923},[917,4949,2558],{"class":934},[917,4951,4886],{"class":923},[917,4953,4954],{"class":934},") (((",[917,4956,4957],{"class":923},"float",[917,4959,4960],{"class":934},") $retryAfter ",[917,4962,4963],{"class":923},"+",[917,4965,4966],{"class":934}," $jitter) ",[917,4968,4169],{"class":923},[917,4970,4971],{"class":1004}," 1_000_000",[917,4973,4974],{"class":934},"); ",[917,4976,4193],{"class":1814},[917,4978,4979],{"class":919,"line":1049},[917,4980,2591],{"class":934},[917,4982,4983,4986,4988,4991,4993,4995,4997,4999,5001,5003,5006,5008],{"class":919,"line":1297},[917,4984,4985],{"class":934},"    $ceilingMs ",[917,4987,1038],{"class":923},[917,4989,4990],{"class":1004}," min",[917,4992,947],{"class":934},[917,4994,4216],{"class":1004},[917,4996,415],{"class":934},[917,4998,4221],{"class":1004},[917,5000,4224],{"class":923},[917,5002,2558],{"class":934},[917,5004,5005],{"class":1004},"2",[917,5007,4230],{"class":923},[917,5009,5010],{"class":934}," $attempt));\n",[917,5012,5013,5015,5017,5019,5022,5024,5026,5028,5031,5033,5036,5038,5040,5042,5044,5047],{"class":919,"line":1306},[917,5014,4163],{"class":923},[917,5016,2558],{"class":934},[917,5018,4886],{"class":923},[917,5020,5021],{"class":934},") (($ceilingMs ",[917,5023,2378],{"class":923},[917,5025,4227],{"class":1004},[917,5027,4175],{"class":923},[917,5029,5030],{"class":934}," $jitter ",[917,5032,4169],{"class":923},[917,5034,5035],{"class":934}," $ceilingMs ",[917,5037,2378],{"class":923},[917,5039,4227],{"class":1004},[917,5041,1934],{"class":934},[917,5043,4169],{"class":923},[917,5045,5046],{"class":1004}," 1_000",[917,5048,2084],{"class":934},[917,5050,5051],{"class":919,"line":1318},[917,5052,1473],{"class":934},[917,5054,5055],{"class":919,"line":1330},[917,5056,1026],{"emptyLinePlaceholder":1025},[917,5058,5059,5062,5065,5068,5071,5073,5075,5077],{"class":919,"line":1342},[917,5060,5061],{"class":1814},"\u002F** ",[917,5063,5064],{"class":923},"@return",[917,5066,5067],{"class":923}," array",[917,5069,5070],{"class":1814},"{",[917,5072,2051],{"class":1004},[917,5074,1189],{"class":1814},[917,5076,4886],{"class":923},[917,5078,5079],{"class":1814},", headers:array\u003Cstring,string>, body:mixed} *\u002F\n",[917,5081,5082,5084,5086,5088,5091,5094,5096,5099,5102,5105,5108,5111,5113,5116,5118,5120,5122,5124],{"class":919,"line":1354},[917,5083,2498],{"class":923},[917,5085,1862],{"class":927},[917,5087,947],{"class":934},[917,5089,5090],{"class":923},"string",[917,5092,5093],{"class":934}," $method, ",[917,5095,5090],{"class":923},[917,5097,5098],{"class":934}," $path, ",[917,5100,5101],{"class":923},"?array",[917,5103,5104],{"class":934}," $body, ",[917,5106,5107],{"class":923},"bool",[917,5109,5110],{"class":934}," $repeatable, ",[917,5112,4886],{"class":923},[917,5114,5115],{"class":934}," $maxAttempts ",[917,5117,1038],{"class":923},[917,5119,4333],{"class":1004},[917,5121,2369],{"class":934},[917,5123,1189],{"class":923},[917,5125,5126],{"class":923}," array\n",[917,5128,5129],{"class":919,"line":1366},[917,5130,1201],{"class":934},[917,5132,5133,5136,5138,5141,5143,5146,5148,5151],{"class":919,"line":1378},[917,5134,5135],{"class":934},"    $operation ",[917,5137,1038],{"class":923},[917,5139,5140],{"class":1004}," bin2hex",[917,5142,947],{"class":934},[917,5144,5145],{"class":927},"random_bytes",[917,5147,947],{"class":934},[917,5149,5150],{"class":1004},"16",[917,5152,5153],{"class":934},"));\n",[917,5155,5156,5159,5161,5163],{"class":919,"line":1390},[917,5157,5158],{"class":934},"    $forceNewToken ",[917,5160,1038],{"class":923},[917,5162,4377],{"class":1004},[917,5164,3986],{"class":934},[917,5166,5167,5170,5172,5175],{"class":919,"line":1403},[917,5168,5169],{"class":934},"    $lastProblem ",[917,5171,1038],{"class":923},[917,5173,5174],{"class":950}," 'no attempt made'",[917,5176,3986],{"class":934},[917,5178,5179],{"class":919,"line":1416},[917,5180,1026],{"emptyLinePlaceholder":1025},[917,5182,5183,5186,5189,5191,5193,5196,5198,5201,5203],{"class":919,"line":1428},[917,5184,5185],{"class":923},"    for",[917,5187,5188],{"class":934}," ($attempt ",[917,5190,1038],{"class":923},[917,5192,4409],{"class":1004},[917,5194,5195],{"class":934},"; $attempt ",[917,5197,4415],{"class":923},[917,5199,5200],{"class":934}," $maxAttempts; $attempt",[917,5202,4421],{"class":923},[917,5204,1847],{"class":934},[917,5206,5207,5210,5212],{"class":919,"line":1441},[917,5208,5209],{"class":934},"        $headers ",[917,5211,1038],{"class":923},[917,5213,5214],{"class":934}," [];\n",[917,5216,5217,5220,5222,5225,5227,5230,5232],{"class":919,"line":1453},[917,5218,5219],{"class":934},"        $ch ",[917,5221,1038],{"class":923},[917,5223,5224],{"class":1004}," curl_init",[917,5226,947],{"class":934},[917,5228,5229],{"class":950},"'https:\u002F\u002Fapi.main-team.org\u002Fv1'",[917,5231,2767],{"class":923},[917,5233,5234],{"class":934}," $path);\n",[917,5236,5237,5240],{"class":919,"line":1464},[917,5238,5239],{"class":1004},"        curl_setopt_array",[917,5241,5242],{"class":934},"($ch, [\n",[917,5244,5245,5248,5251],{"class":919,"line":1470},[917,5246,5247],{"class":1004},"            CURLOPT_CUSTOMREQUEST",[917,5249,5250],{"class":923}," =>",[917,5252,5253],{"class":934}," $method,\n",[917,5255,5256,5259,5261,5263],{"class":919,"line":4389},[917,5257,5258],{"class":1004},"            CURLOPT_RETURNTRANSFER",[917,5260,5250],{"class":923},[917,5262,4698],{"class":1004},[917,5264,966],{"class":934},[917,5266,5267,5270,5272,5274],{"class":919,"line":4394},[917,5268,5269],{"class":1004},"            CURLOPT_CONNECTTIMEOUT",[917,5271,5250],{"class":923},[917,5273,4333],{"class":1004},[917,5275,966],{"class":934},[917,5277,5278,5281,5283,5286],{"class":919,"line":4426},[917,5279,5280],{"class":1004},"            CURLOPT_TIMEOUT",[917,5282,5250],{"class":923},[917,5284,5285],{"class":1004}," 30",[917,5287,966],{"class":934},[917,5289,5290,5293,5295],{"class":919,"line":4434},[917,5291,5292],{"class":1004},"            CURLOPT_HTTPHEADER",[917,5294,5250],{"class":923},[917,5296,5297],{"class":934}," [\n",[917,5299,5300,5303,5305,5308],{"class":919,"line":4441},[917,5301,5302],{"class":950},"                'Authorization: Bearer '",[917,5304,2767],{"class":923},[917,5306,5307],{"class":927}," apiToken",[917,5309,5310],{"class":934},"($forceNewToken),\n",[917,5312,5313,5316],{"class":919,"line":4464},[917,5314,5315],{"class":950},"                'Content-Type: application\u002Fjson'",[917,5317,966],{"class":934},[917,5319,5320,5323,5325,5328,5330,5333,5335,5337,5339,5341],{"class":919,"line":4470},[917,5321,5322],{"class":950},"                'X-Request-Id: '",[917,5324,2767],{"class":923},[917,5326,5327],{"class":934}," $operation ",[917,5329,365],{"class":923},[917,5331,5332],{"class":950}," '.'",[917,5334,2767],{"class":923},[917,5336,5188],{"class":934},[917,5338,4963],{"class":923},[917,5340,4532],{"class":1004},[917,5342,5343],{"class":934},"),\n",[917,5345,5346],{"class":919,"line":4476},[917,5347,5348],{"class":934},"            ],\n",[917,5350,5351,5354,5356,5358,5361,5363,5366,5369,5371,5374,5377,5379,5382],{"class":919,"line":4500},[917,5352,5353],{"class":1004},"            CURLOPT_HEADERFUNCTION",[917,5355,5250],{"class":923},[917,5357,1826],{"class":923},[917,5359,5360],{"class":934}," ($ch, ",[917,5362,5090],{"class":923},[917,5364,5365],{"class":934}," $line) ",[917,5367,5368],{"class":923},"use",[917,5370,2558],{"class":934},[917,5372,5373],{"class":923},"&",[917,5375,5376],{"class":934},"$headers)",[917,5378,1189],{"class":923},[917,5380,5381],{"class":923}," int",[917,5383,2222],{"class":934},[917,5385,5386,5389,5391,5394,5396,5399,5402,5404],{"class":919,"line":4512},[917,5387,5388],{"class":934},"                $parts ",[917,5390,1038],{"class":923},[917,5392,5393],{"class":1004}," explode",[917,5395,947],{"class":934},[917,5397,5398],{"class":950},"':'",[917,5400,5401],{"class":934},", $line, ",[917,5403,5005],{"class":1004},[917,5405,2084],{"class":934},[917,5407,5408,5411,5413,5416,5419,5421,5423],{"class":919,"line":4539},[917,5409,5410],{"class":923},"                if",[917,5412,2558],{"class":934},[917,5414,5415],{"class":1004},"count",[917,5417,5418],{"class":934},"($parts) ",[917,5420,1070],{"class":923},[917,5422,4227],{"class":1004},[917,5424,1847],{"class":934},[917,5426,5427,5430,5433,5435,5438,5441,5443,5446,5448,5451,5453,5455],{"class":919,"line":4545},[917,5428,5429],{"class":934},"                    $headers[",[917,5431,5432],{"class":1004},"strtolower",[917,5434,947],{"class":934},[917,5436,5437],{"class":1004},"trim",[917,5439,5440],{"class":934},"($parts[",[917,5442,1398],{"class":1004},[917,5444,5445],{"class":934},"]))] ",[917,5447,1038],{"class":923},[917,5449,5450],{"class":1004}," trim",[917,5452,5440],{"class":934},[917,5454,2401],{"class":1004},[917,5456,2783],{"class":934},[917,5458,5459],{"class":919,"line":4574},[917,5460,5461],{"class":934},"                }\n",[917,5463,5464,5467,5470],{"class":919,"line":4586},[917,5465,5466],{"class":923},"                return",[917,5468,5469],{"class":1004}," strlen",[917,5471,5472],{"class":934},"($line);\n",[917,5474,5475],{"class":919,"line":4592},[917,5476,5477],{"class":934},"            },\n",[917,5479,5480],{"class":919,"line":4602},[917,5481,5482],{"class":934},"        ]);\n",[917,5484,5485,5487,5490,5492,5494],{"class":919,"line":4625},[917,5486,2663],{"class":923},[917,5488,5489],{"class":934}," ($body ",[917,5491,4933],{"class":923},[917,5493,4146],{"class":1004},[917,5495,1847],{"class":934},[917,5497,5498,5501,5504,5507,5509,5512,5515,5518],{"class":919,"line":4636},[917,5499,5500],{"class":1004},"            curl_setopt",[917,5502,5503],{"class":934},"($ch, ",[917,5505,5506],{"class":1004},"CURLOPT_POSTFIELDS",[917,5508,415],{"class":934},[917,5510,5511],{"class":1004},"json_encode",[917,5513,5514],{"class":934},"($body, ",[917,5516,5517],{"class":1004},"JSON_THROW_ON_ERROR",[917,5519,5153],{"class":934},[917,5521,5522],{"class":919,"line":4652},[917,5523,2724],{"class":934},[917,5525,5526,5529,5531,5534],{"class":919,"line":4660},[917,5527,5528],{"class":934},"        $raw ",[917,5530,1038],{"class":923},[917,5532,5533],{"class":1004}," curl_exec",[917,5535,5536],{"class":934},"($ch);\n",[917,5538,5539,5542,5544,5546,5548,5550,5553,5555,5558],{"class":919,"line":4665},[917,5540,5541],{"class":934},"        $status ",[917,5543,1038],{"class":923},[917,5545,2558],{"class":934},[917,5547,4886],{"class":923},[917,5549,1934],{"class":934},[917,5551,5552],{"class":1004},"curl_getinfo",[917,5554,5503],{"class":934},[917,5556,5557],{"class":1004},"CURLINFO_RESPONSE_CODE",[917,5559,2084],{"class":934},[917,5561,5562,5565,5567,5570],{"class":919,"line":4670},[917,5563,5564],{"class":934},"        $error ",[917,5566,1038],{"class":923},[917,5568,5569],{"class":1004}," curl_error",[917,5571,5536],{"class":934},[917,5573,5574,5577],{"class":919,"line":4690},[917,5575,5576],{"class":1004},"        curl_close",[917,5578,5536],{"class":934},[917,5580,5581],{"class":919,"line":4706},[917,5582,1026],{"emptyLinePlaceholder":1025},[917,5584,5585,5587,5590,5592,5594],{"class":919,"line":4713},[917,5586,2663],{"class":923},[917,5588,5589],{"class":934}," ($raw ",[917,5591,1070],{"class":923},[917,5593,4377],{"class":1004},[917,5595,1847],{"class":934},[917,5597,5598,5601,5603,5605],{"class":919,"line":4718},[917,5599,5600],{"class":923},"            if",[917,5602,2558],{"class":934},[917,5604,4610],{"class":923},[917,5606,5607],{"class":934},"$repeatable) {\n",[917,5609,5610,5613,5615,5617,5619,5622,5624,5627,5629,5632],{"class":919,"line":4748},[917,5611,5612],{"class":923},"                throw",[917,5614,2035],{"class":923},[917,5616,2734],{"class":1004},[917,5618,947],{"class":934},[917,5620,5621],{"class":950},"'No answer ('",[917,5623,2767],{"class":923},[917,5625,5626],{"class":934}," $error ",[917,5628,365],{"class":923},[917,5630,5631],{"class":950}," '); check before retrying.'",[917,5633,2084],{"class":934},[917,5635,5636],{"class":919,"line":4797},[917,5637,5638],{"class":934},"            }\n",[917,5640,5641,5644,5646],{"class":919,"line":4821},[917,5642,5643],{"class":934},"            $lastProblem ",[917,5645,1038],{"class":923},[917,5647,5648],{"class":934}," $error;\n",[917,5650,5651,5654,5656,5659,5662,5665],{"class":919,"line":4828},[917,5652,5653],{"class":1004},"            usleep",[917,5655,947],{"class":934},[917,5657,5658],{"class":927},"backoffMicroseconds",[917,5660,5661],{"class":934},"($attempt, ",[917,5663,5664],{"class":1004},"null",[917,5666,5153],{"class":934},[917,5668,5669,5672],{"class":919,"line":4833},[917,5670,5671],{"class":923},"            continue",[917,5673,3986],{"class":934},[917,5675,5676],{"class":919,"line":4840},[917,5677,2724],{"class":934},[917,5679,5680,5682,5685,5687,5689,5691,5693],{"class":919,"line":4845},[917,5681,2663],{"class":923},[917,5683,5684],{"class":934}," ($status ",[917,5686,1070],{"class":923},[917,5688,4679],{"class":1004},[917,5690,4149],{"class":923},[917,5692,4684],{"class":923},[917,5694,5695],{"class":934},"$forceNewToken) {\n",[917,5697,5698,5701,5703,5705],{"class":919,"line":4852},[917,5699,5700],{"class":934},"            $forceNewToken ",[917,5702,1038],{"class":923},[917,5704,4698],{"class":1004},[917,5706,3986],{"class":934},[917,5708,5710,5712],{"class":919,"line":5709},60,[917,5711,5671],{"class":923},[917,5713,3986],{"class":934},[917,5715,5717],{"class":919,"line":5716},61,[917,5718,2724],{"class":934},[917,5720,5722,5724,5726,5728,5730,5732,5735,5737,5740,5743,5745,5747,5749,5751,5753,5755,5757,5760,5762],{"class":919,"line":5721},62,[917,5723,2663],{"class":923},[917,5725,5684],{"class":934},[917,5727,1070],{"class":923},[917,5729,4727],{"class":1004},[917,5731,1064],{"class":923},[917,5733,5734],{"class":934}," ($repeatable ",[917,5736,4735],{"class":923},[917,5738,5739],{"class":1004}," in_array",[917,5741,5742],{"class":934},"($status, [",[917,5744,505],{"class":1004},[917,5746,415],{"class":934},[917,5748,518],{"class":1004},[917,5750,415],{"class":934},[917,5752,521],{"class":1004},[917,5754,415],{"class":934},[917,5756,524],{"class":1004},[917,5758,5759],{"class":934},"], ",[917,5761,1212],{"class":1004},[917,5763,5764],{"class":934},"))) {\n",[917,5766,5768,5770,5772,5775,5777,5780,5782,5785,5787,5790,5792,5794,5797,5800,5802,5804,5807],{"class":919,"line":5767},63,[917,5769,5643],{"class":934},[917,5771,1038],{"class":923},[917,5773,5774],{"class":950}," 'HTTP '",[917,5776,2767],{"class":923},[917,5778,5779],{"class":934}," $status ",[917,5781,365],{"class":923},[917,5783,5784],{"class":950}," ' (request '",[917,5786,2767],{"class":923},[917,5788,5789],{"class":934}," ($headers[",[917,5791,4787],{"class":950},[917,5793,2608],{"class":934},[917,5795,5796],{"class":923},"??",[917,5798,5799],{"class":950}," '-'",[917,5801,1934],{"class":934},[917,5803,365],{"class":923},[917,5805,5806],{"class":950}," ')'",[917,5808,3986],{"class":934},[917,5810,5812,5814,5816,5818,5821,5823,5825,5827,5829],{"class":919,"line":5811},64,[917,5813,5653],{"class":1004},[917,5815,947],{"class":934},[917,5817,5658],{"class":927},[917,5819,5820],{"class":934},"($attempt, $headers[",[917,5822,4815],{"class":950},[917,5824,2608],{"class":934},[917,5826,5796],{"class":923},[917,5828,4146],{"class":1004},[917,5830,5153],{"class":934},[917,5832,5834,5836],{"class":919,"line":5833},65,[917,5835,5671],{"class":923},[917,5837,3986],{"class":934},[917,5839,5841],{"class":919,"line":5840},66,[917,5842,2724],{"class":934},[917,5844,5846,5848,5851,5853,5855,5858,5861,5863,5866,5868,5870,5873,5876,5878],{"class":919,"line":5845},67,[917,5847,2619],{"class":923},[917,5849,5850],{"class":934}," [",[917,5852,2605],{"class":950},[917,5854,5250],{"class":923},[917,5856,5857],{"class":934}," $status, ",[917,5859,5860],{"class":950},"'headers'",[917,5862,5250],{"class":923},[917,5864,5865],{"class":934}," $headers, ",[917,5867,2625],{"class":950},[917,5869,5250],{"class":923},[917,5871,5872],{"class":1004}," json_decode",[917,5874,5875],{"class":934},"($raw, ",[917,5877,1212],{"class":1004},[917,5879,5880],{"class":934},")];\n",[917,5882,5884],{"class":919,"line":5883},68,[917,5885,2591],{"class":934},[917,5887,5889,5891,5893,5895,5897,5900,5902],{"class":919,"line":5888},69,[917,5890,2409],{"class":923},[917,5892,2035],{"class":923},[917,5894,2734],{"class":1004},[917,5896,947],{"class":934},[917,5898,5899],{"class":950},"'Gave up: '",[917,5901,2767],{"class":923},[917,5903,5904],{"class":934}," $lastProblem);\n",[917,5906,5908],{"class":919,"line":5907},70,[917,5909,1473],{"class":934},[367,5911,5913],{"id":5912},"checklist","Checklist",[2792,5915,5918,5937,5949,5958,5968,5978,5985,5992],{"className":5916},[5917],"contains-task-list",[1738,5919,5922,5927,5928,5930,5931,5933,5934,5936],{"className":5920},[5921],"task-list-item",[5923,5924],"input",{"disabled":1025,"type":5925,"ariaLabel":5926},"checkbox","Every 4xx except 401 (once) and 429 is handled without a retry."," Every ",[399,5929,542],{}," except ",[399,5932,434],{}," (once) and ",[399,5935,489],{}," is handled without a retry.",[1738,5938,5940,595,5943,5945,5946,5948],{"className":5939},[5921],[5923,5941],{"disabled":1025,"type":5925,"ariaLabel":5942},"429 waits at least Retry-After seconds.",[399,5944,489],{}," waits at least ",[399,5947,497],{}," seconds.",[1738,5950,5952,595,5955,5957],{"className":5951},[5921],[5923,5953],{"disabled":1025,"type":5925,"ariaLabel":5954},"5xx and timeouts are retried with jittered backoff, at most five attempts in total, and only for operations that are safe to repeat.",[399,5956,549],{}," and timeouts are retried with jittered backoff, at most five attempts in total, and only for operations that are safe to repeat.",[1738,5959,5961,5964,5965,5967],{"className":5960},[5921],[5923,5962],{"disabled":1025,"type":5925,"ariaLabel":5963},"A registration that timed out is re-sent, and its 409 is read for the student's id."," A registration that timed out is re-sent, and its ",[399,5966,474],{}," is read for the student's id.",[1738,5969,5971,5974,5975,5977],{"className":5970},[5921],[5923,5972],{"disabled":1025,"type":5925,"ariaLabel":5973},"An application create is never sent twice in parallel, and a 409 on a retry is checked against the student's applications."," An application create is never sent twice in parallel, and a ",[399,5976,474],{}," on a retry is checked against the student's applications.",[1738,5979,5981,5984],{"className":5980},[5921],[5923,5982],{"disabled":1025,"type":5925,"ariaLabel":5983},"Sign-in links are minted on demand and never reopened."," Sign-in links are minted on demand and never reopened.",[1738,5986,5988,5991],{"className":5987},[5921],[5923,5989],{"disabled":1025,"type":5925,"ariaLabel":5990},"Downloads are written to a temporary file and discarded if truncated."," Downloads are written to a temporary file and discarded if truncated.",[1738,5993,5995,5998,5999,6001],{"className":5994},[5921],[5923,5996],{"disabled":1025,"type":5925,"ariaLabel":5997},"Each attempt carries its own X-Request-Id, with no personal data in it."," Each attempt carries its own ",[399,6000,3907],{},", with no personal data in it.",[6003,6004,6005],"style",{},"html pre.shiki code .sHUrx, html code.shiki .sHUrx{--shiki-default:#A0111F;--shiki-dark:#FF9492}html pre.shiki code .sKwhi, html code.shiki .sKwhi{--shiki-default:#622CBC;--shiki-dark:#DBB7FF}html pre.shiki code .suds8, html code.shiki .suds8{--shiki-default:#0E1116;--shiki-dark:#F0F3F6}html pre.shiki code .sT6z2, html code.shiki .sT6z2{--shiki-default:#032563;--shiki-dark:#ADDCFF}html pre.shiki code .s-5SL, html code.shiki .s-5SL{--shiki-default:#023B95;--shiki-dark:#91CBFF}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 .soyes, html code.shiki .soyes{--shiki-default:#702C00;--shiki-dark:#FFB757}html pre.shiki code .sne4z, html code.shiki .sne4z{--shiki-default:#024C1A;--shiki-dark:#72F088}html pre.shiki code .sLBg1, html code.shiki .sLBg1{--shiki-default:#66707B;--shiki-dark:#BDC4CC}html pre.shiki code .sJaa3, html code.shiki .sJaa3{--shiki-default:#024C1A;--shiki-default-font-weight:bold;--shiki-dark:#72F088;--shiki-dark-font-weight:bold}",{"title":913,"searchDepth":941,"depth":957,"links":6007},[6008,6009,6010,6011,6012,6013,6014,6015,6016,6017,6018,6019,6020,6021,6022,6023,6024],{"id":369,"depth":941,"text":370},{"id":565,"depth":941,"text":566},{"id":888,"depth":941,"text":653},{"id":1103,"depth":941,"text":1104},{"id":2091,"depth":941,"text":623},{"id":2827,"depth":941,"text":2828},{"id":2869,"depth":941,"text":2870},{"id":3132,"depth":941,"text":467},{"id":3389,"depth":941,"text":839},{"id":3481,"depth":941,"text":3482},{"id":3526,"depth":941,"text":3527},{"id":3566,"depth":941,"text":3567},{"id":3631,"depth":941,"text":3632},{"id":3824,"depth":941,"text":3825},{"id":3900,"depth":941,"text":3901},{"id":3949,"depth":941,"text":3950},{"id":5912,"depth":941,"text":5913},"Which requests are safe to repeat, how to recover from timeouts and server errors, and how to back off without wasting your rate limit.","md",{},[6029,6030,6031,6032,6033,6034,6035,6036,6037,6038,6039,6040,6041,6042,6043,3396,3402],"createStudentImport","getStudentImport","createApplication","moveApplication","deleteApplication","registerStudent","updateStudent","updateOrgStudent","setStudentPassword","linkStudentSupervisor","createSigninLink","revokeToken","downloadCertificate","downloadReport","getHealth","50",{"title":353,"description":6025},"api\u002Fretries-and-idempotency","qZLGuCCPLJpwULMcsBUgBwOPGgeG0RIVViD38k93cdM",[6049,6054,6057,6062,6066,6069,6072,6076,6079,6083,6086,6089,6093,6097,6101,6106,6110],{"operationId":6029,"slug":6050,"method":141,"path":6051,"tag":62,"summary":179,"deprecated":134,"public":134,"permission":6052,"scope":6053,"order":1330},"create-student-import","\u002Fv1\u002Fstudent\u002Fimport","student\u002Fcreate:$org:$ID","flat",{"operationId":6030,"slug":6055,"method":133,"path":6056,"tag":62,"summary":182,"deprecated":134,"public":134,"permission":6052,"scope":6053,"order":1342},"get-student-import","\u002Fv1\u002Fstudent\u002Fimport\u002F{importId}",{"operationId":6031,"slug":6058,"method":141,"path":6059,"tag":86,"summary":237,"deprecated":134,"public":134,"permission":6060,"scope":6061,"order":4434},"create-application","\u002Fv1\u002F{organizationId}\u002Fapplication","application\u002Fcreate:$org:$ID","organization",{"operationId":6032,"slug":6063,"method":190,"path":6064,"tag":86,"summary":249,"deprecated":134,"public":134,"permission":6065,"scope":6061,"order":4476},"move-application","\u002Fv1\u002F{organizationId}\u002Fapplication\u002F{applicationId}","application\u002Fupdate:$org:$ID",{"operationId":6033,"slug":6067,"method":254,"path":6064,"tag":86,"summary":252,"deprecated":134,"public":134,"permission":6068,"scope":6061,"order":4500},"delete-application","application\u002Fdelete:$org:$ID",{"operationId":6034,"slug":6070,"method":141,"path":6071,"tag":62,"summary":173,"deprecated":134,"public":134,"permission":6052,"scope":6053,"order":1306},"register-student","\u002Fv1\u002Fstudent",{"operationId":6035,"slug":6073,"method":190,"path":6074,"tag":62,"summary":188,"deprecated":134,"public":134,"permission":6075,"scope":6053,"order":1366},"update-student","\u002Fv1\u002Fstudent\u002F{studentId}","student\u002Fupdate:$org:$ID",{"operationId":6036,"slug":6077,"method":190,"path":6078,"tag":62,"summary":201,"deprecated":134,"public":134,"permission":6075,"scope":6061,"order":1416},"update-org-student","\u002Fv1\u002F{organizationId}\u002Fstudent\u002F{studentId}",{"operationId":6037,"slug":6080,"method":190,"path":6081,"tag":62,"summary":192,"deprecated":134,"public":134,"permission":6082,"scope":6053,"order":1378},"set-student-password","\u002Fv1\u002Fstudent\u002F{studentId}\u002Fpassword","auth\u002Fsignin:$org:$ID",{"operationId":6038,"slug":6084,"method":190,"path":6085,"tag":62,"summary":204,"deprecated":134,"public":134,"permission":6075,"scope":6061,"order":1428},"link-student-supervisor","\u002Fv1\u002F{organizationId}\u002Fstudent\u002F{studentId}\u002Fsupervisor",{"operationId":6039,"slug":6087,"method":141,"path":6088,"tag":80,"summary":210,"deprecated":134,"public":134,"permission":6082,"scope":6061,"order":1441},"create-signin-link","\u002Fv1\u002F{organizationId}\u002Fauth\u002Fsignin",{"operationId":6040,"slug":6090,"method":141,"path":6091,"tag":77,"summary":139,"deprecated":134,"public":134,"permission":6092,"scope":6053,"order":941},"revoke-token","\u002Fv1\u002Fapi-account\u002Frevoke-token","api\u002F*:$org:$ID",{"operationId":6041,"slug":6094,"method":133,"path":6095,"tag":256,"summary":260,"deprecated":134,"public":134,"permission":6096,"scope":6061,"order":4512},"download-certificate","\u002Fv1\u002F{organizationId}\u002Fcertificate\u002Fdownload\u002F{certificateId}","certificate\u002Fread:$org:$ID",{"operationId":6042,"slug":6098,"method":133,"path":6099,"tag":256,"summary":266,"deprecated":134,"public":134,"permission":6100,"scope":6061,"order":4545},"download-report","\u002Fv1\u002F{organizationId}\u002Freport\u002Fdownload\u002F{reportId}","report\u002Fread:$org:$ID",{"operationId":6043,"slug":6102,"method":133,"path":6103,"tag":127,"summary":131,"deprecated":134,"public":1025,"permission":6104,"scope":6105,"order":920},"get-health","\u002Fv1\u002Fhealth",null,"public",{"operationId":3396,"slug":6107,"method":141,"path":6108,"tag":89,"summary":293,"deprecated":134,"public":134,"permission":6109,"scope":6061,"order":4660},"submit-group-challenge-step","\u002Fv1\u002F{organizationId}\u002Fgroup-challenge\u002F{challengeId}\u002Fgroup\u002F{groupId}\u002Fstep\u002F{stepId}\u002Fsubmit","group-challenge\u002Fsubmit:$org:$ID",{"operationId":3402,"slug":6111,"method":141,"path":6112,"tag":89,"summary":290,"deprecated":134,"public":134,"permission":6109,"scope":6061,"order":4652},"submit-group-challenge-work","\u002Fv1\u002F{organizationId}\u002Fgroup-challenge\u002F{challengeId}\u002Fgroup\u002F{groupId}\u002Ffinal-submit",1791554614951]