Skip to main content

Challenges

Challenges are sponsor-run prizes or tasks attached to an event — for example, "Best use of a sponsor's API." A challenge is linked to the event it runs at, and participants compete to win it.

Challenge submissions are the entries participants send in for a challenge. Each submission ties a project to a challenge and moves through a review workflow (submitted, approved, rejected, or withdrawn) until an organizer decides whether it won.

This page covers both resources. For conventions shared across the API — authentication, pagination, filtering, expanding related data, and errors — see Making requests and Authentication.

Challenges

A challenge record links an event to a challenge (the sponsor prize). It tells you which event a challenge belongs to and which challenge it points at.

Endpoints

MethodPathDoes
GET/v4/challengesList challenges
GET/v4/challenges/{id}Get one challenge
POST/v4/challengesCreate a challenge
PATCH / PUT/v4/challenges/{id}Update a challenge
GET/v4/challenges/identifyLook up a challenge entry by a user's email or phone

GET /v4/challenges supports pagination and filtering. You can filter on the challenge record's own fields (id) and on the underlying challenge's fields (name, description, short_description, prize_description, challenge_type, featured, active, mlh_sponsorship), plus created_at and updated_at. See Filtering.

Fields

These are the fields on a challenge record.

FieldRequiredRead-onlyDescription
idYesUnique identifier for the challenge record. Example: "a1b2c3d4-...".
event_idOptionalNoID of the event this challenge belongs to. Example: "e5f6...".
challenge_idOptionalNoID of the challenge (the sponsor prize) this record points at. Example: "c7d8...".
eventOptionalNoThe related event. Expand with expand[]=event to include it.
challengeOptionalNoThe related challenge. Expand with expand[]=challenge to include it.
created_atYesWhen the record was created, as a Unix timestamp (seconds). Example: 1755561600.
updated_atYesWhen the record was last updated, as a Unix timestamp (seconds). Example: 1755561600.

id, created_at, and updated_at are set by the API and cannot be written. In responses, created_at and updated_at are Unix timestamps; when you send them in a request body they are ISO 8601 datetime strings.

Use expand[] to pull in related records — event and challenge are the expandable associations on both GET /v4/challenges and GET /v4/challenges/{id}. See Expanding related data.

Scopes

These endpoints use OAuth 2.0. Request only the scopes your integration needs (see Authentication). Reading challenges needs read access; creating or updating them needs write access.

Identify a challenge

GET /v4/challenges/identify

Looks up a challenge entry for a user by an identifier. Use this when you have a participant's email or phone number and need to find their challenge record.

ParameterInRequiredDescription
identifierqueryYesThe email address or phone number to identify the user by. Example: jane@example.com.
auto_createqueryOptionalIf true, create the user when no match is found. Defaults to false.
GET /v4/challenges/identify?identifier=jane@example.com

The response is a challenge record with the same fields listed above.

Request examples

List challenges for one event, with the related event and challenge expanded:

GET /v4/challenges?event_id[eq]=e5f6...&expand[]=event&expand[]=challenge

Create a challenge record linking an event to a challenge:

POST /v4/challenges
Content-Type: application/json

{
"event_id": "e5f6...",
"challenge_id": "c7d8..."
}

Challenge Submissions

A challenge submission is a participant's entry for a challenge. It records the project, who submitted it, which event and challenge it's for, and where it is in the review workflow.

Endpoints

MethodPathDoes
GET/v4/challenge_submissionsList submissions
GET/v4/challenge_submissions/{id}Get one submission
POST/v4/challenge_submissionsCreate a submission
PATCH / PUT/v4/challenge_submissions/{id}Update a submission
DELETE/v4/challenge_submissions/{id}Delete a submission
POST/v4/challenge_submissions/{id}/submitSubmit a draft for review
POST/v4/challenge_submissions/{id}/manual_approveApprove one submission by hand
POST/v4/challenge_submissions/{id}/auto_approveAuto-approve one submission
POST/v4/challenge_submissions/{id}/bulk_approveApprove as part of a bulk action
POST/v4/challenge_submissions/{id}/rejectReject a submission
POST/v4/challenge_submissions/{id}/withdrawWithdraw a submission
POST/v4/submissions/exportExport submissions

GET /v4/challenge_submissions supports pagination and filtering on project_id, event_id, challenge_id, submitter_id, status, winner, submitted_at, created_at, and updated_at. Expandable associations are project, submitter, event, and challenge.

Fields

