manak.

The hackathon workspace

API reference

Every operation this deployment performs. The same list drives the HTML forms, the JSON API and the OpenAPI document; there is no operation in one that is missing from the others.

A JSON response comes from the route as written below. The same route without the /api prefix is the browser's: a GET renders a page there, and a POST takes the form and answers with a redirect to the page that shows what it did.

OperationRouteCallable by
appeals.listGET /api/events/:event/appealsanyone, signed in or not
appeals.openPOST /api/events/:event/appealsa participant of the event
appeals.resolvePOST /api/events/:event/appeals/:appeal/resolvea organizer of the event
assignments.drawPOST /api/events/:event/assignmentsa organizer of the event
assignments.previewGET /api/events/:event/assignments/previewa organizer of the event
auth.linkGET /api/signin/:tokenanyone, signed in or not
auth.requestPOST /api/signinanyone, signed in or not
auth.sessionPOST /api/sessionanyone, signed in or not
auth.signinGET /api/signinanyone, signed in or not
auth.signoutPOST /api/signoutany signed-in account
auth.whoamiGET /api/whoamiany signed-in account
awards.decidePOST /api/events/:event/awardsa organizer of the event
awards.listGET /api/events/:event/awardsanyone, signed in or not
ballots.savePOST /api/events/:event/projects/:project/ballota judge of the event, the judge the ballot belongs to, while judging is open
comments.addPOST /api/events/:event/projects/:project/commentsany signed-in account
comments.hidePOST /api/events/:event/projects/:project/comments/hidea organizer of the event
duels.decidePOST /api/events/:event/duela judge of the event, while judging is open
duels.nextGET /api/events/:event/duela judge of the event
duplicates.listGET /api/events/:event/manage/duplicatesa organizer of the event
duplicates.triagePOST /api/events/:event/manage/duplicates/triagea organizer of the event
events.clockGET /api/events/:event/clocka organizer of the event
events.createPOST /api/eventsan account this deployment's operator listed as a founder
events.dashboardGET /api/events/:event/dashboarda organizer of the event
events.invitePOST /api/events/:event/invitationsa organizer of the event
events.judgesGET /api/events/:event/judgesa organizer of the event
events.listGET /api/eventsanyone, signed in or not
events.mineGET /api/mineany signed-in account
events.ping_webhookPOST /api/events/:event/webhooks/pinga organizer of the event
events.revoke_rolePOST /api/events/:event/roles/revokea organizer of the event
events.showGET /api/events/:eventanyone, signed in or not
events.updatePOST /api/events/:eventa organizer of the event
events.warp_clockPOST /api/events/:event/clock/warpa organizer of the event
events.webhooksGET /api/events/:event/webhooksa organizer of the event
exports.archive_manifestGET /api/events/:event/archivea organizer of the event
exports.audit_csvGET /api/events/:event/export/audit.csva organizer of the event
exports.downloadGET /api/events/:event/csv/:stagea organizer of the event
exports.projects_csvGET /api/events/:event/export/projects.csva organizer of the event
exports.registrations_csvGET /api/events/:event/export/registrations.csva organizer of the event
exports.results_csvGET /api/events/:event/export/results.csva organizer of the event
exports.scores_csvGET /api/events/:event/export/scores.csva organizer of the event
exports.teams_csvGET /api/events/:event/export/teams.csva organizer of the event
judges.configurePOST /api/events/:event/judges/configurea organizer of the event
judges.recusalPOST /api/events/:event/judges/recusala organizer of the event
judges.rosterGET /api/events/:event/judges/rostera organizer of the event
judges.self_recusalPOST /api/events/:event/judging/:project/recusea judge of the event, while judging is open
judging.queueGET /api/events/:event/judginga judge of the event
projects.createPOST /api/events/:event/projectsa participant of the event, while submissions are open
projects.disqualifyPOST /api/events/:event/projects/:project/disqualifya organizer of the event
projects.listGET /api/events/:event/projectsanyone, signed in or not
projects.pullPOST /api/events/:event/projects/:project/pulla organizer of the event
projects.showGET /api/events/:event/projects/:projectanyone, signed in or not
projects.submitPOST /api/events/:event/projects/:project/submita participant of the event, on the project's own team, while submissions are open
projects.updatePOST /api/events/:event/projects/:projecta participant of the event, on the project's own team, while submissions are open
projects.withdrawPOST /api/events/:event/projects/:project/withdrawa participant of the event, on the project's own team, while submissions are open
results.certificate_statusGET /api/events/:event/certificates/statusanyone, signed in or not
results.certificate_studioGET /api/events/:event/certificates/studioa organizer of the event
results.certificatesGET /api/events/:event/certificatesa organizer of the event
results.confidenceGET /api/events/:event/results/confidenceanyone, signed in or not
results.configure_certificate_templatePOST /api/events/:event/certificates/templatea organizer of the event
results.correct_certPOST /api/events/:event/certificates/correctionsa organizer of the event
results.evidence_packetGET /api/events/:event/results/evidenceanyone, signed in or not
results.explainGET /api/events/:event/results/explaina participant of the event
results.historyGET /api/events/:event/results/historyanyone, signed in or not
results.issue_certsPOST /api/events/:event/certificatesa organizer of the event
results.judge_evidencePOST /api/events/:event/results/judge-evidencea organizer of the event
results.preflightGET /api/events/:event/results/preflighta organizer of the event
results.public_certificateGET /api/events/:event/certificates/:serialanyone, signed in or not
results.publishPOST /api/events/:event/results/publisha organizer of the event
results.sandboxGET /api/events/:event/results/sandboxa organizer of the event
results.showGET /api/events/:event/resultsanyone, signed in or not
results.unpublishPOST /api/events/:event/results/unpublisha organizer of the event
reviews.cancelPOST /api/events/:event/review-requests/:request/cancela organizer of the event
reviews.requestPOST /api/events/:event/review-requestsa organizer of the event
reviews.requestsGET /api/events/:event/review-requestsa organizer of the event
rubrics.createPOST /api/events/:event/rubrica organizer of the event
rubrics.publishPOST /api/events/:event/rubric/publisha organizer of the event
rubrics.showGET /api/events/:event/rubricanyone, signed in or not
system.aboutGET /api/aboutanyone, signed in or not
system.capabilitiesGET /api/capabilitiesanyone, signed in or not
system.docsGET /api/docsanyone, signed in or not
system.healthzGET /api/healthzanyone, signed in or not
system.homeGET /apianyone, signed in or not
system.limitsGET /api/system/limitsanyone, signed in or not
system.openapiGET /api/openapi.jsonanyone, signed in or not
system.rate_probePOST /api/system/rate-probeanyone, signed in or not
teams.invite_rotatePOST /api/events/:event/teams/:team/invites/rotatea participant of the event, while submissions are open
teams.joinPOST /api/events/:event/teams/:team/membersa participant of the event, while submissions are open
teams.leavePOST /api/events/:event/teams/:team/leavea participant of the event, while submissions are open
teams.listGET /api/events/:event/teamsa participant of the event
tokens.createPOST /api/me/tokensany signed-in account
tokens.listGET /api/me/tokensany signed-in account
tokens.revokePOST /api/me/tokens/:tokenId/revokeany signed-in account
tracks.createPOST /api/events/:event/tracksa organizer of the event
votes.abuseGET /api/events/:event/voting/abusea organizer of the event
votes.ballotGET /api/events/:event/votinganyone, signed in or not
votes.castPOST /api/events/:event/votesanyone, signed in or not
votes.configure_abusePOST /api/events/:event/voting/abuse/policya organizer of the event
votes.discount_clusterPOST /api/events/:event/voting/discounta organizer of the event
votes.resultsGET /api/events/:event/votesanyone, signed in or not
votes.review_abusePOST /api/events/:event/voting/abuse/reviewa organizer of the event
votes.startPOST /api/events/:event/votes/startanyone, signed in or not
votes.void_voterPOST /api/events/:event/voting/voida organizer of the event

