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 }
| Field | Meaning |
|---|---|
| srcHost, tgtHost | IMAP servers. srcPort/tgtPort default to 993, srcSsl/tgtSsl to true. |
| srcAccounts, tgtAccounts | One email per line followed by its password; row order pairs the accounts. |
| accountConcurrency | Accounts at the same time, 1 to 10 (default 2). |
| folderConcurrency | Folders per account at the same time, 1 to 5 (default 1). |
| dryRun | Count only, copy nothing. |
| skipExisting | Skip messages whose Message-ID is already on the target. |
| deltaSync | Copy only mail newer than the last completed run for these accounts. |
| forceRemigrate | Ignore saved progress and copy everything again. |
| since, before | Received-date window, YYYY-MM-DD. |
| autoMapSpecial | Put Sent, Drafts, Trash, Junk and Archive into the target's own folders. |
| excludedFolders | [{"name": "Spam"}] |
| folderMappings | [{"sourceName": "Old", "targetName": "Archive/Old"}] |
| messagesPerMinute | Speed limit per lane; 0 means none. |
| verify | Compare target folder counts before and after (default true). |
| scheduledAt | ISO 8601 time to start, e.g. 2026-09-20T02:00:00+03:00. |
| clientName | Shown 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
| Status | Meaning |
|---|---|
| 400 | Invalid input, with {"error": "…"}. |
| 401 | Missing or wrong API key. |
| 403 | An active plan is needed ("code": "NO_SUBSCRIPTION"). |
| 404 | Not found, or not yours. |
| 409 / 410 | Not possible in the current state, or the saved credentials expired. |
| 429 | More than 120 requests a minute, or 5 migrations already running. |