API Reference

TheMigrator REST API

Programmatic access to tenants, migration jobs, and live progress streams. All endpoints return JSON and require a Bearer token.

Overview

Base URL
https://api.themigrator.app

All endpoints are versioned under /v1. TLS is required — HTTP requests are rejected.

Authentication

All requests must include an Authorization header with a Bearer token. Generate API keys from Settings → API keys in your dashboard.

Authorization: Bearer tmk_live_••••••••••••••••••••••••••••••••

Keep your API key secret. Do not commit it to source control. Use environment variables.

Rate limits

Requests are rate-limited at 1,000 requests per minute per organisation. Exceeding this returns a 429 Too Many Requests response with a Retry-After header indicating how many seconds to wait.

Starter
300 / min
Pro
1,000 / min
Enterprise
Custom
Errors

All errors return a consistent JSON body with an error message, a machine-readable code, and the HTTP status.

{
  "error": "Tenant not found",
  "code": "TENANT_NOT_FOUND",
  "status": 404
}
UNAUTHORIZED401Missing or invalid API key.
FORBIDDEN403Your plan does not have access to this resource.
NOT_FOUND404The requested resource does not exist.
VALIDATION_ERROR422The request body failed validation. The errors field contains details.
TENANT_NOT_FOUND404The specified tenant ID does not exist in your organisation.
JOB_NOT_FOUND404The specified job ID does not exist in your organisation.
JOB_NOT_RUNNING409Cannot pause a job that is not RUNNING.
JOB_NOT_PAUSED409Cannot resume a job that is not PAUSED.
RATE_LIMITED429You have exceeded the request rate limit. Retry after the Retry-After header value.
INTERNAL_ERROR500An unexpected server error occurred.

Tenants

A tenant is a connected Microsoft 365 organisation. You must connect at least two tenants (source and destination) before creating a migration job.

POST/v1/tenants/connectInitiate tenant OAuth

Starts the Microsoft 365 OAuth 2.0 admin consent flow. Returns an authorization URL that a Global Admin must visit to grant the application the required Graph API permissions. After the admin completes consent, the callback endpoint stores the token and the tenant appears in your tenant list.

Request body
domainreq
stringPrimary domain of the M365 tenant (e.g. contoso.com).
rolereq
"source" | "destination"Whether this tenant is the migration source or destination.
clientId
stringAzure App Registration client ID. If omitted, TheMigrator's shared registration is used.
clientSecret
stringAzure App Registration client secret. Required when clientId is provided.
Response
{
  "authUrl": "https://login.microsoftonline.com/common/adminconsent?client_id=...",
  "state": "tok_9Kx2mPqRv"
}
cURL
curl -X POST https://api.themigrator.app/v1/tenants/connect \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "domain": "contoso.com",
    "role": "source"
  }'
GET/v1/tenantsList connected tenants

Returns all M365 tenants connected to the current organisation, including discovered object counts, storage quotas, and enabled workloads. Storage quota fields are populated during tenant discovery — they may be null if discovery has not completed.

Response
{
  "tenants": [
    {
      "id": "ten_01HXKP3B",
      "domain": "contoso.com",
      "type": "M365",
      "role": "source",
      "mailboxCount": 312,
      "siteCount": 47,
      "totalSizeBytes": 1099511627776,
      "sharepointQuotaBytes": 26843545600000,
      "sharepointUsedBytes": 8053063680000,
      "onedriveQuotaPerUserBytes": 1099511627776,
      "workloads": ["EMAIL", "SHAREPOINT", "ONEDRIVE", "TEAMS"],
      "discoveredAt": "2026-04-10T09:23:00Z",
      "connectedAt": "2026-04-10T09:00:00Z"
    }
  ]
}
cURL
curl https://api.themigrator.app/v1/tenants \
  -H "Authorization: Bearer $API_KEY"
GET/v1/tenants/:idGet tenant detail