appeals.list

GET /api/events/:event/appeals

List public appeal resolutions, or private appeals you may inspect.

Callable by anyone, signed in or not.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.

appeals.open

POST /api/events/:event/appeals

Open a private appeal for your submitted team project.

Callable by a participant of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
projectbodyProject ID — a 26-character identifier. Required.
privateMessagebodyPrivate appeal message — text, any number of lines, between 8 and 2000 characters. Required. Only organizers and you can read this text.

Records appeal.opened.

Limited to 30 submission edits by one team per window.

appeals.resolve

POST /api/events/:event/appeals/:appeal/resolve

Resolve an appeal and optionally publish a corrected result revision.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
appealpathAppeal ID — a 26-character identifier. Required.
decisionbodyDecision — one of accepted, rejected. Required.
republishbodyPublish corrected results — yes or no. Defaults to false.
expectedRevisionbodyCurrent publication revision — a whole number, at least 1. Required.
publicSummarybodyPublic explanation — text on one line, between 8 and 300 characters. Required.
internalReasonbodyPrivate resolution reason — text on one line, between 8 and 1000 characters. Required.

Records appeal.resolved, result.corrected.

Limited to 120 organizer changes to one event per window.

assignments.draw

POST /api/events/:event/assignments

Assign judges to projects, honouring conflicts and balancing the load.

Uses the event's own reviews-per-project setting. Safe to run twice: the plan is applied as a difference. An assignment that already has a ballot against it is never removed.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
trackbodyTrack — text on one line, at most 40 characters. Optional. Draw within one track only. Leave blank to draw the whole event.
dryRunbodyPreview only — yes or no. Defaults to false. Compute the plan and report shortfalls without writing any assignments.
expectedRevisionbodyPreview revision — text on one line, between 64 and 64 characters. Optional. Prevents applying a plan after event evidence changes.

Records assignment.run, assignment.created, assignment.removed.

Limited to 120 organizer changes to one event per window.

assignments.preview

GET /api/events/:event/assignments/preview

Preview assignment coverage before applying a draw.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
trackqueryTrack — text on one line, at most 40 characters. Optional. Draw within one track only. Leave blank to draw the whole event.

auth.request

POST /api/signin

Send a sign-in link to an email address.

Answers identically for a known and an unknown address, so this cannot be used to find out who has an account here.

Callable by anyone, signed in or not.

Field Where Meaning
emailbodyEmail address — an email address. Required. Where to send the link. It is the address an organizer invited, if you were invited.

Records signin.requested.

Limited to 10 sign-in links for one address per window.

auth.session

POST /api/session

Exchange a sign-in link for a session.

Callable by anyone, signed in or not.

Field Where Meaning
tokenbodySign-in token — text on one line, between 43 and 43 characters. Required. Never echoed back or written to the ledger. The token from the link that was sent to you.

Records link.consumed, account.created, membership.granted, session.created.

Limited to 10 sign-in links for one address per window.

auth.signin

GET /api/signin

Show how to sign in.

Callable by anyone, signed in or not.

Field Where Meaning
sentqueryLink sent — yes or no. Defaults to false. Set by the redirect after a link has been requested. Nothing reads it but the page.

auth.signout

POST /api/signout

Sign out of this session, or of every session.

Callable by any signed-in account.

Field Where Meaning
everywherebodySign out everywhere — yes or no. Defaults to false. Revoke every session for this account, not just this one. Use it if you think a link or a token has been seen by somebody else.

Records session.revoked.

Limited to 600 requests from one session per window.

auth.whoami

GET /api/whoami

Describe the signed-in account and its live sessions.

Callable by any signed-in account.

awards.decide

POST /api/events/:event/awards

Record an organizer award decision against the published revision.

Repeated award keys in one revision explicitly represent shared awards. A corrected publication requires new decisions.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
projectbodySubmitted project — a 26-character identifier. Required.
awardKeybodyAward name/key — text on one line, between 3 and 80 characters. Required.
typebodyAward type — one of placement, special. Required.
placebodyPlace — a whole number between 1 and 100. Optional.
publicSummarybodyPublic explanation — text on one line, between 8 and 500 characters. Required.
internalReasonbodyPrivate decision record — text on one line, between 8 and 1000 characters. Required.

Records award.decided.

Limited to 120 organizer changes to one event per window.

awards.list

GET /api/events/:event/awards

List explicit award decisions for the current results revision.

Callable by anyone, signed in or not.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.

ballots.save

