---
title: "Api Learning Progress Migrate"
method: POST
path: "/api/learning/progress/migrate"
tags: ["Education"]
---

# Api Learning Progress Migrate

`POST /api/learning/progress/migrate`

## 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/learning/progress/migrate`
- Auth: none declared

Import a user's localStorage mastery into PG with source='client_migrated'.

Request body: {"modules": {"mod-id": {score, passed, attempts, hintUsed?, timeSpent?}, ...}}

Writes each module via ON CONFLICT DO NOTHING (not UPDATE) — we
never want to overwrite an existing server_graded row. Returns a
count of {inserted, skipped} so the client can decide whether to
suppress the legacy-local banner.

## Response `200`

Successful Response

- LearningProgressMigrateResponse: `POST /api/learning/progress/migrate` — one-shot localStorage->PG. Run 19 F4 backfill 2026-05-12. A3 Step 6 cutover helper. ON CONFLICT DO NOTHING so server_graded rows are never clobbered.
  - `inserted` integer, nullable: Modules inserted as source='client_migrated'.
  - `skipped` integer, nullable: Modules skipped because a server_graded row already exists.
  - `error` string, nullable: Top-level error.

---

[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)