Returns detail for a single connected tenant.

Path parameters
idreq
stringThe tenant ID.
Response
{
  "tenant": {
    "id": "ten_01HXKP3B",
    "domain": "contoso.com",
    "type": "M365",
    "role": "source",
    "mailboxCount": 312,
    "siteCount": 47,
    "totalSizeBytes": 1099511627776,
    "sharepointQuotaBytes": 26843545600000,
    "sharepointUsedBytes": 8053063680000,
    "onedriveQuotaPerUserBytes": 1099511627776,
    "workloads": ["EMAIL", "SHAREPOINT", "ONEDRIVE", "TEAMS"],
    "discoveredAt": "2026-04-10T09:23:00Z",
    "connectedAt": "2026-04-10T09:00:00Z"
  }
}
cURL
curl https://api.themigrator.app/v1/tenants/ten_01HXKP3B \
  -H "Authorization: Bearer $API_KEY"
GET/v1/tenants/:id/usersList discovered users

Returns the list of users discovered in the tenant during the most recent discovery scan. Used by the wizard to populate the mailbox/user mapping step for Email, OneDrive, and Teams Chat migrations.

Path parameters
idreq
stringThe tenant ID.
Response
{
  "users": [
    {
      "id": "dbu_01HXKP3C",
      "tenantId": "ten_01HXKP3B",
      "upn": "[email protected]",
      "displayName": "John Smith",
      "sourceSizeBytes": 3221225472
    },
    {
      "id": "dbu_01HXKP3D",
      "tenantId": "ten_01HXKP3B",
      "upn": "[email protected]",
      "displayName": "Lisa Nguyen",
      "sourceSizeBytes": 1073741824
    }
  ],
  "latestJob": {
    "id": "dis_01HXKP3E",
    "status": "DONE",
    "completedAt": "2026-04-10T09:23:00Z"
  }
}
cURL
curl https://api.themigrator.app/v1/tenants/ten_01HXKP3B/users \
  -H "Authorization: Bearer $API_KEY"
GET/v1/tenants/:id/sitesList discovered sites

Returns the list of SharePoint sites discovered in the tenant during the most recent discovery scan. Used by the wizard to populate the site mapping step for SharePoint migrations.

Path parameters
idreq
stringThe tenant ID.
Response
{
  "sites": [
    {
      "id": "dbs_01HXKP3F",
      "tenantId": "ten_01HXKP3B",
      "siteId": "contoso.sharepoint.com,abc-123,...",
      "name": "Marketing",
      "url": "https://contoso.sharepoint.com/sites/marketing",
      "sizeBytes": "10737418240"
    }
  ],
  "latestJob": {
    "id": "dis_01HXKP3E",
    "status": "DONE",
    "completedAt": "2026-04-10T09:23:00Z"
  }
}
cURL
curl https://api.themigrator.app/v1/tenants/ten_01HXKP3B/sites \
  -H "Authorization: Bearer $API_KEY"
GET/v1/tenants/:id/teamsList discovered Teams

Returns the list of Microsoft Teams workspaces discovered in the tenant during the most recent discovery scan. Used by the wizard to populate the team mapping step for Teams Channels migrations. Teams are discovered via the Microsoft Graph groups endpoint filtered by resourceProvisioningOptions eq 'Team'.

Path parameters
idreq
stringThe tenant ID.
Response
{
  "teams": [
    {
      "id": "dbt_01HXKP3G",
      "tenantId": "ten_01HXKP3B",
      "teamId": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
      "name": "Engineering",
      "description": "Core engineering team",
      "memberCount": 24
    },
    {
      "id": "dbt_01HXKP3H",
      "tenantId": "ten_01HXKP3B",
      "teamId": "ffffffff-0000-1111-2222-333333333333",
      "name": "Sales",
      "description": "",
      "memberCount": 41
    }
  ],
  "latestJob": {
    "id": "dis_01HXKP3E",
    "status": "DONE",
    "completedAt": "2026-04-10T09:23:00Z"
  }
}
cURL
curl https://api.themigrator.app/v1/tenants/ten_01HXKP3B/teams \
  -H "Authorization: Bearer $API_KEY"