POST /api/events/:event/projects/:project/ballot

Score a project against the published rubric.

The ballot is always filed as the signed-in judge; there is no way to enter one on another judge's behalf over HTTP. Saving again replaces the earlier ballot and records the revision. Scoring an unassigned project assigns it to you.

Callable by a judge of the event, the judge the ballot belongs to, while judging is open.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
projectpathProject — a 26-character identifier. Required. The project's id, as it appears in the URL.
scoresbodyScores — one whole number per rubric criterion, keyed by criterion. Optional. One whole number per criterion of the published rubric, keyed by criterion. From a form, send them as scores.<key> — a JSON client sends an object.
commentbodyComment — text, any number of lines, at most 4000 characters. Optional. What the team should hear. Organizers see this; whether the team does is their call.
draftbodySave as draft — yes or no. Defaults to false. A draft is not counted anywhere. Leave this off to file the ballot.

Records assignment.created, ballot.submitted, ballot.revised.

Limited to 60 ballot writes by one judge per window.

comments.add

POST /api/events/:event/projects/:project/comments

Comment on a submitted project.

Callable by any signed-in account.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
projectpathProject — a 26-character identifier. Required. The project's identifier, as it appears in the URL.
bodybodyYour comment — text, any number of lines, at most 2000 characters. Required.

Records comment.created.

Limited to 30 public vote writes by one voter per window.

comments.hide

POST /api/events/:event/projects/:project/comments/hide

Hide a project comment with an audited reason.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
projectpathProject — a 26-character identifier. Required. The project's identifier, as it appears in the URL.
commentbodyComment identifier — text on one line, at most 20 characters. Required.
reasonbodyReason — text, any number of lines, between 3 and 1000 characters. Required. The team will be shown this. It goes on the record either way.

Records comment.hidden.

Limited to 120 organizer changes to one event per window.

duels.decide

POST /api/events/:event/duel

Record which of two projects is stronger.

A skip is recorded rather than discarded: it does not move the ranking, but a judge skipping most of their duels is something an organizer needs to see. Deciding the same pair again replaces the earlier verdict and records the change.

Callable by a judge of the event, while judging is open.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
leftbodyProject — a 26-character identifier. Required. The project's id, as it appears in the URL.
rightbodyProject — a 26-character identifier. Required. The project's id, as it appears in the URL.
verdictbodyVerdict — one of left, right, skip. Required. Which of the two shown projects is stronger, or skip if you cannot separate them.
reasonbodyOffered because — one of bridge, informative, explore, exposure, manual. Defaults to "manual". The reason the pairing scheduler gave for this pair. Recorded, not trusted.

Records comparison.recorded, comparison.revised.

Limited to 60 ballot writes by one judge per window.

duels.next

GET /api/events/:event/duel

The next pair of projects for you to compare.

Callable by a judge of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.

duplicates.list

GET /api/events/:event/manage/duplicates

Review quarantined project collisions.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.

duplicates.triage

POST /api/events/:event/manage/duplicates/triage

Confirm or clear a quarantined project.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
projectbodyProject — a 26-character identifier. Required. The project's identifier, as it appears in the URL.
decisionbodyDecision — one of confirmed, cleared. Required.
reasonbodyReason — text, any number of lines, between 3 and 1000 characters. Required. The team will be shown this. It goes on the record either way.

Records project.duplicate_confirmed, project.duplicate_cleared.

Limited to 120 organizer changes to one event per window.

events.clock

GET /api/events/:event/clock

Inspect virtual event clock and time offsets.

Reports real system time vs virtual offset time and current phase gates for demo evaluation.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.

events.create

POST /api/events

Create an event and become its organizer.

Limited to the addresses this deployment's operator named as founders. Holding any role in an existing event, including organizer, does not grant it.

Callable by an account this deployment's operator listed as a founder.

Field Where Meaning
slugbodyURL name — text on one line, between 2 and 64 characters. Required. Lower-case letters, digits and hyphens. It appears in every link to this event and cannot be changed.
namebodyEvent name — text on one line, at most 200 characters. Required. What people call it. “Dogfood Hackathon 2026”, not “dogfood-2026”.
prizesbodyPrizes and recognition — text, any number of lines, at most 4000 characters. Optional. One prize per line, including its amount and eligibility.
questionsbodySubmission questions — text, any number of lines, at most 4000 characters. Optional. One question per line. Teams answer these publicly on their project page.
timezonebodyTimezone — text on one line, at most 64 characters. Defaults to "UTC". An IANA zone such as Europe/Lisbon, used for displaying times. Every deadline is still one instant for everybody.
submissionsOpenAtbodySubmissions open — a date and time, as epoch milliseconds or an ISO timestamp. Required. When teams may start submitting.
submissionsCloseAtbodySubmissions close — a date and time, as epoch milliseconds or an ISO timestamp. Required. The deadline. It is enforced to the millisecond.
judgingOpenAtbodyJudging opens — a date and time, as epoch milliseconds or an ISO timestamp. Required. When judges may start scoring. It may be before submissions close.
judgingCloseAtbodyJudging closes — a date and time, as epoch milliseconds or an ISO timestamp. Required. When scoring stops.
reviewsPerProjectbodyReviews per project — a whole number between 1 and 20. Defaults to 3. How many judges should see each project. Three is the usual answer; below three there is nothing to cross-check a lenient judge against.
pairwiseEnabledbodyCollect pairwise comparisons — yes or no. Defaults to false. Ask judges which of two projects is better, as well as scoring each. It sharpens the top of the leaderboard and costs judges time.
votingOpenAtbodyVoting opens — a date and time, as epoch milliseconds or an ISO timestamp. Optional. When community voting begins.
votingCloseAtbodyVoting closes — a date and time, as epoch milliseconds or an ISO timestamp. Optional. When community voting ends.
votingModebodyVoting access — one of off, open, account. Defaults to "off". Choose off, open to a voter token, or signed-in accounts only.
votingCreditsbodyVoting credits — a whole number between 1 and 100000. Defaults to 100. The quadratic voting budget per voter.

Records event.created, membership.granted.

Limited to 20 events created by one founder per window.

events.dashboard

GET /api/events/:event/dashboard

Show judging progress, coverage and judge effects for an event.

