Skip to main content

Users

A user is a person in the MLH ecosystem — a hacker, an organizer, or anyone who has signed in through MLH. This page covers the user resource, the handful of special lookup endpoints (me, identify, batch_identify, phone verification), and the sub-resources nested under a user: their addresses, participations, organized events, and projects.

This page only covers what's specific to users. For conventions shared across the whole API — pagination, filtering with [eq]/[contains]/etc., expand[], error shapes, and the base URL — see Making requests. For auth and scopes, see Authentication. Every request must be authenticated with an OAuth 2.0 token or a bearer JWT; the user scope covers user data.

Throughout, created_at and updated_at are Unix timestamps (seconds) in responses. Fields like id, created_at, and updated_at are read-only — you can't set them.

Users

The top-level person record.

Endpoints

MethodPathWhat it does
GET/v4/usersList users (paginated, filterable)
GET/v4/users/{id}Get one user
POST/v4/usersCreate a user
PATCH / PUT/v4/users/{id}Update a user
GET/v4/users/meGet the user for the current token
GET/v4/users/identifyFind a user by email or phone
GET/v4/users/batch_identifyFind several users by email or phone

Fields

FieldRead/writeMeaning
idread-onlyUnique identifier. Example: usr_123abc.
first_namewritableGiven name. Example: "Ada".
last_namewritableFamily name. Example: "Lovelace".
emailwritableEmail address. Example: "ada@example.com".
phone_numberwritablePhone number, ideally E.164. Example: "+15551234567".
time_zonewritableIANA time zone. Example: "America/New_York".
suspendedwritableWhether the account is suspended.
addresswritable (create/update)The user's address. On create/update you may pass a nested address object; in responses it's a reference you can expand[].
profilewritable (create/update)Nested profile object (demographics, subscriptions, clothing sizes, etc.); a reference in responses.
professional_experiencereferenceWork history. expand[] to inline.
educationreferenceEducation history. expand[] to inline.
social_profilesreference (array)Linked social accounts. expand[] to inline.
identifiersreference (array)The emails/phones this user is known by. expand[] to inline.
challenge_submissionsreference (array)Challenge entries. expand[] to inline.
created_at / updated_atread-onlyUnix timestamps.

When you create or update a user, address accepts a nested address object (same fields as Addresses below) and profile accepts a nested profile object with fields such as country_of_residence, gender, pronouns, age, birthdate, dietary_preferences, clothing_sizes, newsletter_subscriptions, and topic_subscriptions. In responses these come back as references — add them with expand[] to see the full records.

Expanding and filtering

Expandable associations: professional_experience, education, social_profiles, address, identifiers, challenge_submissions.

GET /v4/users supports filtering on id, first_name, and last_name (with [eq], [contains], [excludes]) and email (with [eq], [contains]). See Making requests.

GET /v4/users?first_name[contains]=ada&expand[]=address&limit=50

Special endpoints

GET /v4/users/me — returns the user tied to the current access token. Use it to find out who you're acting as after signing a user in, without knowing their id up front.

GET /v4/users/me
Authorization: Bearer <token>

GET /v4/users/identify — looks a user up by a single identifier (an email address or a phone number) instead of by id. Use it when your system knows a person's email or phone but not their MLH user ID.

  • identifier (required) — the email or phone to match. Example: ada@example.com.
  • auto_create (optional, boolean) — if no user matches, create one instead of returning nothing.
GET /v4/users/identify?identifier=ada@example.com&auto_create=true

GET /v4/users/batch_identify — the same idea for many people at once. Pass identifiers as an array of emails/phones; auto_create (optional) creates any that don't yet exist. Use it to reconcile a whole list of contacts in one call.

GET /v4/users/batch_identify?identifiers[]=ada@example.com&identifiers[]=+15551234567

Addresses

A user's postal addresses, nested under the user. A user can have more than one (each has a nickname, e.g. "Home" or "School").

Endpoints

MethodPathWhat it does
GET/v4/users/{user_id}/addressesList a user's addresses
POST/v4/users/{user_id}/addressesCreate an address
POST/v4/users/{user_id}/addresses/upsertCreate or update an address

Fields

FieldRead/writeMeaning
idread-onlyAddress identifier.
nicknamewritableLabel for the address. Example: "Home".
line1writableStreet address. Example: "1 Main St".
line2 / line3writableExtra address lines (apt, suite).
citywritableExample: "New York".
statewritableState/province. Example: "NY".
postal_codewritableZIP/postal code. Example: "10001".
countrywritableCountry name. Example: "United States".
country_codewritableISO country code. Example: "US".
created_at / updated_atread-onlyUnix timestamps.

Special endpoint — upsert

POST /v4/users/{user_id}/addresses/upsert creates the address if it doesn't exist yet and updates it if it does. Use this when you sync addresses from another system and don't want to check first whether one already exists. If you include an id (or a matching nickname) it updates that record; otherwise it creates a new one.