DELETE/v1/tenants/:idDisconnect a tenant

Revokes access and removes the tenant connection. Any running jobs that reference this tenant are paused before deletion.

Path parameters
idreq
stringThe tenant ID.
Response
{ "deleted": true }
cURL
curl -X DELETE https://api.themigrator.app/v1/tenants/ten_01HXKP3B \
  -H "Authorization: Bearer $API_KEY"

Jobs

A job represents a single migration task — one workload type between one source and one destination tenant. Jobs are processed asynchronously by the worker fleet via BullMQ.

POST/v1/jobsCreate a migration job

Creates a new migration job and enqueues it for processing. The job starts immediately unless scheduledAt is provided. Scope options default to all available items for the selected type. The wizard UI runs pre-flight storage and licensing checks before calling this endpoint — when calling directly via API, ensure destination quotas are sufficient using the tenant storage fields.

Request body
sourceTenantIdreq
stringID of the source tenant.
destTenantIdreq
stringID of the destination tenant.
typereq
"EMAIL" | "SHAREPOINT" | "ONEDRIVE" | "TEAMS"Migration workload type.
scope
objectPer-type scope flags. EMAIL: { email, calendar, contacts }. SHAREPOINT: { lists, permissions }. ONEDRIVE: { files, permissions }. TEAMS: { teamsChannels, teamsChat }. teamsChat requires Chat.Read.All on the source App Registration.
dryRun
booleanValidates mappings and estimates counts without moving data. Defaults to false.
scheduledAt
string (ISO 8601)Schedule the job to start at a future time. Omit to start immediately.
Response
{
  "job": {
    "id": "job_01HY2MQR",
    "type": "EMAIL",
    "status": "QUEUED",
    "sourceTenantId": "ten_01HXKP3B",
    "destTenantId": "ten_02HXZ9QW",
    "scope": { "email": true, "calendar": true, "contacts": true },
    "totalItems": 0,
    "doneItems": 0,
    "errorItems": 0,
    "skippedItems": 0,
    "dryRun": false,
    "createdAt": "2026-05-09T08:00:00Z",
    "startedAt": null,
    "completedAt": null
  }
}
cURL
curl -X POST https://api.themigrator.app/v1/jobs \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "sourceTenantId": "ten_01HXKP3B",
    "destTenantId": "ten_02HXZ9QW",
    "type": "EMAIL",
    "scope": { "email": true, "calendar": true, "contacts": true }
  }'
POST/v1/jobs/batchCreate a batch of migration jobs

Creates multiple migration jobs in a single request — one per batch item. Each batch item can target a different set of mailboxes, sites, or teams and can start at a different scheduled time. Useful for phased rollouts where different groups of users migrate at different times. The jobs are created in parallel and all share the same source tenant, destination tenant, type, and scope. Returns all job IDs in order.

The batches array must have at least one item. Jobs are created in declaration order — the first element of the response jobIds array corresponds to the first element of the request batches array.