Organizer-only. The judge-effect table is here and nowhere else: results.show publishes per-project rankMove instead, which shows that normalization happened without naming a judge. reliability and criteria are the read-only passes over the fit — uncertainty and tiers, and what each line of the rubric is doing. results.show gets the anonymous half of the first and none of the second. calibration is the pre-publish read on the panel itself: one row per judge with a verdict on whether their part of it is ready, and the judge pairs who agreed more than these comparisons predict. It is the only place in the product that prints a verdict about a person, and it reaches no public surface at any role. Because it exists, rubric.warnings is panel-level whenever calibration is not null: a sentence about one judge belongs in that judge's row, with the action beside it, rather than twice on one page.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
labqueryRun advanced evidence diagnostics — yes or no. Defaults to false.
finalistsqueryFinalist places — a whole number between 1 and 100. Defaults to 3.
sensitivityqueryRun reviewer influence analysis — yes or no. Defaults to false.

events.invite

POST /api/events/:event/invitations

Send somebody a link that joins them to this event in a role.

The response contains the invitation link. Organizer-only, and the ledger records who issued it, to which address and in which role.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
emailbodyEmail address — an email address. Required. The address to invite. It does not need an account here yet.
rolebodyRole — one of organizer, judge, participant. Required. What they will be able to do. A judge scores projects; a participant submits one; an organizer can do everything here, including inviting more organizers.

Records invite.issued.

Limited to 200 invitations from one event per window.

events.judges

GET /api/events/:event/judges

List the judges and organizers of this event.

Organizer-only on purpose. Publishing a judge roster would let anybody un-blind the judging by reading a URL.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.

events.list

GET /api/events

List the events this deployment is running.

Callable by anyone, signed in or not.

Field Where Meaning
archivedqueryInclude finished events — yes or no. Defaults to false. Include events that have been archived. They stay reachable by slug either way.

events.mine

GET /api/mine

List the events the caller holds a role in.

Callable by any signed-in account.

events.ping_webhook

POST /api/events/:event/webhooks/ping

Generate a signed webhook test payload without sending it.

Generates a signed test payload locally and records it. Does not contact the supplied URL or verify delivery.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
urlbodyWebhook Receiver URL — an http or https link. Required. The HTTPS receiver endpoint.
secretbodyWebhook Signing Secret — text on one line, between 32 and 128 characters. Required. Never echoed back or written to the ledger. Shared secret for HMAC-SHA256 signature verification (minimum 32 characters).

Records webhook.pinged.

Limited to 120 organizer changes to one event per window.

events.revoke_role

POST /api/events/:event/roles/revoke

Remove an event role while retaining its historical records.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
accountbodyAccount ID — text on one line, at most 64 characters. Required.
rolebodyRole — one of organizer, judge, participant. Required.

Records membership.revoked.

Limited to 120 organizer changes to one event per window.

events.show

GET /api/events/:event

Describe one event, its clock and its tracks.

Callable by anyone, signed in or not.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.

events.update

POST /api/events/:event

Update this event's dates and judging settings.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
namebodyEvent name — text on one line, at most 200 characters. Required. What people call it. “Dogfood Hackathon 2026”, not “dogfood-2026”.
timezonebodyTimezone — text on one line, at most 64 characters. Defaults to "UTC". An IANA zone such as Europe/Lisbon, used for displaying times. Every deadline is still one instant for everybody.
prizesbodyPrizes and recognition — text, any number of lines, at most 4000 characters. Optional. One prize per line, including its amount and eligibility.
questionsbodySubmission questions — text, any number of lines, at most 4000 characters. Optional. One question per line. Teams answer these publicly on their project page.
submissionsOpenAtbodySubmissions open — a date and time, as epoch milliseconds or an ISO timestamp. Required. When teams may start submitting.
submissionsCloseAtbodySubmissions close — a date and time, as epoch milliseconds or an ISO timestamp. Required. The deadline. It is enforced to the millisecond.
judgingOpenAtbodyJudging opens — a date and time, as epoch milliseconds or an ISO timestamp. Required. When judges may start scoring. It may be before submissions close.
judgingCloseAtbodyJudging closes — a date and time, as epoch milliseconds or an ISO timestamp. Required. When scoring stops.
reviewsPerProjectbodyReviews per project — a whole number between 1 and 20. Defaults to 3. How many judges should see each project. Three is the usual answer; below three there is nothing to cross-check a lenient judge against.
pairwiseEnabledbodyCollect pairwise comparisons — yes or no. Defaults to false. Ask judges which of two projects is better, as well as scoring each. It sharpens the top of the leaderboard and costs judges time.
votingOpenAtbodyVoting opens — a date and time, as epoch milliseconds or an ISO timestamp. Optional. When community voting begins.
votingCloseAtbodyVoting closes — a date and time, as epoch milliseconds or an ISO timestamp. Optional. When community voting ends.
votingModebodyVoting access — one of off, open, account. Defaults to "off". Choose off, open to a voter token, or signed-in accounts only.
votingCreditsbodyVoting credits — a whole number between 1 and 100000. Defaults to 100. The quadratic voting budget per voter.

Records event.updated.

Limited to 120 organizer changes to one event per window.

events.warp_clock

POST /api/events/:event/clock/warp

Fast-forward or reset the virtual clock for demo and evaluation.

Fast-forwards virtual time in-memory. Appends clock.warped audit ledger entry.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
targetPhasebodyTarget Competition Phase — one of realtime, submissions, judging, results. Optional. Jump virtual clock directly into competition milestone.
targetAtbodyTarget Absolute Instant — a date and time, as epoch milliseconds or an ISO timestamp. Optional. Set virtual clock to an exact timestamp.
offsetMsbodyRelative Offset Milliseconds — a whole number. Optional. Apply an explicit millisecond offset to real time.

Records clock.warped.

Limited to 120 organizer changes to one event per window.

events.webhooks

GET /api/events/:event/webhooks

Inspect webhook dispatch status, receiver configuration and signing specifications.

Organizer-only. Provides HMAC-SHA256 signature specification and supported event action types.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.

exports.archive_manifest

GET /api/events/:event/archive

Export the full lossless archive manifest and schema metadata.

Organizer-only. Exposes archive structure and verified row counts across all strict tables.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.

