[{"data":1,"prerenderedAt":1491},["ShallowReactive",2],{"api-nav":3,"api-guide:\u002Fapi\u002Fversioning":351,"api-spec:guide:\u002Fapi\u002Fversioning":1490},[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":1481,"extension":1482,"meta":1483,"navTitle":54,"navigation":1484,"operations":1485,"order":1486,"path":55,"section":29,"seo":1487,"status":14,"stem":1488,"__hash__":1489},"apiGuides\u002Fapi\u002Fversioning.md","Versioning and deprecation",{"type":355,"value":356,"toc":1473},"minimark",[357,361,366,434,448,451,501,507,511,514,582,586,589,624,628,635,656,662,679,876,1031,1037,1054,1068,1081,1084,1087,1140,1146,1149,1287,1424,1428,1469],[358,359,360],"p",{},"You build against the API once and expect it to keep working. This page explains the promises that make that possible: which changes can happen without notice, which ones can't, how you'll hear about them, and what your client has to do on its side.",[362,363,365],"h2",{"id":364},"two-version-numbers","Two version numbers",[367,368,369,384],"table",{},[370,371,372],"thead",{},[373,374,375,378,381],"tr",{},[376,377],"th",{},[376,379,380],{},"Where you see it",[376,382,383],{},"What it tells you",[385,386,387,414],"tbody",{},[373,388,389,396,403],{},[390,391,392],"td",{},[393,394,395],"strong",{},"Major version",[390,397,398,399],{},"The URL: ",[400,401,402],"code",{},"https:\u002F\u002Fapi.main-team.org\u002Fv1\u002F...",[390,404,405,406,409,410,413],{},"The contract you call. Every operation is under ",[400,407,408],{},"\u002Fv1",". A breaking change needs a new major version, a new URL prefix such as ",[400,411,412],{},"\u002Fv2",".",[373,415,416,421,428],{},[390,417,418],{},[393,419,420],{},"Documented version",[390,422,423,424],{},"The version badge on these pages, and the ",[425,426,427],"a",{"href":349},"changelog",[390,429,430,431,413],{},"The exact behavior these pages describe, as semantic versioning: ",[400,432,433],{},"MAJOR.MINOR.PATCH",[358,435,436,437,440,441,443,444,413],{},"The ",[425,438,439],{"href":121},"API reference"," shows the documented version these pages describe. The ",[425,442,427],{"href":349}," lists every version and what changed in it; the first, 1.0.0, also lists ",[425,445,447],{"href":446},"\u002Fapi\u002Fchangelog\u002F1-0-0","the behaviors the API started with",[358,449,450],{},"The documented version moves like this:",[452,453,454,469,481],"ul",{},[455,456,457,460,461,464,465,468],"li",{},[393,458,459],{},"Patch"," (",[400,462,463],{},"1.0.0"," → ",[400,466,467],{},"1.0.1","): a fix or clarification that changes nothing your client can rely on.",[455,470,471,460,474,464,477,480],{},[393,472,473],{},"Minor",[400,475,476],{},"1.0.x",[400,478,479],{},"1.1.0","): something new that is backward compatible, such as a new operation or a new response field.",[455,482,483,460,486,464,489,492,493,495,496,500],{},[393,484,485],{},"Major",[400,487,488],{},"1.x",[400,490,491],{},"2.0.0","): a breaking change. It comes with a new URL prefix, and ",[400,494,408],{}," keeps working alongside it (see ",[425,497,499],{"href":498},"#deprecation-and-removal","Deprecation and removal",").",[358,502,503,504,506],{},"Put the base URL, ",[400,505,408],{}," included, in one place in your configuration. The API sends no version header, and it doesn't need one: the path says which contract you are calling.",[362,508,510],{"id":509},"what-we-will-change-without-notice","What we will change without notice",[358,512,513],{},"These changes are backward compatible. They can arrive in any minor or patch version, and your client must not break when they do:",[452,515,516,522,528,534,539,545,550,560,566,576],{},[455,517,518,521],{},[393,519,520],{},"New operations",", on new paths.",[455,523,524,527],{},[393,525,526],{},"New fields in responses",", at any level of any object.",[455,529,530,533],{},[393,531,532],{},"New optional fields in requests."," Until you send them, nothing changes for you.",[455,535,536],{},[393,537,538],{},"New values in a response field that already has a fixed set of values.",[455,540,541,544],{},[393,542,543],{},"New error codes",", for situations that didn't have their own code before.",[455,546,547],{},[393,548,549],{},"New response headers.",[455,551,552,559],{},[393,553,554,555,558],{},"Different wording in ",[400,556,557],{},"message"," fields",", on successes and on errors.",[455,561,562,565],{},[393,563,564],{},"A different order"," of fields in an object, or of items in a list you didn't ask to have sorted.",[455,567,568,571,572,575],{},[393,569,570],{},"More organizations"," in ",[400,573,574],{},"GET \u002Fv1\u002Forganization",", and new countries, grades, exam categories and exams in the reference data.",[455,577,578,581],{},[393,579,580],{},"Relaxed validation",", meaning a request that used to be refused is now accepted.",[362,583,585],{"id":584},"what-counts-as-breaking","What counts as breaking",[358,587,588],{},"These changes need a new major version:",[452,590,591,594,601,604,611,614,617],{},[455,592,593],{},"Removing or renaming an operation, a path, a request field or a response field.",[455,595,596,597,600],{},"Changing a field's type or format, for example turning a string into an object, or changing the ",[400,598,599],{},"DD\u002FMM\u002FYYYY"," birth-date format.",[455,602,603],{},"Making an optional request field required, or adding a new required field.",[455,605,606,607,610],{},"Changing the status code or the ",[400,608,609],{},"error.code"," the API gives for an existing situation.",[455,612,613],{},"Requiring a different permission for an existing operation.",[455,615,616],{},"Changing the success or error envelope.",[455,618,619,620,623],{},"Changing what an operation does in a way that makes a correct client wrong, for example making ",[400,621,622],{},"POST \u002Fv1\u002F{organizationId}\u002Fapplication"," stop being idempotent.",[362,625,627],{"id":626},"build-a-tolerant-client","Build a tolerant client",[358,629,630,631,634],{},"The API is strict about what it accepts: it refuses any request field it doesn't know with ",[400,632,633],{},"400 bad_request",". Your client should be the opposite about what it receives. That asymmetry is what lets the API add things without breaking you.",[358,636,637,640,641,644,645,648,649,652,653,655],{},[393,638,639],{},"Ignore what you don't recognize."," Read the fields you need and ignore the rest. Don't validate responses against a closed schema that fails on an unknown field. That goes for errors too: ",[400,642,643],{},"error"," may carry an optional ",[400,646,647],{},"details"," object, and only where the operation says so. Today one does — ",[425,650,651],{"href":180},"createStudentImport"," puts the rows it cannot register there. Treat a ",[400,654,647],{}," you do not recognize as absent.",[358,657,658,661],{},[393,659,660],{},"Handle unknown values."," When a field holds a value you've never seen, fall back to a safe default. Don't throw.",[358,663,664,672,673,675,676,678],{},[393,665,666,667,669,670,413],{},"Branch on status and ",[400,668,609],{},", never on ",[400,671,557],{}," Messages are for people and may be reworded at any time. The ",[400,674,400],{}," values are stable identifiers. If you meet a ",[400,677,400],{}," your client doesn't know, handle it by its status class:",[680,681,686],"pre",{"className":682,"code":683,"language":684,"meta":685,"style":685},"language-js shiki shiki-themes github-light-high-contrast github-dark-high-contrast","function classify(status, error) {\n  switch (error?.code) {\n    case 'unauthorized':\n      return 'refresh-token';\n    case 'too_many_requests':\n      return 'wait';\n    case 'conflict':\n      return 'check-state';\n    \u002F\u002F ...the codes you handle specially\n    default:\n      if (status >= 500) return 'retry-later';\n      if (status >= 400) return 'fix-request';\n      return 'ok';\n  }\n}\n","js","",[400,687,688,717,726,739,751,761,771,781,791,798,806,833,854,864,870],{"__ignoreMap":685},[689,690,693,697,701,705,709,712,714],"span",{"class":691,"line":692},"line",1,[689,694,696],{"class":695},"sHUrx","function",[689,698,700],{"class":699},"sKwhi"," classify",[689,702,704],{"class":703},"suds8","(",[689,706,708],{"class":707},"soyes","status",[689,710,711],{"class":703},", ",[689,713,643],{"class":707},[689,715,716],{"class":703},") {\n",[689,718,720,723],{"class":691,"line":719},2,[689,721,722],{"class":695},"  switch",[689,724,725],{"class":703}," (error?.code) {\n",[689,727,729,732,736],{"class":691,"line":728},3,[689,730,731],{"class":695},"    case",[689,733,735],{"class":734},"sT6z2"," 'unauthorized'",[689,737,738],{"class":703},":\n",[689,740,742,745,748],{"class":691,"line":741},4,[689,743,744],{"class":695},"      return",[689,746,747],{"class":734}," 'refresh-token'",[689,749,750],{"class":703},";\n",[689,752,754,756,759],{"class":691,"line":753},5,[689,755,731],{"class":695},[689,757,758],{"class":734}," 'too_many_requests'",[689,760,738],{"class":703},[689,762,764,766,769],{"class":691,"line":763},6,[689,765,744],{"class":695},[689,767,768],{"class":734}," 'wait'",[689,770,750],{"class":703},[689,772,774,776,779],{"class":691,"line":773},7,[689,775,731],{"class":695},[689,777,778],{"class":734}," 'conflict'",[689,780,738],{"class":703},[689,782,784,786,789],{"class":691,"line":783},8,[689,785,744],{"class":695},[689,787,788],{"class":734}," 'check-state'",[689,790,750],{"class":703},[689,792,794],{"class":691,"line":793},9,[689,795,797],{"class":796},"sLBg1","    \u002F\u002F ...the codes you handle specially\n",[689,799,801,804],{"class":691,"line":800},10,[689,802,803],{"class":695},"    default",[689,805,738],{"class":703},[689,807,809,812,815,818,822,825,828,831],{"class":691,"line":808},11,[689,810,811],{"class":695},"      if",[689,813,814],{"class":703}," (status ",[689,816,817],{"class":695},">=",[689,819,821],{"class":820},"s-5SL"," 500",[689,823,824],{"class":703},") ",[689,826,827],{"class":695},"return",[689,829,830],{"class":734}," 'retry-later'",[689,832,750],{"class":703},[689,834,836,838,840,842,845,847,849,852],{"class":691,"line":835},12,[689,837,811],{"class":695},[689,839,814],{"class":703},[689,841,817],{"class":695},[689,843,844],{"class":820}," 400",[689,846,824],{"class":703},[689,848,827],{"class":695},[689,850,851],{"class":734}," 'fix-request'",[689,853,750],{"class":703},[689,855,857,859,862],{"class":691,"line":856},13,[689,858,744],{"class":695},[689,860,861],{"class":734}," 'ok'",[689,863,750],{"class":703},[689,865,867],{"class":691,"line":866},14,[689,868,869],{"class":703},"  }\n",[689,871,873],{"class":691,"line":872},15,[689,874,875],{"class":703},"}\n",[680,877,881],{"className":878,"code":879,"language":880,"meta":685,"style":685},"language-php shiki shiki-themes github-light-high-contrast github-dark-high-contrast","\u003C?php\nfunction classify(int $status, ?array $error): string\n{\n    return match ($error['code'] ?? null) {\n        'unauthorized' => 'refresh-token',\n        'too_many_requests' => 'wait',\n        'conflict' => 'check-state',\n        default => $status >= 500 ? 'retry-later' : ($status >= 400 ? 'fix-request' : 'ok'),\n    };\n}\n","php",[400,882,883,891,917,922,947,960,971,982,1022,1027],{"__ignoreMap":685},[689,884,885,888],{"class":691,"line":692},[689,886,887],{"class":695},"\u003C?",[689,889,890],{"class":820},"php\n",[689,892,893,895,897,899,902,905,908,911,914],{"class":691,"line":719},[689,894,696],{"class":695},[689,896,700],{"class":699},[689,898,704],{"class":703},[689,900,901],{"class":695},"int",[689,903,904],{"class":703}," $status, ",[689,906,907],{"class":695},"?array",[689,909,910],{"class":703}," $error)",[689,912,913],{"class":695},":",[689,915,916],{"class":695}," string\n",[689,918,919],{"class":691,"line":728},[689,920,921],{"class":703},"{\n",[689,923,924,927,930,933,936,939,942,945],{"class":691,"line":741},[689,925,926],{"class":695},"    return",[689,928,929],{"class":695}," match",[689,931,932],{"class":703}," ($error[",[689,934,935],{"class":734},"'code'",[689,937,938],{"class":703},"] ",[689,940,941],{"class":695},"??",[689,943,944],{"class":820}," null",[689,946,716],{"class":703},[689,948,949,952,955,957],{"class":691,"line":753},[689,950,951],{"class":734},"        'unauthorized'",[689,953,954],{"class":695}," =>",[689,956,747],{"class":734},[689,958,959],{"class":703},",\n",[689,961,962,965,967,969],{"class":691,"line":763},[689,963,964],{"class":734},"        'too_many_requests'",[689,966,954],{"class":695},[689,968,768],{"class":734},[689,970,959],{"class":703},[689,972,973,976,978,980],{"class":691,"line":773},[689,974,975],{"class":734},"        'conflict'",[689,977,954],{"class":695},[689,979,788],{"class":734},[689,981,959],{"class":703},[689,983,984,987,989,992,994,996,999,1001,1004,1007,1009,1011,1013,1015,1017,1019],{"class":691,"line":783},[689,985,986],{"class":695},"        default",[689,988,954],{"class":695},[689,990,991],{"class":703}," $status ",[689,993,817],{"class":695},[689,995,821],{"class":820},[689,997,998],{"class":695}," ?",[689,1000,830],{"class":734},[689,1002,1003],{"class":695}," :",[689,1005,1006],{"class":703}," ($status ",[689,1008,817],{"class":695},[689,1010,844],{"class":820},[689,1012,998],{"class":695},[689,1014,851],{"class":734},[689,1016,1003],{"class":695},[689,1018,861],{"class":734},[689,1020,1021],{"class":703},"),\n",[689,1023,1024],{"class":691,"line":793},[689,1025,1026],{"class":703},"    };\n",[689,1028,1029],{"class":691,"line":800},[689,1030,875],{"class":703},[358,1032,1033,1036],{},[393,1034,1035],{},"Send only documented fields."," Because unknown request fields are refused, don't send whole records copied from your own system \"just in case\". Build each request body from the documented fields.",[358,1038,1039,1042,1043,1046,1047,1050,1051,413],{},[393,1040,1041],{},"Treat ids as opaque."," Record ids (",[400,1044,1045],{},"_id",") are 24-character hexadecimal strings. Store them as strings, compare them as strings, and don't read meaning into them. The same goes for the other identifiers you receive, such as a student's ",[400,1048,1049],{},"username"," or a document's ",[400,1052,1053],{},"shortId",[358,1055,1056,1059,1060,1063,1064,1067],{},[393,1057,1058],{},"Treat links as opaque."," Follow ",[400,1061,1062],{},"documentation_url"," in an error, and the ",[400,1065,1066],{},"url"," of a sign-in link, as they are. Don't build them yourself or parse them.",[358,1069,1070,1073,1074,1077,1078,413],{},[393,1071,1072],{},"Treat a missing field as missing."," An exam nobody priced has no ",[400,1075,1076],{},"price"," field at all, which is not the same as a price of ",[400,1079,1080],{},"0",[362,1082,499],{"id":1083},"deprecation-and-removal",[358,1085,1086],{},"When something is going to be removed or changed in a breaking way:",[1088,1089,1090,1102,1122],"ol",{},[455,1091,1092,1097,1098,1101],{},[393,1093,1094,1095],{},"We announce it in the ",[425,1096,427],{"href":349}," at least ",[393,1099,1100],{},"six months"," before it changes, with what is affected and what to use instead.",[455,1103,1104,1115,1116,1118,1119,1121],{},[393,1105,1106,1107,1110,1111,1114],{},"Responses from the affected operations carry ",[400,1108,1109],{},"Deprecation"," and ",[400,1112,1113],{},"Sunset"," headers"," for that whole period. ",[400,1117,1109],{}," marks the operation as deprecated, and ",[400,1120,1113],{}," gives the date after which it may stop working.",[455,1123,1124,1127,1128,1130,1131,1133,1134,1136,1137,1139],{},[393,1125,1126],{},"The removal itself only happens in a new major version."," Nothing is removed from ",[400,1129,408],{},". When ",[400,1132,412],{}," exists, ",[400,1135,408],{}," keeps working. Retiring ",[400,1138,408],{}," altogether is also a removal, so it follows the same rule: at least six months' notice in the changelog.",[358,1141,1142,1143,1145],{},"No operation is deprecated at the moment. A deprecation is always announced in the ",[425,1144,427],{"href":349}," first.",[358,1147,1148],{},"Have your client watch for the headers, so a deprecation reaches someone who can act on it even if nobody reads the changelog that month:",[680,1150,1152],{"className":682,"code":1151,"language":684,"meta":685,"style":685},"\u002F\u002F Wrap your HTTP call once; log every deprecated operation you still use.\nfunction warnIfDeprecated(method, path, res) {\n  const deprecation = res.headers.get('deprecation');\n  if (!deprecation) return;\n  const sunset = res.headers.get('sunset') ?? 'no date given';\n  console.warn(`[main-team-api] ${method} ${path} is deprecated (sunset: ${sunset}). See https:\u002F\u002Fhub.main-team.org\u002Fapi\u002Fchangelog`);\n}\n",[400,1153,1154,1159,1183,1208,1225,1252,1283],{"__ignoreMap":685},[689,1155,1156],{"class":691,"line":692},[689,1157,1158],{"class":796},"\u002F\u002F Wrap your HTTP call once; log every deprecated operation you still use.\n",[689,1160,1161,1163,1166,1168,1171,1173,1176,1178,1181],{"class":691,"line":719},[689,1162,696],{"class":695},[689,1164,1165],{"class":699}," warnIfDeprecated",[689,1167,704],{"class":703},[689,1169,1170],{"class":707},"method",[689,1172,711],{"class":703},[689,1174,1175],{"class":707},"path",[689,1177,711],{"class":703},[689,1179,1180],{"class":707},"res",[689,1182,716],{"class":703},[689,1184,1185,1188,1191,1194,1197,1200,1202,1205],{"class":691,"line":728},[689,1186,1187],{"class":695},"  const",[689,1189,1190],{"class":820}," deprecation",[689,1192,1193],{"class":695}," =",[689,1195,1196],{"class":703}," res.headers.",[689,1198,1199],{"class":699},"get",[689,1201,704],{"class":703},[689,1203,1204],{"class":734},"'deprecation'",[689,1206,1207],{"class":703},");\n",[689,1209,1210,1213,1215,1218,1221,1223],{"class":691,"line":741},[689,1211,1212],{"class":695},"  if",[689,1214,460],{"class":703},[689,1216,1217],{"class":695},"!",[689,1219,1220],{"class":703},"deprecation) ",[689,1222,827],{"class":695},[689,1224,750],{"class":703},[689,1226,1227,1229,1232,1234,1236,1238,1240,1243,1245,1247,1250],{"class":691,"line":753},[689,1228,1187],{"class":695},[689,1230,1231],{"class":820}," sunset",[689,1233,1193],{"class":695},[689,1235,1196],{"class":703},[689,1237,1199],{"class":699},[689,1239,704],{"class":703},[689,1241,1242],{"class":734},"'sunset'",[689,1244,824],{"class":703},[689,1246,941],{"class":695},[689,1248,1249],{"class":734}," 'no date given'",[689,1251,750],{"class":703},[689,1253,1254,1257,1260,1262,1265,1267,1270,1272,1275,1278,1281],{"class":691,"line":763},[689,1255,1256],{"class":703},"  console.",[689,1258,1259],{"class":699},"warn",[689,1261,704],{"class":703},[689,1263,1264],{"class":734},"`[main-team-api] ${",[689,1266,1170],{"class":703},[689,1268,1269],{"class":734},"} ${",[689,1271,1175],{"class":703},[689,1273,1274],{"class":734},"} is deprecated (sunset: ${",[689,1276,1277],{"class":703},"sunset",[689,1279,1280],{"class":734},"}). See https:\u002F\u002Fhub.main-team.org\u002Fapi\u002Fchangelog`",[689,1282,1207],{"class":703},[689,1284,1285],{"class":691,"line":773},[689,1286,875],{"class":703},[680,1288,1290],{"className":878,"code":1289,"language":880,"meta":685,"style":685},"\u003C?php\n\u002F\u002F $headers: response headers with lower-cased names, as collected by the retry helper.\nfunction warnIfDeprecated(string $method, string $path, array $headers): void\n{\n    if (!isset($headers['deprecation'])) {\n        return;\n    }\n    $sunset = $headers['sunset'] ?? 'no date given';\n    error_log(\"[main-team-api] {$method} {$path} is deprecated (sunset: {$sunset}). See https:\u002F\u002Fhub.main-team.org\u002Fapi\u002Fchangelog\");\n}\n",[400,1291,1292,1298,1303,1333,1337,1357,1364,1369,1390,1420],{"__ignoreMap":685},[689,1293,1294,1296],{"class":691,"line":692},[689,1295,887],{"class":695},[689,1297,890],{"class":820},[689,1299,1300],{"class":691,"line":719},[689,1301,1302],{"class":796},"\u002F\u002F $headers: response headers with lower-cased names, as collected by the retry helper.\n",[689,1304,1305,1307,1309,1311,1314,1317,1319,1322,1325,1328,1330],{"class":691,"line":728},[689,1306,696],{"class":695},[689,1308,1165],{"class":699},[689,1310,704],{"class":703},[689,1312,1313],{"class":695},"string",[689,1315,1316],{"class":703}," $method, ",[689,1318,1313],{"class":695},[689,1320,1321],{"class":703}," $path, ",[689,1323,1324],{"class":695},"array",[689,1326,1327],{"class":703}," $headers)",[689,1329,913],{"class":695},[689,1331,1332],{"class":695}," void\n",[689,1334,1335],{"class":691,"line":741},[689,1336,921],{"class":703},[689,1338,1339,1342,1344,1346,1349,1352,1354],{"class":691,"line":753},[689,1340,1341],{"class":695},"    if",[689,1343,460],{"class":703},[689,1345,1217],{"class":695},[689,1347,1348],{"class":820},"isset",[689,1350,1351],{"class":703},"($headers[",[689,1353,1204],{"class":734},[689,1355,1356],{"class":703},"])) {\n",[689,1358,1359,1362],{"class":691,"line":763},[689,1360,1361],{"class":695},"        return",[689,1363,750],{"class":703},[689,1365,1366],{"class":691,"line":773},[689,1367,1368],{"class":703},"    }\n",[689,1370,1371,1374,1377,1380,1382,1384,1386,1388],{"class":691,"line":783},[689,1372,1373],{"class":703},"    $sunset ",[689,1375,1376],{"class":695},"=",[689,1378,1379],{"class":703}," $headers[",[689,1381,1242],{"class":734},[689,1383,938],{"class":703},[689,1385,941],{"class":695},[689,1387,1249],{"class":734},[689,1389,750],{"class":703},[689,1391,1392,1395,1397,1400,1403,1406,1409,1412,1415,1418],{"class":691,"line":793},[689,1393,1394],{"class":820},"    error_log",[689,1396,704],{"class":703},[689,1398,1399],{"class":734},"\"[main-team-api] {",[689,1401,1402],{"class":703},"$method",[689,1404,1405],{"class":734},"} {",[689,1407,1408],{"class":703},"$path",[689,1410,1411],{"class":734},"} is deprecated (sunset: {",[689,1413,1414],{"class":703},"$sunset",[689,1416,1417],{"class":734},"}). See https:\u002F\u002Fhub.main-team.org\u002Fapi\u002Fchangelog\"",[689,1419,1207],{"class":703},[689,1421,1422],{"class":691,"line":800},[689,1423,875],{"class":703},[362,1425,1427],{"id":1426},"staying-informed","Staying informed",[452,1429,1430,1439,1448,1454],{},[455,1431,1432,1436,1437,413],{},[393,1433,436,1434],{},[425,1435,427],{"href":349}," lists every version, with breaking changes marked. Each version has its own page, such as ",[425,1438,463],{"href":446},[455,1440,1441,1447],{},[393,1442,436,1443,1110,1445,1114],{},[400,1444,1109],{},[400,1446,1113],{}," reach your logs even when nobody reads the changelog.",[455,1449,1450,1453],{},[393,1451,1452],{},"The version badge on these pages"," tells you which version you are reading about.",[455,1455,1456,1459,1460,1466,1467,413],{},[393,1457,1458],{},"Questions"," go to ",[393,1461,1462],{},[425,1463,1465],{"href":1464},"mailto:info@main-team.org","info@main-team.org",". See ",[425,1468,345],{"href":346},[1470,1471,1472],"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 .soyes, html code.shiki .soyes{--shiki-default:#702C00;--shiki-dark:#FFB757}html pre.shiki code .sT6z2, html code.shiki .sT6z2{--shiki-default:#032563;--shiki-dark:#ADDCFF}html pre.shiki code .sLBg1, html code.shiki .sLBg1{--shiki-default:#66707B;--shiki-dark:#BDC4CC}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);}",{"title":685,"searchDepth":719,"depth":728,"links":1474},[1475,1476,1477,1478,1479,1480],{"id":364,"depth":719,"text":365},{"id":509,"depth":719,"text":510},{"id":584,"depth":719,"text":585},{"id":626,"depth":719,"text":627},{"id":1083,"depth":719,"text":499},{"id":1426,"depth":719,"text":1427},"How the API is versioned, what counts as a breaking change, how deprecations are announced, and how to write a client that keeps working.","md",{},true,[],"70",{"title":353,"description":1481},"api\u002Fversioning","RezE1pmpJj4b4FHvdPoQ8Iz_FTAJXQiXIYs0bt0jDAs",[],1791554614961]