Request body
sourceTenantIdreq
stringID of the source tenant.
destTenantIdreq
stringID of the destination tenant.
typereq
"EMAIL" | "SHAREPOINT" | "ONEDRIVE" | "TEAMS"Migration workload type — shared across all batches.
scope
objectPer-type scope flags. Shared across all batches.
dryRun
booleanApplies to all batches. Defaults to false.
batchesreq
BatchItem[]Array of batch definitions. Each item creates one job.
batches[].name
stringHuman-readable name for this batch (for your reference only).
batches[].scheduledAt
string (ISO 8601)When this batch job should start. Omit to start immediately.
batches[].options
objectPer-batch job options. Supports mailboxes, mailboxMappings, siteMappings, and any field accepted by POST /v1/jobs options.
Response
{
  "jobIds": [
    "job_01HY2MQR",
    "job_01HY2MQS",
    "job_01HY2MQT"
  ]
}
cURL
curl -X POST https://api.themigrator.app/v1/jobs/batch \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "sourceTenantId": "ten_01HXKP3B",
    "destTenantId": "ten_02HXZ9QW",
    "type": "EMAIL",
    "scope": { "email": true, "calendar": true, "contacts": true },
    "batches": [
      {
        "name": "Wave 1 — Exec team",
        "scheduledAt": "2026-06-01T22:00:00Z",
        "options": {
          "mailboxes": ["[email protected]", "[email protected]"],
          "mailboxMappings": [
            { "source": "[email protected]",  "dest": "[email protected]" },
            { "source": "[email protected]",  "dest": "[email protected]" }
          ]
        }
      },
      {
        "name": "Wave 2 — Engineering",
        "scheduledAt": "2026-06-02T22:00:00Z",
        "options": {
          "mailboxes": ["[email protected]", "[email protected]"],
          "mailboxMappings": [
            { "source": "[email protected]", "dest": "[email protected]" },
            { "source": "[email protected]",   "dest": "[email protected]" }
          ]
        }
      }
    ]
  }'
GET/v1/jobsList migration jobs

Returns a paginated list of migration jobs for the current organisation, ordered by creation date descending.

Query parameters
status
stringFilter by status: QUEUED, RUNNING, PAUSED, DONE, ERROR, DRY_RUN.
type
stringFilter by migration type: EMAIL, SHAREPOINT, ONEDRIVE, TEAMS.
limit
numberResults per page. Default 20, max 100.
cursor
stringPagination cursor from a previous response's nextCursor field.
Response
{
  "jobs": [
    {
      "id": "job_01HY2MQR",
      "type": "EMAIL",
      "status": "RUNNING",
      "sourceTenantId": "ten_01HXKP3B",
      "destTenantId": "ten_02HXZ9QW",
      "totalItems": 48210,
      "doneItems": 31405,
      "errorItems": 12,
      "skippedItems": 3,
      "bytesTransferred": 5368709120,
      "createdAt": "2026-05-09T08:00:00Z",
      "startedAt": "2026-05-09T08:01:12Z",
      "completedAt": null
    }
  ],
  "nextCursor": "cur_KxP2Rv9",
  "hasMore": true
}
cURL
curl "https://api.themigrator.app/v1/jobs?status=RUNNING&limit=10" \
  -H "Authorization: Bearer $API_KEY"
GET/v1/jobs/:idGet job detail

Returns the full detail for a single job, including live counters and configuration.

Path parameters
idreq
stringThe job ID.
Response
{
  "job": {
    "id": "job_01HY2MQR",
    "type": "EMAIL",
    "status": "RUNNING",
    "sourceTenantId": "ten_01HXKP3B",
    "destTenantId": "ten_02HXZ9QW",
    "scope": { "email": true, "calendar": true, "contacts": true },
    "totalItems": 48210,
    "doneItems": 31405,
    "errorItems": 12,
    "skippedItems": 3,
    "bytesTransferred": 5368709120,
    "dryRun": false,
    "createdAt": "2026-05-09T08:00:00Z",
    "startedAt": "2026-05-09T08:01:12Z",
    "completedAt": null
  }
}
cURL
curl https://api.themigrator.app/v1/jobs/job_01HY2MQR \
  -H "Authorization: Bearer $API_KEY"
PATCH/v1/jobs/:id/pausePause a running job

Signals the worker to pause after completing its current item batch. The job transitions to PAUSED status. In-flight items are completed; no new items are picked up.

Path parameters
idreq
stringThe job ID.
Response
{ "status": "PAUSED" }
cURL
curl -X PATCH https://api.themigrator.app/v1/jobs/job_01HY2MQR/pause \
  -H "Authorization: Bearer $API_KEY"