FieldRequiredRead-onlyDescription
idYesUnique identifier for the submission. Example: "9f0a...".
project_idOptionalNoID of the project being submitted. Example: "p1q2...".
submitter_idOptionalNoID of the user who submitted it. Example: "u3v4...".
event_idOptionalNoID of the event the submission is for.
challenge_idOptionalNoID of the challenge the submission is for.
statusOptionalNoWhere the submission is in the workflow. One of draft, submitted, manual_approved, bulk_approved, auto_approved, rejected, withdrawn. Usually driven by the workflow actions below rather than set directly.
winnerOptionalNoWhether this submission won the challenge. true or false.
rejection_reasonOptionalNoWhy the submission was rejected. Set when you reject. Example: "Out of scope".
withdraw_reasonOptionalNoWhy the submission was withdrawn. Set when you withdraw. Example: "Duplicate entry".
submitted_atOptionalNoWhen it was submitted. Unix timestamp in responses; ISO 8601 datetime string in requests.
accepted_atOptionalNoWhen it was accepted. Unix timestamp in responses; ISO 8601 in requests.
rejected_atOptionalNoWhen it was rejected. Unix timestamp in responses; ISO 8601 in requests.
withdrawn_atOptionalNoWhen it was withdrawn. Unix timestamp in responses; ISO 8601 in requests.
verified_atOptionalNoWhen it was verified. Unix timestamp in responses; ISO 8601 in requests.
custom_fieldsOptionalNoAn object for extra event-specific data. Example: { "demo_url": "https://..." }.
projectOptionalNoThe related project. Expand with expand[]=project.
submitterOptionalNoThe related user. Expand with expand[]=submitter.
eventOptionalNoThe related event. Expand with expand[]=event.
challengeOptionalNoThe related challenge. Expand with expand[]=challenge.
created_atYesWhen the submission was created, as a Unix timestamp.
updated_atYesWhen the submission was last updated, as a Unix timestamp.

id, created_at, and updated_at are set by the API and cannot be written. In responses, all timestamp fields (created_at, updated_at, submitted_at, accepted_at, rejected_at, withdrawn_at, verified_at) are Unix timestamps; in request bodies the datetime fields are ISO 8601 strings.

Scopes

These endpoints use OAuth 2.0. Request only the scopes your integration needs (see Authentication). Reading submissions needs read access; creating, updating, deleting, or running a workflow action needs write access.

Workflow actions

A submission moves through its lifecycle with the action endpoints below. Each is a POST to /v4/challenge_submissions/{id}/<action>, where {id} is the submission you're acting on. Each returns the updated submission.

  • submit — moves a draft submission into review. Call this once a participant has finished their entry. After this the status becomes submitted.
  • manual_approve — approves a single submission by hand, typically after an organizer reviews it. Sets the status to manual_approved.
  • auto_approve — approves a single submission through an automated rule rather than manual review. Sets the status to auto_approved.
  • bulk_approve — approves a submission as part of a bulk approval. Use this when approving many entries at once. Sets the status to bulk_approved. This still targets one submission per call (via its {id}); the "bulk" refers to the approval mode, so to approve several entries you call it once per submission.
  • reject — rejects a submission. Set rejection_reason in the body to record why. Sets the status to rejected.
  • withdraw — withdraws a submission (for example, a participant pulls their entry). Set withdraw_reason in the body to record why. Sets the status to withdrawn.

Gotchas:

  • Actions depend on the current status. submit applies to a draft; the approve, reject, and withdraw actions apply to a submission that has been submitted. Acting on a submission that isn't in the right state returns a validation error.
  • There are three separate approve actions — manual_approve, auto_approve, and bulk_approve — and they set different final statuses (manual_approved, auto_approved, bulk_approved). Pick the one that matches how the decision was made. All three approve a single submission per call; none of them approves a batch in one request.
  • Prefer the workflow actions over writing status directly with PATCH/PUT, so the related timestamp and reason fields are set consistently.

Export

POST /v4/submissions/export

Runs an export over challenge submissions. Send a request body describing the submissions to export using the submission fields above (for example, filter by event_id, challenge_id, or status).

Request examples

Submit a draft for review:

POST /v4/challenge_submissions/9f0a.../submit

Reject a submission with a reason:

POST /v4/challenge_submissions/9f0a.../reject
Content-Type: application/json

{
"rejection_reason": "Out of scope for this challenge"
}

Withdraw a submission with a reason:

POST /v4/challenge_submissions/9f0a.../withdraw
Content-Type: application/json

{
"withdraw_reason": "Duplicate entry"
}

List a challenge's winning submissions, with the project and submitter expanded:

GET /v4/challenge_submissions?challenge_id[eq]=c7d8...&winner[eq]=true&expand[]=project&expand[]=submitter