API / poll-origin-mirror-transition-jobs-via-api

API

Poll Origin mirror transition jobs via the Migration API

Follow a mirror transition with GET https://api.cursor.com/v1/origin/repos/{ownerSlug}/{repoName}/mirror/transition-jobs:active and GET https://api.cursor.com/v1/origin/repos/{ownerSlug}/{repoName}/mirror/transition-jobs/{jobId}. Official reference: Origin Migration API → Get Active Mirror Transition Job / Get Mirror Transition Job.

Origin is in Early Beta and subject to change. Call these endpoints from a migration script you run as a Cursor user, not from an Origin App. Sign in with origin auth login, or pass a Cursor API key through origin api. Availability: Early Beta per the API overview.

Required scope: repository:metadata:read (user policy). An Origin App cannot call these endpoints.

After you start a transition or force cutover, poll until the job reaches a terminal status. Prefer the active endpoint for a live follow: once activeJob disappears, read lastJob for how it ended.

Get active (and last) job

curl --request GET \
  --url 'https://api.cursor.com/v1/origin/repos/OWNER_SLUG/REPO_NAME/mirror/transition-jobs:active' \
  --header 'Authorization: Bearer YOUR_ORIGIN_TOKEN'
Field Meaning
activeJob Currently active transition job (same shape as Get Mirror Transition Job). Absent when nothing is in progress.
lastJob Most recent job that reached a terminal status. Absent when the repository has never completed a transition.

A repository that has never transitioned returns an empty object.

Example:

{
  "activeJob": {
    "id": "rmt_01k2ja2000e0080000000000m4",
    "transition": "outbound_to_inbound",
    "status": "running",
    "phase": "draining-writes",
    "attemptCount": 1,
    "drainUntil": "2026-08-02T15:05:00Z",
    "startedAt": "2026-08-02T15:00:00Z",
    "createdAt": "2026-08-02T14:59:30Z",
    "updatedAt": "2026-08-02T15:01:00Z"
  },
  "lastJob": {
    "id": "rmt_01k2ja2000e0080000000000m3",
    "transition": "inbound_to_outbound",
    "status": "succeeded",
    "phase": "completed",
    "attemptCount": 1,
    "startedAt": "2026-08-01T10:00:00Z",
    "completedAt": "2026-08-01T10:12:00Z",
    "createdAt": "2026-08-01T09:59:30Z",
    "updatedAt": "2026-08-01T10:12:00Z"
  }
}

Get one job by id

curl --request GET \
  --url 'https://api.cursor.com/v1/origin/repos/OWNER_SLUG/REPO_NAME/mirror/transition-jobs/JOB_ID' \
  --header 'Authorization: Bearer YOUR_ORIGIN_TOKEN'

An unknown jobId returns HTTP 404.

Job fields

Field Meaning
id Job identifier (for example rmt_…).
transition initial_to_inbound, inbound_to_outbound, or outbound_to_inbound.
status Lifecycle: queued, running, succeeded, failed_rolled_back, requires_attention, superseded. Terminal: succeeded, failed_rolled_back, superseded. requires_attention needs operator intervention or a forced cutover.
phase Progress detail for display/debugging (for example draining-writes, snapshotting-refs, completed). New phases can appear — poll status for completion, not phase equality.
attemptCount Times this job has been attempted.
drainUntil RFC 3339 end of the write-drain window; absent outside the draining phase.
lastErrorCode / lastErrorMessage Stable failure code (for example InboundMirrorDrainTimeout, MirrorIntegrityMismatch) and human detail; absent while the job has not failed.
startedAt / completedAt / createdAt / updatedAt RFC 3339 timestamps; startedAt absent while queued; completedAt absent until terminal.

Succeeded example:

{
  "id": "rmt_01k2ja2000e0080000000000m3",
  "transition": "inbound_to_outbound",
  "status": "succeeded",
  "phase": "completed",
  "attemptCount": 1,
  "startedAt": "2026-08-02T15:00:00Z",
  "completedAt": "2026-08-02T15:12:00Z",
  "createdAt": "2026-08-02T14:59:30Z",
  "updatedAt": "2026-08-02T15:12:00Z"
}

Pair these reads with Transition Repo Mirror and Force Repo Mirror Cutover in the same migration script.