PATCH/v1/jobs/:id/resumeResume a paused job

Re-queues a paused job. The worker picks it up and continues from where it left off — already-migrated items are skipped via delta tracking.

Path parameters
idreq
stringThe job ID.
Response
{ "status": "QUEUED" }
cURL
curl -X PATCH https://api.themigrator.app/v1/jobs/job_01HY2MQR/resume \
  -H "Authorization: Bearer $API_KEY"
DELETE/v1/jobs/:idCancel a job

Cancels and removes a job. Running jobs are stopped after the current batch. Data already migrated is not reversed.

Path parameters
idreq
stringThe job ID.
Response
{ "deleted": true }
cURL
curl -X DELETE https://api.themigrator.app/v1/jobs/job_01HY2MQR \
  -H "Authorization: Bearer $API_KEY"
GET/v1/jobs/:id/logsStream job logs

Opens a Server-Sent Events stream that emits log lines in real time as the worker processes items. The connection stays open until the job completes, at which point a done event is emitted and the stream closes.

Set the Accept: text/event-stream header and use an SSE-compatible client. The stream emits log and done event types.

Path parameters
idreq
stringThe job ID.
Query parameters
since
string (ISO 8601)Only emit log lines after this timestamp. Use when reconnecting to avoid replaying the full history.
level
"INFO" | "OK" | "WARN" | "ERROR"Filter by minimum log level. Defaults to all levels.
SSE stream
event: log
data: {"id":"log_01HY3A","level":"OK","message":"[email protected] → 4,210 items migrated","ts":"2026-05-09T08:05:00Z"}

event: log
data: {"id":"log_01HY3B","level":"WARN","message":"Throttled (429) — retrying in 8s","ts":"2026-05-09T08:05:01Z"}

event: log
data: {"id":"log_01HY3C","level":"ERROR","message":"[email protected] — 403 Forbidden on Mail.ReadWrite","ts":"2026-05-09T08:07:14Z"}

event: done
data: {"status":"DONE","completedAt":"2026-05-09T10:22:00Z"}
cURL
curl -N https://api.themigrator.app/v1/jobs/job_01HY2MQR/logs \
  -H "Authorization: Bearer $API_KEY" \
  -H "Accept: text/event-stream"
GET/v1/jobs/:id/logs/exportExport logs as CSV

Downloads the complete log history for a job as a CSV file. Returns a binary response with Content-Disposition: attachment; filename="job-logs.csv".

Path parameters
idreq
stringThe job ID.
CSV file
id,level,message,ts
log_01HY3A,OK,[email protected] → 4210 items migrated,2026-05-09T08:05:00Z
log_01HY3B,WARN,Throttled (429) — retrying in 8s,2026-05-09T08:05:01Z
log_01HY3C,ERROR,[email protected] — 403 Forbidden on Mail.ReadWrite,2026-05-09T08:07:14Z
cURL
curl -o job-logs.csv \
  https://api.themigrator.app/v1/jobs/job_01HY2MQR/logs/export \
  -H "Authorization: Bearer $API_KEY"
GET/v1/jobs/:id/mailboxesGet mailbox progress

Returns paginated per-mailbox migration progress for an EMAIL job. Each entry shows the source → destination mapping and current item counts.

