Changelog
v1 only ever adds — columns, resources, operators. We never remove or repurpose a shipped field within v1; breaking changes would ship as a parallel v2 with ≥6 months of overlap and advance email notice to every token holder.
2026-09-12
A student is identity plus a cohort
cohort_namemoves onto the student, and theprogramsarray is gone. Placement used to be buried insideprograms[].cohort_name; it is now a plain field on the student, exactly like the column in the roster file your advisors upload.graduation_datemoves with it. Everything else the array carried — per-programme name, status, course year — is no longer stored, so send a student as identity, cohort and flags and nothing more.POSTandPUTnow require a complete object. A cohort needsname,display_name,program,degree,start_date,end_date,intake_yearandintake_term; a student needsemail,first_name,last_name,cohort_nameandis_alumni. These are precisely the columns the advisor roster template makes mandatory — only campus and study mode are optional there, and the same two are optional here. A half-populated cohort is invisible to the filters advisors work from, which is why it is no longer accepted.- A student write no longer creates cohorts. Naming a cohort that does not exist is refused with
COHORT_NOT_FOUNDinstead of quietly creating an empty one, because a student write carries no degree, dates or intake to build it from. Push/v1/cohortsfirst — which the guide has always recommended and the API now requires. PATCHis unchanged in spirit and more useful in practice. It never creates, so everything except the identity may be omitted, and an omitted field is left exactly as it is rather than cleared. Sendemailplus only what you want to change: correct a name, add a phone number, setis_alumni, or move someone to a different cohort withcohort_name. To move students into a cohort that does not exist yet, create it withPOST /v1/cohortsand then patch them. A cohort'snameremains frozen — every other cohort field is editable.- The API reference now has separate create and update schemas —
CohortWrite/CohortPatchandStudentWrite/StudentPatch— so it states exactly which fields a create requires rather than showing one schema for every verb.
2026-09-11
Every student must be placed in a cohort
- A student write whose programmes carry no
cohort_nameis now refused withMISSING_COHORT, and nothing is written for that row. Until now such a student was created withcohort_id: nulland reported as a plain success — an account on no advisor's roster, inheriting no résumé templates and receiving nothing targeted at their year. Only the programme the student should be placed in needs a name; the others are recorded as history either way. The most common cause is a source row with no graduation year, since a cohort name is usually built from it. - When several programmes are sent, placement now ranks only the programmes that carry a
cohort_name. Previously an in-progress programme without one would win the ranking and leave the student unplaced even though another programme named a cohort; now the student is placed in that cohort instead. The programme placement picks is also the one whosegraduation_dateis stored, so the date and the cohort always come from the same programme.
2026-09-07
Write students into CareerOS
/v1/studentsnow acceptsPOST(create),PUT(idempotent upsert) andPATCH(update). Each takes a batch of up to 500 students and returns per-row results, so one refused student never blocks the rest of a sync. Writes require a token CareerOS has enabled for writing, scoped to a single university.- Address students by email. It is unique across CareerOS, so a nightly sync is idempotent without you storing an identifier of ours. Send
external_idas well if you have a durable student number: it then takes precedence when matching, so a student whose address changes stays one account instead of becoming two. - Cohorts are writable too:
POST,PUTandPATCH /v1/cohortsmanage display name, programme, degree, campus, intake year and term, dates, study mode and résumé templates — the same fields your advisors edit in the app, so you never need to send a roster spreadsheet. A cohort is addressed bynamewithin your university andnameis frozen once created. Omitting a field leaves it untouched; sendingnullclears it. Assigning a student to a cohort is part of the student write: sendcohort_nameon the programme. - Academic context lives on the cohort, not on every student: set
degreeonce on the cohort and students placed there inherit it, and expected completion is the cohort'send_dateplusgraduation_yearon the programme. A student's owngraduation_datemeans they have actually graduated. - A created student is an invited account: no login identity until the person first signs in, and no email is sent.
invitations_sentis always0— your advisors decide when a student is contacted. Requests are student-grain, so an extract with one row per course per term must be grouped first; send the programmes in aprogramsarray. - New writable fields beyond name and graduation date: contact
phone(E.164 with country code — a local number is refused rather than guessed), and per-programmeprogram,course_year,statusand cohort placement. Sendgraduation_dateonly once a person has genuinely graduated: a past date is what makes an account an alumni account. is_alumniis writable. CareerOS normally derives it fromgraduation_date, but only when the student next signs in or their cohort or graduation date changes — there is no nightly job, so a historical roster you push would readis_alumni: falseuntil each person logged in. Sendis_alumnion the student to set it straight away. Omitting the field is not the same as sendingfalse: omitting leaves the derivation alone. The derivation still runs later and remains the authority, so a value that disagrees withgraduation_dateis overwritten the next time that student's cohort or graduation date changes — when it disagrees, we say so in that row'snotesrather than let you assume it stuck.- Cohort placement picks the programme in progress first, then one not yet started, then a finished one — a future exchange never displaces the programme a student is in today. Naming a
cohort_namethat does not exist creates it with the programme metadata you sent. PATCH /v1/students?id=eq.is unchanged. The original single-row form still takes a flat body offirst_name/last_name/graduation_dateand still answers204. If you already integrate against it, nothing about your calls needs to change; the batch form is what you get when you omit theidfilter.- Not stored on a student: dates of birth and gender (we hold no demographics), and
degree,specializationandanticipated_completion_date—degreebelongs on the cohort, and expected completion is the cohort's end date. Courses and grades are not stored yet; there is no transcript model today. Send any of them anyway and they are dropped, with the field names echoed back indropped_fieldsso you can see what was ignored rather than assume it was saved. DELETEreturns405. Erasure runs through a staged deletion flow with a grace window and its own audit trail, so it is not something an API token can start — email support@thecareeros.com.- An email that already belongs to an account at another university, to a non-student account, or to an existing CareerOS user with no university (self-serve) is refused rather than adopted — and so is a write addressed by
external_idwhose student has since moved to another university or become staff.updated_aton/v1/studentsnow moves whenever a student changes, so incremental syncs that page on it no longer miss edits. - Contact email stays create-only. Pushing a student by
external_idwith a new address records it as a secondary address and tells you so in that row'snotes; it does not become a login or the contact address, because that needs the student to verify it. Email support@thecareeros.com to complete a domain migration. - Two things that used to pass silently now come back as rejections: a
cohort_namethat matches more than one of your cohorts (COHORT_NAME_AMBIGUOUS, so we never guess which), and a résumé-template name that matches none of yours (UNKNOWN_TEMPLATE).
2026-08-12
Event participants and advisor appointments
- New resource:
/v1/appointments— every booking of your advisors' CalendarOS appointment types, across all advisors: advisor, student, appointment type, timing,status(requested/confirmed/rejected/no_show/cancelled), and location. Full history — past and upcoming, all statuses, including bookings of appointment types that were since deleted. Free-text booking notes and booking-form answers are not exposed. - New resource:
/v1/event_participants— one row per student per event: who registered for each event and who actually attended. Filter by event with?event_id=eq.; each row carries the student's identity, cohort, rawstatus/attendance_status, and derivedis_registered/has_attended/is_waitlistedbooleans that sum exactly to the counts on/v1/events. - Cancelled registrations are included with
is_registered=false, so sign-up drop-off is measurable.attendance_status=pendingmeans attendance was never marked — check the event'sattendance_trackedbefore reading absence into it.
2026-08-11
Test accounts removed; deactivated staff and students retained
/v1/eventsand/v1/alumnino longer return records that originate from CareerOS internal test accounts. Expect a small drop in row counts — these were never real events or real alumni, so any figure they affected was overstated./v1/advisor_students: theassigned_advisor_*columns now include advisors who have since been suspended or moved to another role. Previously an advisor disappeared from these columns the moment their account was deactivated, which made some students appear to have no advisor at all and undercountedassigned_advisor_countfor others. Historic advising relationships are facts and now stay reported./v1/events:registrations,attendedandwaitlistednow include students who have since been deactivated or have left their cohort. A student who attended an event keeps that attendance in your numbers. Counts can only go up.- No columns were added, removed or renamed, and no filters changed. If you snapshot these resources, expect a one-off step in the affected counts rather than a gradual shift.
2026-08-10
Analytics resources: engagement, companies, events
- New resource:
/v1/advisor_students— the student roster with advising context: applicationstatus,profile_completeness,onboarding_updated_at, cohort label, and assigned advisors. Same students as/v1/students, more columns. - New resource:
/v1/student_engagement— per-student totals for companies saved, contacts saved, outreach sent, replies received, applications submitted, interviews obtained, referrals and coffee chats. Students with no activity are included with zeros so denominators stay correct. - New resource:
/v1/student_engagement_monthly— the same metrics at one row per student per active month, for time-series reporting. - New resource:
/v1/companies— companies your students saved or applied to, with save counts and an application-funnel breakdown, one row per company per university. - New resource:
/v1/events— events your university organises, with registration and attendance counts. Useattendance_trackedto exclude events where attendance was never recorded before computing rates. cohort_namenow means the same thing everywhere./v1/studentsand/v1/resumesreturned a cohort's internalname; they now return its display label — thedisplay_nameyour advisors set, falling back tonamewhen there isn't one. That is what the app shows and what the new resources above already returned.cohort_idis unchanged, so anything keyed on the id is unaffected.- All five use the metric definitions of the equivalent CareerOS advisor screens. Two known differences from the in-app figures are documented per resource: ghost and deleted accounts are excluded here, and
student_engagement.company_savedcounts the auto-assigned CareerOS company while/v1/companiesexcludes it.
2026-07-23
Resume source files move to private storage
/v1/resumes:source_urlnow always returnsnull. Student-uploaded source PDFs moved to private storage as part of a platform-wide PII review; the raw storage URL is no longer usable. The column stays in the response shape. It was populated on almost no rows — reach out if your integration relied on it.
2026-07-15
Profiles, onboarding, alumni — and a cleaner resumes shape
- New resource:
/v1/student_profiles— structured career profiles (summary + sections), respecting student visibility settings. - New resource:
/v1/onboarding— each student's latest onboarding questionnaire; sensitive demographic answers are removed server-side. - New resource:
/v1/alumni— the alumni directory with current position where known. /v1/studentsgainedcohort_idandcohort_namecolumns./v1/resumes: removed the legacybodyandpreview_urlcolumns —contentis the single canonical resume payload.
2026-07-14
Jobs
- New resource:
/v1/jobs— employer-posted, advisor-curated, and aggregated postings from the last 365 days, withuniversity_ids/cohort_ids/all_cohortsvisibility columns.
2026-05-19
Launch
- Partners API v1 goes live:
/v1/universities,/v1/students(GET + PATCH),/v1/cohorts,/v1/campuses,/v1/resumes. - Consortium tokens: one token can span every member university, resolved at request time.