exports.audit_csv

GET /api/events/:event/export/audit.csv

Download audit as CSV.

Organizer-only event data. Text cells are escaped against spreadsheet formulas. Use the JSONL archive for a lossless backup.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.

exports.download

GET /api/events/:event/csv/:stage

Download event records as CSV.

Includes private event data. Requires the event organizer role for every stage, including results and projects. Use the JSONL archive for lossless backups; spreadsheet exports neutralize formula-like text.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
stagepathExport stage — one of registrations, teams, projects, assignments, ballots, results, votes, audit. Required.

exports.projects_csv

GET /api/events/:event/export/projects.csv

Download projects as CSV.

Organizer-only event data. Text cells are escaped against spreadsheet formulas. Use the JSONL archive for a lossless backup.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.

exports.registrations_csv

GET /api/events/:event/export/registrations.csv

Download registrations as CSV.

Organizer-only event data. Text cells are escaped against spreadsheet formulas. Use the JSONL archive for a lossless backup.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.

exports.results_csv

GET /api/events/:event/export/results.csv

Download results as CSV.

Organizer-only event data. Text cells are escaped against spreadsheet formulas. Use the JSONL archive for a lossless backup.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.

exports.scores_csv

GET /api/events/:event/export/scores.csv

Download scores as CSV.

Organizer-only event data. Text cells are escaped against spreadsheet formulas. Use the JSONL archive for a lossless backup.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.

exports.teams_csv

GET /api/events/:event/export/teams.csv

Download teams as CSV.

Organizer-only event data. Text cells are escaped against spreadsheet formulas. Use the JSONL archive for a lossless backup.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.

judges.configure

POST /api/events/:event/judges/configure

Set one judge's eligible tracks and review capacity.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
judgebodyJudge account ID — text on one line, at most 64 characters. Required.
tracksbodyEligible track keys — text on one line, at most 2000 characters. Optional. Comma separated. Leave blank for every track.
capacitybodyMaximum reviews — a whole number between 0 and 1000. Optional. Leave blank for no explicit limit. Zero pauses new assignments.

Records judge.configured.

Limited to 120 organizer changes to one event per window.

judges.recusal

POST /api/events/:event/judges/recusal

Record or clear a project recusal for one judge.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
judgebodyJudge account ID — text on one line, at most 64 characters. Required.
projectbodyProject ID — text on one line, at most 64 characters. Required.
decisionbodyDecision — one of recuse, clear. Required.
reasonbodyReason — text on one line, between 3 and 500 characters. Required.

Records judge.recused, judge.recusal_cleared, assignment.removed, assignment.run, assignment.created.

Limited to 120 organizer changes to one event per window.

judges.roster

GET /api/events/:event/judges/roster

List judge track, capacity, and recusal controls.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.

judges.self_recusal

POST /api/events/:event/judging/:project/recuse

Leave an assigned project review and request an eligible replacement.

Callable by a judge of the event, while judging is open.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
projectpathProject — a 26-character identifier. Required. The project's id, as it appears in the URL.
reasonbodyReason for recusal — text on one line, between 3 and 500 characters. Required.

Records judge.recused, assignment.removed, assignment.run, assignment.created.

Limited to 60 ballot writes by one judge per window.

judging.queue

GET /api/events/:event/judging

The projects assigned to you, and how far you got with each.

Callable by a judge of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
judgequeryJudge id — text on one line, at most 64 characters. Optional. The judge whose queue or scores to inspect. Non-organizers may only inspect their own.
focusqueryReview to keep open — text on one line, at most 64 characters. Optional.

projects.create

POST /api/events/:event/projects

Enter a project into an event.

Saves a draft. Nothing is entered until projects.submit, and the draft is visible only to the team and the organizers until then.

Callable by a participant of the event, while submissions are open.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
teamNamebodyTeam name — text on one line, at most 120 characters. Optional. Only needed the first time. Leave it empty to enter under your own name.
taglinebodyOne-line pitch — text on one line, at most 200 characters. Optional.
descriptionbodyThe full story — text, any number of lines, at most 20000 characters. Optional. Explain the problem, your approach, what works, and what you learned.
thumbnailUrlbodyCover image URL — an http or https link. Optional. Optional HTTPS image. The portal also works without external images.
videoUrlbodyDemo video URL — an http or https link. Optional.
imageUrlsbodyScreenshot URLs — text, any number of lines, at most 16000 characters. Optional. Up to eight HTTPS image links, one per line.
techTagsbodyTechnologies — text on one line, at most 1000 characters. Optional. Comma-separated tags, for example TypeScript, SQLite, WebCrypto.
answersbodyAnswers to event questions — text, any number of lines, at most 12000 characters. Optional. Answer the organizer’s questions in order. These answers appear on your public project page.
titlebodyProject title — text on one line, at most 200 characters. Required. What the judges will see at the top of the page.
summarybodyWhat it does — text, any number of lines, at most 4000 characters. Required. What you built and what it is for. This is the first thing a judge reads.
repoUrlbodySource code — an http or https link. Optional. An https link to the repository. Judges will open it.
demoUrlbodyDemo — an http or https link. Optional. An https link to something running, or to a recording. Optional.
trackKeybodyTrack — text on one line, at most 40 characters. Optional. Which track to enter. Leave empty if the event has none.

Records team.created, team.joined, project.created.

Limited to 30 submission edits by one team per window.

projects.disqualify

POST /api/events/:event/projects/:project/disqualify

Disqualify a project, with a stated reason.

The reason is written to the ledger and shown to the team. There is no way to reverse it.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
projectpathProject — a 26-character identifier. Required. The project's identifier, as it appears in the URL.
reasonbodyReason — text, any number of lines, between 3 and 1000 characters. Required. The team will be shown this. It goes on the record either way.

Records project.disqualified.

Limited to 120 organizer changes to one event per window.

projects.list

GET /api/events/:event/projects

List the projects entered in an event.

Callable by anyone, signed in or not.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
trackKeyqueryTrack — text on one line, at most 40 characters. Optional. Show only this track. Leave empty for all of them.
qquerySearch projects — text on one line, at most 200 characters. Optional.

projects.pull

POST /api/events/:event/projects/:project/pull