Path parameters
idreq
stringThe job ID.
Query parameters
status
stringFilter by mailbox status: PENDING, RUNNING, DONE, ERROR.
limit
numberResults per page. Default 50, max 200.
cursor
stringPagination cursor.
Response
{
  "mailboxes": [
    {
      "id": "mbp_01HYA3X",
      "email": "[email protected]",
      "destEmail": "[email protected]",
      "status": "DONE",
      "totalItems": 4210,
      "doneItems": 4210,
      "errorItems": 0,
      "sizeBytes": 1073741824,
      "startedAt": "2026-05-09T08:02:00Z",
      "completedAt": "2026-05-09T08:09:44Z"
    },
    {
      "id": "mbp_01HYA3Y",
      "email": "[email protected]",
      "destEmail": "[email protected]",
      "status": "ERROR",
      "totalItems": 8920,
      "doneItems": 0,
      "errorItems": 1,
      "sizeBytes": 2147483648,
      "startedAt": "2026-05-09T08:07:00Z",
      "completedAt": null
    }
  ],
  "nextCursor": null,
  "hasMore": false
}
cURL
curl "https://api.themigrator.app/v1/jobs/job_01HY2MQR/mailboxes?status=DONE&limit=50" \
  -H "Authorization: Bearer $API_KEY"

Devices

The Devices API lets you manage Windows endpoints running the MigratorAgent service. Agents register themselves, check in for commands, and report results. You can list connected devices and send migration commands from the dashboard or directly via API.

POST/v1/devices/registerRegister a device

Called automatically by the MigratorAgent installer. Registers a new Windows device with the organisation and returns a device ID and secret that the agent stores in the Windows registry for future check-ins. You do not normally call this endpoint directly.

Request body
orgIdreq
stringOrganisation ID — passed as /org <orgId> when running the installer.
hostnamereq
stringWindows machine hostname (COMPUTERNAME).
ipAddress
stringCurrent IP address of the device.
machineSid
stringWindows machine SID for deduplication.
domain
stringWindows domain the device is currently joined to, if any.
agentVersion
stringAgent build version string.
Response
{
  "deviceId": "dev_01HXKP9A",
  "secret": "a3f8c2d1e7b6..."
}
cURL
curl -X POST https://api.themigrator.app/v1/devices/register \
  -H "Content-Type: application/json" \
  -d '{
    "orgId": "org_01HXKP3A",
    "hostname": "DESKTOP-ABC123",
    "ipAddress": "192.168.1.42",
    "domain": "contoso.local"
  }'
POST/v1/devices/checkinDevice check-in

Called by the MigratorAgent every 3 minutes. Updates the device's last-seen timestamp and returns any pending commands queued for this device. Authentication uses the device secret returned at registration.

Request body
deviceIdreq
stringDevice ID returned at registration.
secretreq
stringDevice secret returned at registration (bcrypt-verified server-side).
Response
{
  "commands": [
    {
      "id": "cmd_01HY4PQR",
      "type": "FULL_MIGRATION",
      "payload": {
        "ppkgUrl": "https://storage.azure.com/migration-staging/enroll.ppkg",
        "destTenantId": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
      }
    }
  ]
}
cURL
curl -X POST https://api.themigrator.app/v1/devices/checkin \
  -H "Content-Type: application/json" \
  -d '{
    "deviceId": "dev_01HXKP9A",
    "secret": "a3f8c2d1e7b6..."
  }'
POST/v1/devices/resultReport command result

Called by the agent after executing a command (or when a command fails). Updates the command status to DONE, RUNNING (Phase 1 complete, awaiting reboot), or ERROR, and records the result message.

Request body
deviceIdreq
stringDevice ID.
secretreq
stringDevice secret.
commandIdreq
stringThe command ID being reported.
statusreq
"DONE" | "RUNNING" | "ERROR"Command outcome. RUNNING is used by FULL_MIGRATION after Phase 1 to indicate the reboot is pending.
result
stringHuman-readable result message or error description.
Response
{ "ok": true }
cURL
curl -X POST https://api.themigrator.app/v1/devices/result \
  -H "Content-Type: application/json" \
  -d '{
    "deviceId": "dev_01HXKP9A",
    "secret": "a3f8c2d1e7b6...",
    "commandId": "cmd_01HY4PQR",
    "status": "DONE",
    "result": "Phase 2: Entra join and Intune enrollment completed via provisioning package"
  }'
GET/v1/devicesList devices

