REST API

Everything the console does is available over HTTPS as JSON, so a hosting panel or script can start migrations and follow them. Base URL:

https://whatsmyip.tr/api/v1

Authentication

Create a key under Account → API and send it with every request. The key acts as your account, so keep it on the server side.

curl https://whatsmyip.tr/api/v1/me \
  -H "Authorization: Bearer $IMAP_MIGRATOR_KEY"

The X-API-Key: <key> header works too. Starting, cancelling and retrying need an active plan.

Start a migration

POST/migrations

curl -X POST https://whatsmyip.tr/api/v1/migrations \
  -H "Authorization: Bearer $IMAP_MIGRATOR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "srcHost": "mail.old-host.com",
    "tgtHost": "imap.new-host.com",
    "srcAccounts": "[email protected]\nsecret-1\[email protected]\nsecret-2",
    "tgtAccounts": "[email protected]\nsecret-1\[email protected]\nsecret-2",
    "accountConcurrency": 3,
    "folderConcurrency": 2,
    "skipExisting": true,
    "autoMapSpecial": true,
    "clientName": "Atlas Ofis"
  }'
{ "ok": true, "sessionId": 173, "accounts": 2 }
FieldMeaning
srcHost, tgtHostIMAP servers. srcPort/tgtPort default to 993, srcSsl/tgtSsl to true.
srcAccounts, tgtAccountsOne email per line followed by its password; row order pairs the accounts.
accountConcurrencyAccounts at the same time, 1 to 10 (default 2).
folderConcurrencyFolders per account at the same time, 1 to 5 (default 1).
dryRunCount only, copy nothing.
skipExistingSkip messages whose Message-ID is already on the target.
deltaSyncCopy only mail newer than the last completed run for these accounts.
forceRemigrateIgnore saved progress and copy everything again.
since, beforeReceived-date window, YYYY-MM-DD.
autoMapSpecialPut Sent, Drafts, Trash, Junk and Archive into the target's own folders.
excludedFolders[{"name": "Spam"}]
folderMappings[{"sourceName": "Old", "targetName": "Archive/Old"}]
messagesPerMinuteSpeed limit per lane; 0 means none.
verifyCompare target folder counts before and after (default true).
scheduledAtISO 8601 time to start, e.g. 2026-09-20T02:00:00+03:00.
clientNameShown on the report you can share with a client.

Progress

GET/migrations

Your runs, newest first. Filters: status (running, completed, failed, cancelled), limit up to 100.

GET/migrations/{id}

Live totals plus every account and folder with its status, counts and verification. Poll it every few seconds while status is running.

{
  "id": 173, "status": "running", "mode": "full",
  "totals": { "total": 10282, "migrated": 4211, "skipped": 0, "failed": 0, "processed": 4211 },
  "accounts": [
    { "src": "[email protected]", "tgt": "[email protected]", "status": "running", "total": 3912, "migrated": 1490,
      "folders": [ { "name": "INBOX", "target": null, "status": "running", "total": 2400, "migrated": 1490, "verified": null } ] }
  ]
}

Action log

GET/migrations/{id}/events?after=0

Log lines in order. Pass the returned next_after on the next call to receive only new lines.

{ "data": [ { "id": 9120, "level": "info", "account": "[email protected]", "folder": "INBOX", "message": "\"INBOX\": 2,400 messages", "at": "2026-09-18T08:23:51.412+00:00" } ],
  "next_after": 9120 }

Reports

GET/migrations/{id}/report

One row per folder with counts and verification, as JSON. Also available as /report.csv and /report.pdf.

Cancel and retry

POST/migrations/{id}/cancel

Stops after the message in progress. A scheduled run that has not started is closed at once.

POST/migrations/{id}/retry-failed

Copies again what failed, within 24 hours of the run finishing. Messages that already arrived are not copied twice.

Validate and discover

POST/preflight

Logs in to every account pair and reports per side. Same body as starting a migration.

POST/discover-folders

Folders of the first source account with message counts; accountIndex picks another one.

Webhooks

Add a webhook URL under Account → Notifications to receive a POST when a run finishes:

{ "event": "migration.completed", "session_id": 173, "status": "completed",
  "source": "mail.old-host.com", "target": "imap.new-host.com", "client": "Atlas Ofis",
  "accounts": 2, "migrated": 10282, "skipped": 0, "failed": 0,
  "started_at": "…", "finished_at": "…" }

Events: migration.completed, migration.failed, migration.cancelled.

Errors and limits

StatusMeaning
400Invalid input, with {"error": "…"}.
401Missing or wrong API key.
403An active plan is needed ("code": "NO_SUBSCRIPTION").
404Not found, or not yours.
409 / 410Not possible in the current state, or the saved credentials expired.
429More than 120 requests a minute, or 5 migrations already running.