[{"data":1,"prerenderedAt":1175},["ShallowReactive",2],{"api-nav":3,"api-guide:\u002Fapi\u002Fclients":351,"api-spec:guide:\u002Fapi\u002Fclients":1174},[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":1165,"extension":1166,"meta":1167,"navTitle":9,"navigation":1168,"operations":1169,"order":1170,"path":306,"section":302,"seo":1171,"status":14,"stem":1172,"__hash__":1173},"apiGuides\u002Fapi\u002Fclients\u002Findex.md","Client libraries",{"type":355,"value":356,"toc":1140},"minimark",[357,366,369,374,450,471,475,496,506,510,696,703,707,714,730,734,740,750,754,808,811,815,822,851,855,858,863,892,896,902,921,924,928,960,964,992,996,1018,1022,1043,1047,1055,1059,1082,1086,1093,1097,1114,1118],[358,359,360,361,365],"p",{},"There are two official clients for the Main Team API, one for Node.js and one for PHP. You don't\nneed either of them. Every operation is plain HTTPS with a JSON envelope, and the\n",[362,363,364],"a",{"href":121},"API reference"," describes all of it. A client handles four things you would\notherwise write yourself: signing tokens, unwrapping the response envelope, turning error\nresponses into typed exceptions, and refusing calls that can't succeed before they are sent.",[358,367,368],{},"This page tells you what the clients do, how to get them, and when to skip them. The rules\nat the end apply whether or not you use a client, so read them either way.",[370,371,373],"h2",{"id":372},"the-packages","The packages",[375,376,377,399],"table",{},[378,379,380],"thead",{},[381,382,383,387,390,393,396],"tr",{},[384,385,386],"th",{},"Language",[384,388,389],{},"Package",[384,391,392],{},"Install",[384,394,395],{},"Needs",[384,397,398],{},"Status",[400,401,402,424],"tbody",{},[381,403,404,408,414,419,422],{},[405,406,407],"td",{},"Node.js \u002F TypeScript",[405,409,410],{},[411,412,413],"code",{},"@main-team\u002Fapi-client",[405,415,416],{},[411,417,418],{},"npm install @main-team\u002Fapi-client",[405,420,421],{},"Node.js 20 or newer",[405,423,14],{},[381,425,426,428,433,438,448],{},[405,427,311],{},[405,429,430],{},[411,431,432],{},"main-team\u002Fapi-client",[405,434,435],{},[411,436,437],{},"composer require main-team\u002Fapi-client",[405,439,440,441,444,445],{},"PHP 8.1 or newer, ",[411,442,443],{},"ext-curl",", ",[411,446,447],{},"ext-json",[405,449,14],{},[451,452,453,460,466],"ul",{},[454,455,456,459],"li",{},[362,457,458],{"href":309},"Node.js client",": ESM, CommonJS and TypeScript types in one package, with no\nruntime dependencies.",[454,461,462,465],{},[362,463,464],{"href":312},"PHP client",": no dependencies beyond two standard extensions, and a pluggable\ntransport if you want PSR-18 or a proxy.",[454,467,468,470],{},[362,469,314],{"href":315},": what a client has to do, a minimal client in\nNode.js and in PHP, and a conformance checklist.",[370,472,474],{"id":473},"getting-access","Getting access",[358,476,477,478,482,483,486,487,490,491,495],{},"Both packages are ",[479,480,481],"strong",{},"private",". Access is issued with your API credentials: the operator who gives\nyou your ",[411,484,485],{},"apiKey"," and ",[411,488,489],{},"apiSecret"," also gives you access to the packages. If you have credentials\nbut can't install a package, write to ",[362,492,494],{"href":493},"mailto:info@main-team.org","info@main-team.org"," and say\nwhich package you need.",[497,498,500],"callout",{"type":499},"note",[358,501,502,503,505],{},"There is no self-service sign-up for the API or the packages. Accounts are created by an operator\nby arrangement. The ",[362,504,12],{"href":13}," explains what you receive and what to do with it.",[370,507,509],{"id":508},"what-a-client-does-for-you","What a client does for you",[375,511,512,525],{},[378,513,514],{},[381,515,516,519,522],{},[384,517,518],{},"Concern",[384,520,521],{},"Without a client",[384,523,524],{},"With a client",[400,526,527,555,570,597,630,647,665,682],{},[381,528,529,531,547],{},[405,530,19],{},[405,532,533,534,536,537,486,540,543,544,546],{},"You sign an HS256 token with your ",[411,535,489],{},", set ",[411,538,539],{},"kid",[411,541,542],{},"sub"," to your ",[411,545,485],{},", and replace it before it expires.",[405,548,549,550,486,552,554],{},"You pass ",[411,551,485],{},[411,553,489],{}," once. The client signs short-lived tokens for you.",[381,556,557,560,567],{},[405,558,559],{},"Base URL",[405,561,562,563,566],{},"You join ",[411,564,565],{},"https:\u002F\u002Fapi.main-team.org\u002Fv1"," and the path.",[405,568,569],{},"Fixed. The client can't be pointed anywhere else (see below).",[381,571,572,574,588],{},[405,573,22],{},[405,575,576,577,580,581,584,585,587],{},"You call ",[411,578,579],{},"GET \u002Fv1\u002Forganization"," and map slugs to ",[411,582,583],{},"_id","s, because paths take the ",[411,586,583],{}," only.",[405,589,576,590,593,594,596],{},[411,591,592],{},"organization('stem')"," and the client looks the ",[411,595,583],{}," up and caches it.",[381,598,599,602,623],{},[405,600,601],{},"Response envelope",[405,603,604,605,444,608,486,611,614,615,618,619,622],{},"You read ",[411,606,607],{},"data",[411,609,610],{},"message",[411,612,613],{},"pagination"," out of ",[411,616,617],{},"{ success, message, data, pagination? }",", and treat ",[411,620,621],{},"validate-me"," as the one JSON route without an envelope.",[405,624,625,626,629],{},"Methods return the data, or ",[411,627,628],{},"{ data, pagination }"," for lists.",[381,631,632,634,641],{},[405,633,42],{},[405,635,636,637,640],{},"You parse ",[411,638,639],{},"{ error: { code, message, documentation_url, request_id } }",".",[405,642,643,644,646],{},"You catch typed exceptions that carry the same ",[411,645,411],{}," and HTTP status.",[381,648,649,652,658],{},[405,650,651],{},"Impossible calls",[405,653,654,655,640],{},"The server answers ",[411,656,657],{},"400 bad_request",[405,659,660,661,664],{},"The client throws the same ",[411,662,663],{},"bad_request"," \u002F 400 before sending, so one handler covers both.",[381,666,667,669,679],{},[405,668,39],{},[405,670,671,672,675,676,640],{},"You loop ",[411,673,674],{},"page"," until ",[411,677,678],{},"totalPages",[405,680,681],{},"A helper walks every page for you.",[381,683,684,687,693],{},[405,685,686],{},"Downloads",[405,688,689,690,640],{},"You stream the PDF and read the file name from ",[411,691,692],{},"Content-Disposition",[405,694,695],{},"You get a file object with the server's file name and the bytes.",[358,697,698,699,702],{},"A client ",[479,700,701],{},"does not"," change the API's rules. It never invents a restriction the API doesn't\nhave, and it doesn't hide one the API does have. A registration with a duplicate email, an exam the\nstudent can't take, or a paid application you try to delete all fail the same way through a\nclient as over HTTP. The difference is that you get a typed exception instead of a JSON body.",[370,704,706],{"id":705},"why-the-base-url-is-locked","Why the base URL is locked",[358,708,709,710,713],{},"Neither client has a ",[411,711,712],{},"baseUrl"," option. Every request carries a bearer token that is valid for your\nwhole account until it expires. If a client could be pointed at another host, by a typo, a\nmisread environment variable or a malicious configuration, that host would receive a token it\ncould replay as you. Fixing the host in the client removes that risk.",[497,715,716],{"type":499},[358,717,718,719,722,723,726,727,640],{},"The sandbox, at ",[411,720,721],{},"https:\u002F\u002Fapisnd.main-team.org\u002Fv1",", has its own accounts, seeded reference data, no\nemails sent and no real payments. The clients accept only the production base URL, so they can't\nreach it. For the sandbox, call the API over HTTPS directly, or use a client of your own such as\nthe one in ",[362,724,725],{"href":315},"Build your own client",". See\n",[362,728,16],{"href":729},"\u002Fapi\u002Fenvironments#sandbox",[370,731,733],{"id":732},"server-side-only","Server-side only",[358,735,736,737,739],{},"Use the clients from your servers only. In production the API sends no CORS headers, so a web\npage on another origin can't call it. That is deliberate: a browser page that could call the API\nwould have to carry your ",[411,738,489],{},", which would hand it to every visitor. The same applies to\nmobile and desktop apps: anything you ship to a user can be unpacked.",[358,741,742,743,746,747,749],{},"If your users need to reach the student panel from your site, your server mints a\n",[362,744,745],{"href":81},"sign-in link"," and redirects the browser to it. The\n",[362,748,103],{"href":104}," tutorial shows how.",[370,751,753],{"id":752},"client-or-plain-http","Client or plain HTTP?",[375,755,756,766],{},[378,757,758],{},[381,759,760,763],{},[384,761,762],{},"Use a client when",[384,764,765],{},"Call the API directly when",[400,767,768,778,786,794],{},[381,769,770,773],{},[405,771,772],{},"Your backend is Node.js or PHP.",[405,774,775,776,640],{},"Your backend is another language: see ",[362,777,314],{"href":315},[381,779,780,783],{},[405,781,782],{},"You want typed errors and pre-validated calls.",[405,784,785],{},"You already have an HTTP layer with retries, logging and metrics that you want to reuse.",[381,787,788,791],{},[405,789,790],{},"You want organization slugs resolved for you.",[405,792,793],{},"You need a route before your package version supports it.",[381,795,796,799],{},[405,797,798],{},"You'd rather not write token caching.",[405,800,801,802,486,805,640],{},"You're scripting a one-off with ",[411,803,804],{},"curl",[411,806,807],{},"openssl",[358,809,810],{},"Mixing both is fine. The API doesn't know or care which one sent a request.",[370,812,814],{"id":813},"keeping-a-client-current","Keeping a client current",[358,816,817,818,821],{},"The clients carry the same list of routes as the API. When the API gains a route or a field, the\n",[362,819,820],{"href":349},"changelog"," says so, and a client release follows. Two things to know:",[451,823,824,832],{},[454,825,826,829,830,640],{},[479,827,828],{},"Tolerate what you don't recognize."," New fields can appear in responses without notice, because\nadding a field is not a breaking change. The PHP client's models keep fields they don't model\ninstead of failing on them, and your own code should do the same. See\n",[362,831,54],{"href":55},[454,833,834,837,838,486,841,844,845,847,848,850],{},[479,835,836],{},"Watch for deprecations."," A route or field that is going away is announced at least 6 months\nahead in the changelog, and responses from it carry ",[411,839,840],{},"Deprecation",[411,842,843],{},"Sunset"," headers. Removals\nhappen only in a new major version of the API. The ",[362,846,820],{"href":349}," lists every\nversion, and the ",[362,849,364],{"href":121}," shows the one these pages describe.",[370,852,854],{"id":853},"rules-that-apply-in-any-language","Rules that apply in any language",[358,856,857],{},"These are properties of the API, not of the clients. Each one links to the guide that covers it\nin full.",[859,860,862],"h3",{"id":861},"every-studentid-is-the-core-id","Every studentId is the core id",[358,864,865,866,868,869,872,873,876,877,879,880,883,884,889,890,640],{},"Each organization keeps its own copy of a student, under a different ",[411,867,583],{},". Every ",[411,870,871],{},"studentId"," you\nsend, on every route, is the id that registration (",[411,874,875],{},"POST \u002Fv1\u002Fstudent",") returned. Never use an id\nread from an organization's own records. The student on an application is that organization's\ncopy: its ",[411,878,583],{}," is the organization's id for them, and its ",[411,881,882],{},"mainId"," is the id you registered them\nwith. ",[479,885,886,887,640],{},"Match on ",[411,888,882],{}," See ",[362,891,36],{"href":37},[859,893,895],{"id":894},"a-student-signs-in-once-before-organization-actions","A student signs in once before organization actions",[358,897,898,899,901],{},"Nothing in an organization refers to a student until that organization holds a copy of them, and\nthe copy is created the first time the student follows a ",[362,900,745],{"href":81},"\ninto that organization. Until then:",[451,903,904,911,918],{},[454,905,906,907,910],{},"Creating an application, or listing that student's applications, certificates or reports, answers\n",[411,908,909],{},"409 conflict",". The message tells you to send a sign-in link first.",[454,912,913,914,917],{},"Linking a supervisor answers ",[411,915,916],{},"404 not_found",", the one answer that route gives to every refusal.",[454,919,920],{},"The organization's application lists leave the student out, without an error.",[358,922,923],{},"The organization's student list is different. It shows every student of yours who has access to\nthat organization, whether or not they have signed in there.",[859,925,927],{"id":926},"sign-in-links-are-single-use-and-short-lived","Sign-in links are single-use and short-lived",[358,929,930,933,934,937,938,941,942,945,946,949,950,953,954,957,958,640],{},[411,931,932],{},"POST \u002Fv1\u002F{organizationId}\u002Fauth\u002Fsignin"," returns a URL that signs the student in ",[479,935,936],{},"once"," and\nexpires ",[479,939,940],{},"120 seconds"," after it was issued. Redirect the browser to it immediately. Don't store\nit, email it, log it or paste it into chat, where a link preview can use it up. Mint a new one\nevery time. A student whose email address isn't confirmed yet still gets a link. A student with no\naccess to that organization gets ",[411,943,944],{},"403 forbidden"," instead. The optional ",[411,947,948],{},"redirect"," must be a path on\nthe organization's site that starts with a single ",[411,951,952],{},"\u002F",", such as ",[411,955,956],{},"\u002Fdashboard",". A full URL is refused\nwith ",[411,959,657],{},[859,961,963],{"id":962},"the-exam-listing-is-not-a-catalog","The exam listing is not a catalog",[358,965,966,969,970,973,974,977,978,981,982,985,986,989,990,640],{},[411,967,968],{},"GET \u002Fv1\u002F{organizationId}\u002Fexam"," returns only exams that are ",[479,971,972],{},"open"," for application. A closed\nexam can't be read by id or applied to. To choose an exam for a particular student, use the\nper-student picker, ",[411,975,976],{},"GET \u002Fv1\u002F{organizationId}\u002Fexam\u002Favailable\u002F{studentId}",". It applies that\nstudent's grade and country and leaves out what they already hold. Every leaf of its tree carries a\n",[411,979,980],{},"matchedExam","; send ",[411,983,984],{},"matchedExam._id"," as ",[411,987,988],{},"examId",". See ",[362,991,83],{"href":84},[859,993,995],{"id":994},"applications-are-limited-to-what-the-picker-offers","Applications are limited to what the picker offers",[358,997,998,1001,1002,1004,1005,1008,1009,1012,1013,726,1016,640],{},[411,999,1000],{},"POST \u002Fv1\u002F{organizationId}\u002Fapplication"," runs the same checks as the picker. An exam the picker\nwouldn't offer is refused with ",[411,1003,909],{},", and the message says which rule failed. Applying\ntwice to the same exam is safe: the second call answers ",[411,1006,1007],{},"200"," with ",[411,1010,1011],{},"\"Application already exists.\"","\nand returns the existing application, where the first answered ",[411,1014,1015],{},"201",[362,1017,86],{"href":87},[859,1019,1021],{"id":1020},"registering-the-same-email-twice-is-a-conflict","Registering the same email twice is a conflict",[358,1023,1024,1026,1027,1030,1031,1033,1034,1036,1037,1040,1041,640],{},[411,1025,875],{}," is ",[479,1028,1029],{},"not"," idempotent. If the email is already registered to your account, you\nget ",[411,1032,909],{}," and the message names the ",[411,1035,583],{}," of the student who holds it. Fetch or update\nthat student instead of retrying. If a different account registered the address, you get the same\n",[411,1038,1039],{},"409"," without an id: email addresses are unique across the whole platform. A retry loop won't help\neither way. See ",[362,1042,62],{"href":63},[859,1044,1046],{"id":1045},"unknown-fields-are-errors","Unknown fields are errors",[358,1048,1049,1050,1052,1053,640],{},"A request body with any property the API doesn't declare is refused with ",[411,1051,657],{},", and\nthe message names the property. Send the documented fields, not a whole record copied from your\nown system. See ",[362,1054,33],{"href":34},[859,1056,1058],{"id":1057},"passwords-are-optional-and-need-an-extra-permission","Passwords are optional, and need an extra permission",[358,1060,1061,1062,1065,1066,1069,1070,1073,1074,1076,1077,1079,1080,640],{},"Only two routes set a password: registration (optional ",[411,1063,1064],{},"password",") and\n",[411,1067,1068],{},"PUT \u002Fv1\u002Fstudent\u002F{studentId}\u002Fpassword",". Setting a password either way needs the ",[411,1071,1072],{},"auth\u002Fsignin","\npermission on mto, the permission a sign-in link needs. A registration that carries a password\nwithout that permission is refused with ",[411,1075,944],{},". A password must be at least 5 characters and at most 72 bytes,\nand must not contain the student's name, username or email address. Once the student has confirmed\ntheir email address, the password route answers ",[411,1078,909],{},", and you send them a sign-in link\ninstead. See ",[362,1081,68],{"href":69},[859,1083,1085],{"id":1084},"a-403-is-a-permission-not-a-token","A 403 is a permission, not a token",[358,1087,1088,1090,1091,640],{},[411,1089,944],{}," means the token is fine but your account lacks the permission for that route on\nthat organization. Re-signing won't help. Ask your operator for the role. See\n",[362,1092,25],{"href":26},[859,1094,1096],{"id":1095},"a-429-means-wait","A 429 means wait",[358,1098,1099,1100,1103,1104,1107,1108,1111,1112,640],{},"Each account may make ",[479,1101,1102],{},"100 requests per 60 seconds to each operation",", and each operation is\ncounted on its own. The count belongs to your\naccount, not to your IP address, so spreading calls over several servers doesn't raise it. After a\n",[411,1105,1106],{},"429 too_many_requests",", wait the number of seconds in ",[411,1109,1110],{},"Retry-After",". A request sent sooner is\nrefused too. See ",[362,1113,45],{"href":46},[370,1115,1117],{"id":1116},"getting-help","Getting help",[358,1119,1120,1121,1124,1125,1128,1129,1131,1132,1134,1135,1137,1138,640],{},"When something fails, keep the ",[411,1122,1123],{},"request_id"," from the error body (it's also the ",[411,1126,1127],{},"X-Request-Id","\nresponse header) and the time in UTC. Send them to\n",[362,1130,494],{"href":493}," with the operation you called. Never send your\n",[411,1133,489],{},", a token or a sign-in link. See ",[362,1136,345],{"href":346}," and\n",[362,1139,342],{"href":343},{"title":1141,"searchDepth":1142,"depth":1143,"links":1144},"",2,3,[1145,1146,1147,1148,1149,1150,1151,1152,1164],{"id":372,"depth":1142,"text":373},{"id":473,"depth":1142,"text":474},{"id":508,"depth":1142,"text":509},{"id":705,"depth":1142,"text":706},{"id":732,"depth":1142,"text":733},{"id":752,"depth":1142,"text":753},{"id":813,"depth":1142,"text":814},{"id":853,"depth":1142,"text":854,"children":1153},[1154,1155,1156,1157,1158,1159,1160,1161,1162,1163],{"id":861,"depth":1143,"text":862},{"id":894,"depth":1143,"text":895},{"id":926,"depth":1143,"text":927},{"id":962,"depth":1143,"text":963},{"id":994,"depth":1143,"text":995},{"id":1020,"depth":1143,"text":1021},{"id":1045,"depth":1143,"text":1046},{"id":1057,"depth":1143,"text":1058},{"id":1084,"depth":1143,"text":1085},{"id":1095,"depth":1143,"text":1096},{"id":1116,"depth":1142,"text":1117},"The official Node.js and PHP clients for the Main Team API, how to get access, and when to call the API over plain HTTP instead.","md",{},true,[],"10",{"title":353,"description":1165},"api\u002Fclients\u002Findex","bmoh3IWbvGKmcfsSprXULoEBq2E2DSxVgT1MP0zU7O4",[],1791554615371]