Returns all devices registered to the organisation, with their current status and most recent check-in time. Status is computed from lastSeenAt: ONLINE if seen within the last 10 minutes, MIGRATING if a command is in progress, otherwise OFFLINE.

Response
{
  "devices": [
    {
      "id": "dev_01HXKP9A",
      "hostname": "DESKTOP-ABC123",
      "ipAddress": "192.168.1.42",
      "domain": "contoso.local",
      "status": "ONLINE",
      "lastSeenAt": "2026-05-13T10:55:00Z",
      "agentVersion": "0.6.35",
      "createdAt": "2026-05-13T09:00:00Z"
    }
  ]
}
cURL
curl https://api.themigrator.app/v1/devices \
  -H "Authorization: Bearer $API_KEY"
DELETE/v1/devices/:idRemove a device

Removes a device registration. The agent on the device will continue running but its check-ins will be rejected with 404 until it is re-registered or uninstalled.

Path parameters
idreq
stringThe device ID.
Response
{ "deleted": true }
cURL
curl -X DELETE https://api.themigrator.app/v1/devices/dev_01HXKP9A \
  -H "Authorization: Bearer $API_KEY"
POST/v1/devices/:id/commandsSend a command

Queues a command to be picked up by the device on its next check-in (within 3 minutes). The agent executes commands sequentially — if a command is already running, the new command waits until the current one completes.

Path parameters
idreq
stringThe device ID.
Request body
typereq
"FULL_MIGRATION" | "INTUNE_MIGRATION" | "DOMAIN_MIGRATION" | "OFFICE_RESET" | "TEAMS_RESET" | "ONEDRIVE_RESET"Command type.
payload
objectCommand-specific payload. FULL_MIGRATION accepts: ppkgUrl, enrollmentUrl, destTenantId, destDomain, username, password. DOMAIN_MIGRATION accepts: destDomain, username, password. INTUNE_MIGRATION accepts: enrollmentUrl.
Response
{
  "command": {
    "id": "cmd_01HY4PQR",
    "deviceId": "dev_01HXKP9A",
    "type": "FULL_MIGRATION",
    "status": "PENDING",
    "createdAt": "2026-05-13T11:00:00Z"
  }
}
cURL
curl -X POST https://api.themigrator.app/v1/devices/dev_01HXKP9A/commands \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "FULL_MIGRATION",
    "payload": {
      "ppkgUrl": "https://storage.azure.com/migration-staging/enroll.ppkg",
      "destTenantId": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
    }
  }'
GET/v1/devices/:id/commandsList commands

Returns the command history for a device, ordered by creation date descending.

Path parameters
idreq
stringThe device ID.
Query parameters
status
stringFilter by status: PENDING, RUNNING, DONE, ERROR, CANCELLED.
limit
numberResults per page. Default 20, max 100.
Response
{
  "commands": [
    {
      "id": "cmd_01HY4PQR",
      "type": "FULL_MIGRATION",
      "status": "DONE",
      "result": "Phase 2: Entra join and Intune enrollment completed via provisioning package",
      "createdAt": "2026-05-13T11:00:00Z",
      "updatedAt": "2026-05-13T11:08:42Z"
    }
  ]
}
cURL
curl "https://api.themigrator.app/v1/devices/dev_01HXKP9A/commands?status=DONE" \
  -H "Authorization: Bearer $API_KEY"
PATCH/v1/devices/:id/commands/:commandId/cancelCancel a command

Cancels a PENDING command before the agent picks it up. Commands that are already RUNNING cannot be cancelled — the agent will complete execution and report the result.

Path parameters
idreq
stringThe device ID.
commandIdreq
stringThe command ID to cancel.
Response
{ "status": "CANCELLED" }
cURL
curl -X PATCH https://api.themigrator.app/v1/devices/dev_01HXKP9A/commands/cmd_01HY4PQR/cancel \
  -H "Authorization: Bearer $API_KEY"