Withdraw a project on a team's behalf.

For a team that asked to be pulled. It is not a penalty and it is not recorded as one — use projects.disqualify when the finding is against the team.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
projectpathProject — a 26-character identifier. Required. The project's identifier, as it appears in the URL.
reasonbodyReason — text, any number of lines, between 3 and 1000 characters. Required. The team will be shown this. It goes on the record either way.

Records project.withdrawn.

Limited to 120 organizer changes to one event per window.

projects.show

GET /api/events/:event/projects/:project

Show one project.

Callable by anyone, signed in or not.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
projectpathProject — a 26-character identifier. Required. The project's identifier, as it appears in the URL.

projects.submit

POST /api/events/:event/projects/:project/submit

Submit a project for judging.

Callable by a participant of the event, on the project's own team, while submissions are open.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
projectpathProject — a 26-character identifier. Required. The project's identifier, as it appears in the URL.

Records project.submitted.

Limited to 30 submission edits by one team per window.

projects.update

POST /api/events/:event/projects/:project

Replace a project's details.

Every field is sent, every time. An empty link or track clears it, because a form cannot tell the difference between a box somebody cleared and a field they left out.

Callable by a participant of the event, on the project's own team, while submissions are open.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
projectpathProject — a 26-character identifier. Required. The project's identifier, as it appears in the URL.
taglinebodyOne-line pitch — text on one line, at most 200 characters. Optional.
descriptionbodyThe full story — text, any number of lines, at most 20000 characters. Optional. Explain the problem, your approach, what works, and what you learned.
thumbnailUrlbodyCover image URL — an http or https link. Optional. Optional HTTPS image. The portal also works without external images.
videoUrlbodyDemo video URL — an http or https link. Optional.
imageUrlsbodyScreenshot URLs — text, any number of lines, at most 16000 characters. Optional. Up to eight HTTPS image links, one per line.
techTagsbodyTechnologies — text on one line, at most 1000 characters. Optional. Comma-separated tags, for example TypeScript, SQLite, WebCrypto.
answersbodyAnswers to event questions — text, any number of lines, at most 12000 characters. Optional. Answer the organizer’s questions in order. These answers appear on your public project page.
titlebodyProject title — text on one line, at most 200 characters. Required. What the judges will see at the top of the page.
summarybodyWhat it does — text, any number of lines, at most 4000 characters. Required. What you built and what it is for. This is the first thing a judge reads.
repoUrlbodySource code — an http or https link. Optional. An https link to the repository. Judges will open it.
demoUrlbodyDemo — an http or https link. Optional. An https link to something running, or to a recording. Optional.
trackKeybodyTrack — text on one line, at most 40 characters. Optional. Which track to enter. Leave empty if the event has none.

Records project.updated.

Limited to 30 submission edits by one team per window.

projects.withdraw

POST /api/events/:event/projects/:project/withdraw

Withdraw a project from an event.

Reversible while submissions are open: submitting again clears the withdrawal.

Callable by a participant of the event, on the project's own team, while submissions are open.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
projectpathProject — a 26-character identifier. Required. The project's identifier, as it appears in the URL.
reasonbodyReason — text, any number of lines, between 3 and 1000 characters. Optional. Optional, and only the organizers will read it.

Records project.withdrawn.

Limited to 30 submission edits by one team per window.

results.certificate_status

GET /api/events/:event/certificates/status

Download signed certificate revocations and supersessions without recipient data.

Callable by anyone, signed in or not.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.

results.certificate_studio

GET /api/events/:event/certificates/studio

Design certificates and view the issued recipient roster.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.

results.certificates

GET /api/events/:event/certificates

View issued Ed25519 verifiable certificates for this event.

Organizer-only, read-only. Returns the stored signed snapshot, or an empty report before issuance. Never creates keys or signatures.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.

results.confidence

GET /api/events/:event/results/confidence

Say which parts of the duel ranking the comparisons establish, and which are a tie.

Resamples the panel to ask whether another panel would have produced this order. pairs is the answer to "is first place real": a pair with ordered: false is two projects the comparisons cannot separate, however far apart they sit in the table. A tier holds the projects that are not separated from the one at the top of it, which is the unit to award on; two projects can share a tier and still be separated from each other, so pairs is where a boundary is established. Organizers can read this before publishing; everybody else gets results.notPublic until then. Costs about a second and is limited to 20 a minute per event.

Callable by anyone, signed in or not.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
replicatesqueryResamples — a whole number between 50 and 2000. Defaults to 400. How many times to refit the ranking on resampled data. More is finer and slower; the default resolves a quarter of a percentage point.
confidencequeryConfidence — one of 0.9, 0.95, 0.99. Defaults to "0.95". How much of the resampled spread each interval should cover. A higher level separates fewer pairs, because it demands more evidence to call one project ahead of another.

Limited to 20 resampled analyses of one event per window.

results.configure_certificate_template

POST /api/events/:event/certificates/template

Save the event certificate design before issuance.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
headingbodyHeading — text on one line, between 3 and 90 characters. Required.
bodybodyMessage — text, any number of lines, between 3 and 350 characters. Required.
footerbodyFooter — text on one line, at most 120 characters. Required.
signatorybodySignatory — text on one line, between 2 and 100 characters. Required.

Records certificate.template.updated.

Limited to 120 organizer changes to one event per window.

results.correct_cert

POST /api/events/:event/certificates/corrections

Sign a revocation or supersession for an issued certificate.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
serialbodyCertificate serial — text on one line, between 8 and 180 characters. Required.
actionbodyCorrection — one of revoke, supersede. Required.
reasonbodyReason — text on one line, between 8 and 1000 characters. Required.
recipientNamebodyCorrected recipient name — text on one line, at most 120 characters. Optional.
recipientEmailbodyCorrected recipient email — an email address. Optional.
categorybodyCorrected category — one of participation, judge, placement. Optional.
detailbodyCorrected detail — text on one line, at most 500 characters. Optional.

Records certificate.revoke, certificate.supersede.

Limited to 120 organizer changes to one event per window.

results.evidence_packet

GET /api/events/:event/results/evidence

Download the public method and evidence summary bound to one result revision.

Callable by anyone, signed in or not.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.

results.explain

GET /api/events/:event/results/explain

