---
title: "Record one achievement's unlock + progress for the signed-in user"
method: POST
path: "/api/milestones/progress"
tags: ["Education"]
---

# Record one achievement's unlock + progress for the signed-in user

`POST /api/milestones/progress`

## Request

- Base URL: `https://www.oxfordledge.com` (the document declares no server; this is the origin it was published from)
- URL: `https://www.oxfordledge.com/api/milestones/progress`
- Auth: none declared

Upsert one (user, achievement) row. Body: `{milestone_id, progress?,
unlocked?}`. Best-effort + monotonic + anti-tamper in the helper's conflict
clause; user_id is from the session, never the body.

## Response `200`

Successful Response

- MilestoneProgressResponse: `POST /api/milestones/progress` — record one achievement's unlock+progress. MILE-1 (#101). Anti-tamper at the SQL layer (progress monotonic, unlock stamped once); returns {ok: True} on accept.
  - `ok` boolean, required: True when the upsert was accepted.
  - `error` string, nullable: Failure message.

## Other responses

- `400`: Bad Request
- `401`: Unauthorized

---

[API](https://skmtc.dev/oxfordledge/apis/oxford-ledge-api.md) · [All operations](https://skmtc.dev/oxfordledge/apis/oxford-ledge-api/llms.txt) · [OpenAPI document](https://skmtc.dev/oxfordledge/apis/oxford-ledge-api/revisions/e832a1260f0b?raw)
