Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: make.fun Submissions API
description: 'Competitions to build software with AI agents: the board, leaderboards, kits, entering, entry archives (snapshot, blame, transcripts, action logs), search, discussion, prize claims and the admin routes. Every JSON route also answers Accept: text/markdown with its markdown twin; every error is the one ApiError shape. MCP at https://make.fun/mcp; an index for agents at https://make.fun/llms.txt.'
version: 0.1.0
servers:
- url: https://make.fun
tags:
- name: Submissions
description: Entering a competition and its entries
paths:
/api/competitions/{slug}/submissions:
post:
operationId: postApiCompetitionsBySlugSubmissions
tags:
- Submissions
summary: Enter a competition
description: 'multipart/form-data: repo_url, commit_sha, then one transcript bundle (bundle, .tar.gz) or loose transcripts (transcripts, repeated: .jsonl / .json, .md, .sse, SQLite stores or compressed .jsonl logs); entry_message and entry_signature, the signed entry (make.fun entry v1), required where the prizes are escrowed. With no GitHub repository: repo_url bundle: and source_bundle, one v2 git bundle of the repository history (at most 512 MiB), always signed, the Source line of its entry message naming its sha256. A session cookie or x-api-key; an admin enters only inside its admin window, its own entry (a file:// source, a source bundle or a GitHub repo outside the house organizations) competing like an entrant (the session of an admin with a linked wallet is asked it once, 403 step_up_required; its API key is refused). 202 carries the claim code once; a refusal by a check answers an EntryProblem (application/problem+json).'
requestBody:
required: true
content:
application/x-www-form-urlencoded:
schema:
type: object
properties:
repo_url:
type: string
minLength: 1
maxLength: 2048
commit_sha:
type: string
pattern: ^[0-9a-fA-F]{40}$
title:
description: 'The entry''s public name, shown on the board, its entry page and the results from intake, even while the entrant and the repository are withheld: keep your handle, the repository name and any secret out of it. Omitted or blank, the site names the entry with two generated words (the 202''s title_generated says so).'
type: string
maxLength: 200
entry_signature:
type: string
maxLength: 128
bundle:
anyOf:
- type: string
format: binary
- type: array
items:
type: string
format: binary
source_bundle:
anyOf:
- type: string
format: binary
- type: array
items:
type: string
format: binary
transcripts:
anyOf:
- type: string
format: binary
- type: array
items:
type: string
format: binary
transcripts[]:
anyOf:
- type: string
format: binary
- type: array
items:
type: string
format: binary
entry_message:
anyOf:
- type: string
maxLength: 2064
- type: string
format: binary
required:
- repo_url
- commit_sha
multipart/form-data:
schema:
type: object
properties:
repo_url:
type: string
minLength: 1
maxLength: 2048
commit_sha:
type: string
pattern: ^[0-9a-fA-F]{40}$
title:
description: 'The entry''s public name, shown on the board, its entry page and the results from intake, even while the entrant and the repository are withheld: keep your handle, the repository name and any secret out of it. Omitted or blank, the site names the entry with two generated words (the 202''s title_generated says so).'
type: string
maxLength: 200
entry_signature:
type: string
maxLength: 128
bundle:
anyOf:
- type: string
format: binary
- type: array
items:
type: string
format: binary
source_bundle:
anyOf:
- type: string
format: binary
- type: array
items:
type: string
format: binary
transcripts:
anyOf:
- type: string
format: binary
- type: array
items:
type: string
format: binary
transcripts[]:
anyOf:
- type: string
format: binary
- type: array
items:
type: string
format: binary
entry_message:
anyOf:
- type: string
maxLength: 2064
- type: string
format: binary
required:
- repo_url
- commit_sha
responses:
'202':
description: 'Taken in: SubmissionCreated'
'400':
description: Error (ApiError)
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
enum:
- false
error:
type: array
items:
type: object
properties:
message:
type: string
path:
type: array
items:
type:
- string
- integer
required:
- message
data: {}
required:
- success
- error
'401':
description: Error (ApiError)
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
enum:
- false
error:
type: array
items:
type: object
properties:
message:
type: string
path:
type: array
items:
type:
- string
- integer
required:
- message
data: {}
required:
- success
- error
'403':
description: Error (ApiError)
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
enum:
- false
error:
type: array
items:
type: object
properties:
message:
type: string
path:
type: array
items:
type:
- string
- integer
required:
- message
data: {}
required:
- success
- error
'404':
description: Error (ApiError)
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
enum:
- false
error:
type: array
items:
type: object
properties:
message:
type: string
path:
type: array
items:
type:
- string
- integer
required:
- message
data: {}
required:
- success
- error
'409':
description: Error (ApiError)
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
enum:
- false
error:
type: array
items:
type: object
properties:
message:
type: string
path:
type: array
items:
type:
- string
- integer
required:
- message
data: {}
required:
- success
- error
'413':
description: Error (ApiError)
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
enum:
- false
error:
type: array
items:
type: object
properties:
message:
type: string
path:
type: array
items:
type:
- string
- integer
required:
- message
data: {}
required:
- success
- error
'422':
description: Error (ApiError)
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
enum:
- false
error:
type: array
items:
type: object
properties:
message:
type: string
path:
type: array
items:
type:
- string
- integer
required:
- message
data: {}
required:
- success
- error
'429':
description: Error (ApiError)
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
enum:
- false
error:
type: array
items:
type: object
properties:
message:
type: string
path:
type: array
items:
type:
- string
- integer
required:
- message
data: {}
required:
- success
- error
'503':
description: Error (ApiError)
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
enum:
- false
error:
type: array
items:
type: object
properties:
message:
type: string
path:
type: array
items:
type:
- string
- integer
required:
- message
data: {}
required:
- success
- error
parameters:
- schema:
type: string
in: path
name: slug
required: true
security:
- apiKey: []
- session: []
x-makefun-budget: request
get:
operationId: getApiCompetitionsBySlugSubmissions
tags:
- Submissions
summary: A competition's entries
description: 'Newest first. Public fields only: the receipt without its claim code; a failure reason for its submitter and admins; each entry''s repository and commit, its clone fields (clone_url, our git copy; served_by, mirror or origin; origin_url, its GitHub repository), and its receipt''s repo, commit, snapshot_sha256 and bundle_sha256, withheld (empty or null, source_withheld true) from all but its owner and admins at every time, but the competition''s published solution''s (once it settles, its rank-1 entry of the final standings), which shows to everyone from the deadline: for a competition with a reveal from when its results are published, and for a rehosted bounty from when its upstream owner has decided and the outcome is published, whatever the deadline. rank is the entry''s place on the board phase''s leaderboard (the default view) while that phase''s scores are visible to the caller (exactly as GET /api/competitions/:slug/leaderboard''s phase.scores_visible says), and null otherwise (ungraded, failed, unranked or superseded by the submission rule, and for all but admins while the competition holds its placements: its leaderboard.placements after_finalize, the default, until its ranking phase is finalized, and a rehosted bounty''s until its outcome is published, when score, rank and prize_rank are all null and every entry is still listed, unless the hold is all that hides the board phase''s scores (never on a rehost), when the board lifts its hold for everyone, tied scores or not); it counts house entries and the reference baselines. prize_rank is the entry''s prize place on that leaderboard (its prize_rank, the place the public page shows), null when it holds none: a house entry, a baseline, one below the baseline, or while rank is null. build_cost_micro_usd is the build cost of the entry''s graded score, as the leaderboard''s entry carries it (the build meter''s figure for a metered entry, else the transcripts'' priced total), shown to every caller, signed in or not, whether or not the placements are held (no tokens or models with it): null while the entry is ungraded, or its cost unpriced, never 0. build_wall_ms is how long the agent worked on the entry, the union of its transcript sessions'' first_at..last_at spans in ms, shown to every caller for a public entry: null without a timed session, or for an internal entry whose transcript list the caller may not read (GET /api/submissions/:id/transcripts). image is the entrant''s picture: their uploaded avatar, else their GitHub image, else null (the client draws the ghost from the handle). Answers 304 to If-None-Match when nothing changed.'
responses:
'200':
description: Page<SubmissionListItem>
'304':
description: Not modified
'400':
description: Error (ApiError)
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
enum:
- false
error:
type: array
items:
type: object
properties:
message:
type: string
path:
type: array
items:
type:
- string
- integer
required:
- message
data: {}
required:
- success
- error
'404':
description: Error (ApiError)
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
enum:
- false
error:
type: array
items:
type: object
properties:
message:
type: string
path:
type: array
items:
type:
- string
- integer
required:
- message
data: {}
required:
- success
- error
parameters:
- in: path
name: slug
schema:
type: string
minLength: 1
maxLength: 64
required: true
- in: query
name: limit
schema:
type: string
- in: query
name: cursor
schema:
type: string
minLength: 1
maxLength: 1024
- in: query
name: status
schema:
type: string
enum:
- none
- submitting
- submitted
- preparing
- running
- scoring
- awaiting_validation
- finished
- failed
- cancelled
- nondeterministic
- timeout
security:
- {}
- apiKey: []
- session: []
x-makefun-budget: request
/api/submissions/{id}/breakdown:
get:
operationId: getApiSubmissionsByIdBreakdown
tags:
- Submissions
summary: One entry's run, row by row
description: 'One entry''s grade run on a phase (phase: dev or final; default a phase whose breakdown the caller sees, the latest first), as far as the caller may see it (view). A market replay (kind pnl): every item''s realized PnL, fees, transaction fees and fills with their sums line and every identity re-added (sums: each fill''s cash flow is its trade minus its fees and transaction fee plus its other movements, the cash chain, the items to the net, start plus net to the end), the rejections per reason, the round trips, the equity curve downsampled to at most 1000 points with every dip and spike kept (full=1: every point, once the breakdown is public, a 403 before but to admins) and the fills with each part of their cash flow, paged (cursor, limit: the first page carries the whole breakdown; a later page, asked with the previous page''s pnl.fills.next_cursor, only pnl.unit and that page of fills beside the run''s identity). A program/v1 or agent/v1 run (kind checks): its parts, a scorer''s checks earned against their maximum or its scored columns, per trial on agent/v1. A scrape/v1 run (kind checks, from its score): its timed trials, one per round (main, then playoff), each with its wall time in ms, whether the trimmed mean kept it (1) or dropped it (0) and its verdict (one row per verdict it holds, 1 on the trials that ended so); the total the trimmed mean that ranks it (time_ms, null when it did not finish), and on no trial (no earned_by_trial, its value in mean) the trimmed mean''s 90% interval ends and the trials voided and run again; the same rows to every caller its phase''s scores show to. Who sees what: the whole run (view full) its owner and admins, and everyone once its private parts open (its competition''s deadline; with a running phase the results'' publication); anyone else the score''s public rows (view aggregates). A sealed phase is a 403 until its replay starts; from then every caller, its owner and admins included, sees the run cut at the replay''s clock (view replay: clock), and the whole of it from the replay''s end. On a sealed draw (the phase''s dataset a sealed-window draw) view replay is the run''s equity alone until the results are published: pnl carries its start, its equity and net at the clock (from the replay''s end the run''s as it ended), the equity curve up to the clock, and a page of fills that counts them (fills.total, failed orders and closes included) and lists none, every time in it (clock.t_ms, clock.window, pnl.window, the curve''s t_ms) in ms from the replayed window''s start, as the live board''s frames count it; no item, fill, round trip, sum, rejection, realized or unrealized figure, since any of them would name the window drawn. A phase whose scores are hidden is a 403. Money is integers of pnl.unit as decimal strings.'
responses:
'200':
description: 'OK (JSON, or its markdown twin to Accept: text/markdown)'
'400':
description: Error (ApiError)
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
enum:
- false
error:
type: array
items:
type: object
properties:
message:
type: string
path:
type: array
items:
type:
- string
- integer
required:
- message
data: {}
required:
- success
- error
'403':
description: Error (ApiError)
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
enum:
- false
error:
type: array
items:
type: object
properties:
message:
type: string
path:
type: array
items:
type:
- string
- integer
required:
- message
data: {}
required:
- success
- error
'404':
description: Error (ApiError)
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
enum:
- false
error:
type: array
items:
type: object
properties:
message:
type: string
path:
type: array
items:
type:
- string
- integer
required:
- message
data: {}
required:
- success
- error
parameters:
- in: query
name: limit
schema:
type: string
- in: query
name: cursor
schema:
type: string
minLength: 1
maxLength: 1024
- in: query
name: phase
schema:
type: string
enum:
- dev
- final
- in: query
name: full
schema:
type: string
enum:
- '0'
- '1'
- schema:
type: string
in: path
name: id
required: true
security:
- {}
- apiKey: []
- session: []
x-makefun-budget: request
/api/activity/entries:
get:
operationId: getApiActivityEntries
tags:
- Submissions
summary: The entries made across the site in the last hour, newest first
description: 'Anyone. The entries Discord''s #submissions channel posts (accepted, public, an entrant''s, in a competition the site shares) made in the last window_minutes (60), newest first: at most 20 listed, total counting them all up to 100 (100 reads as 100 or more). Each shows the entrant''s live handle and picture, the competition''s slug, title and category, and when it was made; never a score, a rank, a repository or the entry''s title. The same answer for every caller: Cache-Control public, max-age=15.'
responses:
'200':
description: ActivityEntries
security:
- {}
- apiKey: []
- session: []
x-makefun-budget: request
/api/activity/entries/latest:
get:
operationId: getApiActivityEntriesLatest
tags:
- Submissions
summary: 'The newest entries made across the site, however long ago, newest first: the…'
description: 'Anyone. The newest entries Discord''s #submissions channel posts (accepted, public, an entrant''s, in a competition the site shares), chosen as GET /api/activity/entries chooses them but with no time window: at most 10, newest first. Each shows the entrant''s live handle and picture, the competition''s slug, title and category, and when it was made; never a score, a rank, a repository or the entry''s title. The same answer for every caller: Cache-Control public, max-age=15.'
responses:
'200':
description: LatestActivityEntries
security:
- {}
- apiKey: []
- session: []
x-makefun-budget: request
/api/activity/payouts:
get:
operationId: getApiActivityPayouts
tags:
- Submissions
summary: The prizes paid out across the site in the last 365 days, newest first, and all…
description: 'Anyone. The prize payouts Discord''s #payouts channel posts (paid in USDC on Solana, in a competition the site shares whose results are out, to an entrant named by their live handle, with a public explorer link) paid in the last window_days (365), newest first, at most 50, and paid_usd, the sum of every one of them ever paid. Each shows the winner''s live handle and picture, the amount, when it was paid, the transaction on the explorer, and the competition''s slug, title and category; never a wallet address or a score. The same answer for every caller: Cache-Control public, max-age=60.'
responses:
'200':
description: ActivityPayouts
security:
- {}
- apiKey: []
- session: []
x-makefun-budget: request
/api/source-removals:
get:
operationId: getApiSourceRemovals
tags:
- Submissions
summary: 'The entries whose source an admin took down, newest first: entry, competition…'
responses:
'200':
description: Page<SourceRemoval>
'400':
description: Error (ApiError)
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
enum:
- false
error:
type: array
items:
type: object
properties:
message:
type: string
path:
type: array
items:
type:
- string
- integer
required:
- message
data: {}
required:
- success
- error
parameters:
- in: query
name: limit
schema:
type: string
- in: query
name: cursor
schema:
type: string
minLength: 1
maxLength: 1024
security:
- {}
- apiKey: []
- session: []
x-makefun-budget: request
/api/rehost/terms:
get:
operationId: getApiRehostTerms
tags:
- Submissions
summary: The rehost entrant terms in force and their sha256
description: Anyone. The terms an entrant accepts by entering a rehosted bounty (a fix for an open upstream issue the repository's owner reviews), by version, and the sha256 of their canonical JSON (RFC 8785), by which an entry names the exact text it accepted. A draft until counsel signs off (status draft, counsel_reviewed false); any change to a clause is a new version.
responses:
'200':
description: RehostTermsResponse
security:
- {}
- apiKey: []
- session: []
x-makefun-budget: request
components:
securitySchemes:
apiKey:
type: apiKey
in: header
name: x-api-key
description: A personal API key (POST /api/auth/solana/key, or a session's POST /api/auth/api-key/create). Refused by the admin routes and the session-only ones.
session:
type: apiKey
in: cookie
name: __Secure-better-auth.session_token
description: 'A signed-in session: the cookie the web sign-in sets (better-auth.session_token, unprefixed, over plain http), or the same token as Authorization: Bearer.'