Explain your team's frozen published ranking with anonymous review contributions.

Callable by a participant of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.

results.history

GET /api/events/:event/results/history

List result publication revisions and correction reasons.

Callable by anyone, signed in or not.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.

results.issue_certs

POST /api/events/:event/certificates

Issue and sign Ed25519 certificates for participants, judges, and winners.

Issues cryptographic Ed25519 certificates. Refuses before results are published.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.

Records certificate.issued.

Limited to 120 organizer changes to one event per window.

results.judge_evidence

POST /api/events/:event/results/judge-evidence

Exclude or restore one judge's evidence with an audited reason.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
judgebodyJudge account ID — text on one line, at most 64 characters. Required.
decisionbodyDecision — one of exclude, include. Required.
reasonbodyReason — text on one line, between 3 and 500 characters. Required.

Records judge.evidence_excluded, judge.evidence_restored, result.corrected.

Limited to 120 organizer changes to one event per window.

results.preflight

GET /api/events/:event/results/preflight

Check coverage, model warnings, and publication status before publishing.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.

results.public_certificate

GET /api/events/:event/certificates/:serial

View an issued certificate and its current correction status.

Callable by anyone, signed in or not.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
serialpathCertificate serial — text on one line, between 8 and 180 characters. Required.

results.publish

POST /api/events/:event/results/publish

Publish the ranking for everybody to read.

Reversible: results.unpublish takes the page down again. The warnings on this response are the ones the public page carries, so publishing never looks cleaner than the ranking is.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
reasonbodyInternal correction reason — text on one line, at most 500 characters. Optional. Private organizer note. Give a reason to publish a new revision after correcting evidence.
publicSummarybodyPublic revision summary — text on one line, between 4 and 160 characters. Optional. Visible to everyone in result history. Keep judge and participant details private.

Records event.results_published, result.published, result.corrected.

Limited to 120 organizer changes to one event per window.

results.sandbox

GET /api/events/:event/results/sandbox

Compare normalization methods on current evidence without changing published results.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.

Limited to 20 resampled analyses of one event per window.

results.show

GET /api/events/:event/results

Show the ranking, once an organizer has published it.

Organizers can read this before publishing, as a preview. Everybody else gets results.notPublic until results.publish has been called. Judge leniency and scale are not on this response at any role: see events.dashboard. panel and the per-project tier say how much of the order the evidence supports: a tier holds the projects that are not separated from the one at the top of it.

Callable by anyone, signed in or not.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
revisionqueryPublication revision — a whole number, at least 1. Optional. Leave blank for the latest frozen publication.

results.unpublish

POST /api/events/:event/results/unpublish

Take the published ranking back down.

The ledger keeps the publication and the withdrawal, so a ranking that was briefly public cannot be made never to have happened.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.

Records event.results_withdrawn.

Limited to 120 organizer changes to one event per window.

reviews.cancel

POST /api/events/:event/review-requests/:request/cancel

Cancel an unfinished targeted review request.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
requestpathReview request ID — a 26-character identifier. Required.

Records review.cancelled, assignment.removed.

Limited to 120 organizer changes to one event per window.

reviews.request

POST /api/events/:event/review-requests

Assign one additional eligible judge to a submitted project.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
projectbodyProject — a 26-character identifier. Required. The project's id, as it appears in the URL.
reasonCodebodyReason code — one of coverage, fragility, appeal, other. Required.
internalReasonbodyPrivate reason — text on one line, between 8 and 500 characters. Required.
prioritybodyPriority — a whole number between 1 and 3. Defaults to 2.
dueAtbodyDue time (Unix milliseconds) — a whole number, at least 1. Optional.

Records review.requested, assignment.created.

Limited to 120 organizer changes to one event per window.

reviews.requests

GET /api/events/:event/review-requests

List targeted additional review requests and completion state.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.

rubrics.create

POST /api/events/:event/rubric

Write a new version of an event's rubric.

Saves a draft version. Judges score against the published version, so this changes nothing until rubrics.publish.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
criteriabodyCriteria — text, any number of lines, at most 8000 characters. Required. One per line: keyLabelweightminmax. The last three are optional and default to 115. Example: craftTechnical craft215

Records rubric.created.

Limited to 120 organizer changes to one event per window.

rubrics.publish

POST /api/events/:event/rubric/publish

Publish a rubric version for judges to score against.

There is no way to unpublish. Write a new version and publish that instead.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
versionbodyVersion — a whole number between 1 and 10000. Required. Which version to publish. Rubrics are never edited, only superseded.

Records rubric.published.

Limited to 120 organizer changes to one event per window.

rubrics.show

GET /api/events/:event/rubric

Show the rubric judges score against.

Callable by anyone, signed in or not.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
versionqueryVersion — a whole number between 1 and 10000. Optional. Defaults to the published version.

system.about

GET /api/about

Describe what this deployment is and who wrote it.

Every claim below names the route or the file that settles it. Nothing on this page is measured at request time, so two deployments of the same version answer identically.

Callable by anyone, signed in or not.

system.capabilities

GET /api/capabilities

Publish the access matrix for every operation.

stranger is a signed-in account with no role in the event, which is also how an organizer of a different event presents itself. A notFound cell is the isolation rule: not yours means not found, never forbidden.

Callable by anyone, signed in or not.

system.docs

GET /api/docs

Describe every operation this deployment performs.

Callable by anyone, signed in or not.

system.healthz

GET /api/healthz

Report whether this deployment is serving correctly.

Callable by anyone, signed in or not.

system.home

GET /api

List the events this deployment is running.

Callable by anyone, signed in or not.

system.limits

GET /api/system/limits

List fixed-window rate limiting policies and status 429 contract.

Public policy specification. Explains fixed-window rate meters and Retry-After header semantics.

Callable by anyone, signed in or not.

system.openapi

GET /api/openapi.json

Publish the OpenAPI description of this deployment.

The document is derived from the same command declarations the server dispatches, so a generated client is generated against what is actually running.

Callable by anyone, signed in or not.

system.rate_probe

POST /api/system/rate-probe

Safe rate limit probe endpoint to exercise 429 flood refusal.

Enforces 2 requests per minute. Exceeding triggers HTTP 429 Too Many Requests with Retry-After header.