POST /v4/users/usr_123abc/addresses/upsert
Content-Type: application/json

{
"nickname": "Home",
"line1": "1 Main St",
"city": "New York",
"state": "NY",
"postal_code": "10001",
"country_code": "US"
}

Participations

Read-only list of the events a user has taken part in, from this user's side. To create or change a participation, use the Participations resource — this nested list is for reading only.

Endpoints

MethodPathWhat it does
GET/v4/users/{user_id}/participationsList a user's participations

Fields

FieldMeaning
idParticipation identifier.
statusOne of applied, rejected, accepted, registered, checked_in, canceled.
first_name / last_nameName on the participation.
email / phone_numberContact on the participation.
sourceHow it was created: ohq, manual_import, csvifier, flatfile, avo_upload, csv_upload.
custom_fieldsEvent-specific extra data (object).
userThe user (reference; expand[] to inline).
eventThe event (reference; expand[] to inline).
created_at / updated_atUnix timestamps.

Expandable associations: event, user.

GET /v4/users/usr_123abc/participations?expand[]=event

Organized Events

Read-only list of the events a user organizes (as lead organizer, organizer, or staff). These are the same event records described in the Events resource, scoped to this user.

Endpoints

MethodPathWhat it does
GET/v4/users/{user_id}/organized_eventsList events this user organizes

Fields

Each item is an event. Key fields include id, slug, name, status (draft, pending, in_progress, ended, canceled), event_format (hackathon, hackday, presentation, workshop, conference, meetup, evergreen, campaigns, hackweek), private, starts_at / ends_at (Unix timestamps), time_zone, the various URLs (website_url, registration_url, chat_url, submission_url), counts (registrations_count, check_ins_count, project_submissions_count), and references such as lead_organizer, organizers, sponsors, sponsorships, series, event_application, and prize_categories. created_at / updated_at are Unix timestamps.

Expandable associations: prize_categories, series, sponsors, organizers, lead_organizer, sponsorships, event_application.

GET /v4/users/usr_123abc/organized_events?expand[]=lead_organizer&expand[]=series

Phone Verifications

Reads the phone verification status for a user — a single record per user rather than a list.

Endpoints

MethodPathWhat it does
GET/v4/users/{user_id}/phone_verificationGet the user's phone verification

Use this to check whether a user's phone number has been verified before relying on it (for example, for SMS-based flows). It accepts expand[] to inline related records. There's no create/update endpoint here — verification records are managed by MLH.

GET /v4/users/usr_123abc/phone_verification

Projects

The projects a user has built, nested under the user. Use these endpoints to read a user's projects and to create or update them via upsert. For the standalone project resource, see Projects.

Endpoints

MethodPathWhat it does
GET/v4/users/{user_id}/projectsList a user's projects
PUT/v4/users/{user_id}/projectsCreate or update a project (upsert)
POST/v4/users/{user_id}/projectsCreate or update a project (upsert)

Fields

FieldRead/writeMeaning
idread-onlyProject identifier. Include it to update an existing project.
namewritableProject name. Example: "Route Finder".
descriptionwritableWhat the project does.
source_urlwritableLink to the code. Example: "https://github.com/ada/route-finder".
demo_live_urlwritableLink to a live demo.
demo_video_urlwritableLink to a demo video.
built_withwritable (array)Technologies used. Example: ["python", "react"].
team_member_countwritableNumber of people on the team. Example: 3.
custom_fieldswritable (object)Extra structured data.
project_submissionsreference (array)Submissions to events. expand[] to inline.
project_usersreference (array)Team members. expand[] to inline.
challenge_submissionreferenceLinked challenge entry. expand[] to inline.
screenshotsreference (array)Attached images. expand[] to inline.
created_at / updated_atread-onlyUnix timestamps.

Expandable associations: project_submissions, project_users, challenge_submission, screenshots.

Special endpoint — upsert

Both PUT and POST /v4/users/{user_id}/projects upsert: they create the project if it's new and update it if it already exists. Include an id in the body to target an existing project; omit it to create one. The two verbs behave the same way here — use whichever fits your client.

PUT /v4/users/usr_123abc/projects
Content-Type: application/json

{
"name": "Route Finder",
"description": "Finds the fastest route across campus.",
"source_url": "https://github.com/ada/route-finder",
"built_with": ["python", "react"],
"team_member_count": 3
}

Gotchas

  • Sub-resources are nested under the user. Addresses, participations, organized events, phone verification, and projects all live under /v4/users/{user_id}/.... You need the user's id first — get it from GET /v4/users/me, GET /v4/users/identify, or a list query.
  • Upsert means create-or-update. For addresses and projects, pass an id to update an existing record or omit it to create one. Don't assume upsert always creates a new row.
  • Participations and organized events here are read-only. Manage participations through the Participations resource.
  • References vs. inlined data. Associations come back as references by default; add expand[] to inline them. See Expanding related data.