Callable by anyone, signed in or not.

Records system.probed.

Limited to 2 rate limit test probes per window.

teams.invite_rotate

POST /api/events/:event/teams/:team/invites/rotate

Rotate the private invitation link for this team.

Callable by a participant of the event, while submissions are open.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
teampathTeam — a 26-character identifier. Required. The team's identifier, from the team list or from an invitation.

Records team.invite_rotated.

Limited to 30 submission edits by one team per window.

teams.join

POST /api/events/:event/teams/:team/members

Join a team in an event.

Callable by a participant of the event, while submissions are open.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
teampathTeam — a 26-character identifier. Required. The team's identifier, from the team list or from an invitation.

Records team.joined.

Limited to 30 submission edits by one team per window.

teams.leave

POST /api/events/:event/teams/:team/leave

Leave a team in an event.

Callable by a participant of the event, while submissions are open.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
teampathTeam — a 26-character identifier. Required. The team's identifier, from the team list or from an invitation.

Records team.left.

Limited to 30 submission edits by one team per window.

teams.list

GET /api/events/:event/teams

List the teams in an event.

Callable by a participant of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.

tokens.create

POST /api/me/tokens

Create an expiring API token for one event and scope.

Callable by any signed-in account.

Field Where Meaning
eventbodyEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
labelbodyToken label — text on one line, at most 80 characters. Required.
scopebodyScope — one of read:projects, read:results, write:projects, write:judging. Defaults to "read:projects".
daysbodyExpires in days — a whole number between 1 and 90. Defaults to 30.

Records token.created.

Limited to 120 organizer changes to one event per window.

tokens.list

GET /api/me/tokens

Manage your scoped API tokens.

Callable by any signed-in account.

tokens.revoke

POST /api/me/tokens/:tokenId/revoke

Immediately revoke one of your API tokens.

Callable by any signed-in account.

Field Where Meaning
tokenIdpathToken ID — a 26-character identifier. Required.

Records token.revoked.

Limited to 120 organizer changes to one event per window.

tracks.create

POST /api/events/:event/tracks

Add a track to an event.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
keybodyTrack key — text on one line, at most 40 characters. Required. Lower case, digits, hyphens and underscores. It appears in URLs and in the results table.
labelbodyTrack name — text on one line, at most 120 characters. Required. What participants will see. “Best use of local models”, not “local-models”.
orderingbodyPosition — a whole number between 0 and 999. Defaults to 0. Lower numbers come first. Ties are broken by key, so leaving this alone lists them alphabetically.

Records track.created.

Limited to 120 organizer changes to one event per window.

votes.abuse

GET /api/events/:event/voting/abuse

Detect and analyze suspicious voting rings and Sybil attacks.

Organizer-only. Surfaces collusive voting rings, burst timings, and recommendation factors.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.

votes.ballot

GET /api/events/:event/voting

View your voting budget and shuffled project ballot.

Uses the event-scoped HttpOnly cookie set by votes.start. API clients retain the Set-Cookie header. Projects are shuffled for that credential; only your own allocations are shown. No aggregate standings appear here.

Callable by anyone, signed in or not.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.

votes.cast

POST /api/events/:event/votes

Spend voting credits on a submitted project.

Callable by anyone, signed in or not.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
tokenbodyVoter token — text on one line, between 43 and 43 characters. Optional. Never echoed back or written to the ledger. The token returned when voting started.
projectbodyProject — a 26-character identifier. Required. The project's identifier, as it appears in the URL.
influencebodyInfluence — a whole number between 1 and 10. Defaults to 1. A vote of n influence costs n squared credits.

Records vote.cast.

Limited to 30 public vote writes by one voter per window.

votes.configure_abuse

POST /api/events/:event/voting/abuse/policy

Set this event's voting anomaly thresholds.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
patternPercentbodyPattern similarity percent — a whole number between 50 and 100. Required.
sharedOriginPercentbodyShared-origin similarity percent — a whole number between 50 and 100. Required.
highRiskbodyHigh-risk score threshold — a whole number between 0 and 100. Required.

Records abuse.policy_updated.

Limited to 120 organizer changes to one event per window.

votes.discount_cluster

POST /api/events/:event/voting/discount

Apply an audited discount after confirming a voting signal through human review.

Requires a confirmed review. Raw ballots are preserved; an audited factor is applied in aggregation.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
clusterTokensbodyVoter Token Hashes — text on one line, at most 4096 characters. Required. Comma-separated list of voter hashes to discount.
discountPercentbodyDiscount Percentage — a whole number between 0 and 100. Defaults to 100. Percentage to reduce ballot weights by (default 100% = nullify).
reasonbodyAudit Reason — text on one line, between 5 and 256 characters. Required. Reason for applying discount (logged permanently to audit trail).

Records vote.cluster_discounted.

Limited to 120 organizer changes to one event per window.

votes.results

GET /api/events/:event/votes

List the current public voting totals.

Callable by anyone, signed in or not.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.

votes.review_abuse

POST /api/events/:event/voting/abuse/review

Record an investigator's assessment of one voting signal.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
clusterTokensbodyVoter token hashes — text on one line, between 64 and 4096 characters. Required.
statebodyReview state — one of investigating, benign, confirmed. Required.
reasonbodyEvidence and reason — text on one line, between 8 and 1000 characters. Required.

Records abuse.reviewed.

Limited to 120 organizer changes to one event per window.

votes.start

POST /api/events/:event/votes/start

Start a voting session for this event.

Callable by anyone, signed in or not.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.

Records voter.created.

Limited to 30 public vote writes by one voter per window.

votes.void_voter

POST /api/events/:event/voting/void

Void all votes cast by a suspicious voter identity.

Nullifies voter weight to zero and logs permanent audit record.

Callable by a organizer of the event.

Field Where Meaning
eventpathEvent — text on one line, between 2 and 64 characters. Required. The event's slug or id, as it appears in the URL.
voterTokenbodyVoter Token Hash — text on one line, at most 4096 characters. Required. The token hash of the voter to void.
reasonbodyAudit Reason — text on one line, between 3 and 256 characters. Required. Reason for voiding voter ballots.

Records vote.voter_voided.

Limited to 120 organizer changes to one event per window.