# POST /api/v1/migrations

> Hold a migration request for confirmation

- Group: migrations
- Tier: W
- Required scope: write:hosting
- Docs: https://api.inleed.com/reference/migrations/request-migration

## Description

Validates and returns `{status:"confirmation_required", confirmationUrl, …}` with a redacted preview. It creates nothing and emails no one — the human approves in the client area, and only then is the request filed and support notified. Poll `get_pending_action` for the outcome.

## Body

- `control_panel` — object. The source control panel to migrate from. Omit if migrating by FTP only.
  - `type` — string. The source control panel, e.g. cPanel, Plesk, DirectAdmin.
  - `host` — string. The source control-panel hostname or IP.
  - `username` — string. The source control-panel username.
  - `password` — string. The source control-panel password. Stored encrypted; shown back only as has_password.
- `websites` — object. The websites to migrate and how to reach them over FTP.
  - `ftp_server` — string. Source FTP server hostname or IP.
  - `ftp_username` — string. Source FTP username.
  - `ftp_password` — string. Source FTP password. Stored encrypted; shown back only as has_ftp_password.
  - `additional_information` — string. Anything the migration team should know.
  - `websites` — string[]. The website hostnames to migrate, e.g. ["example.com", "shop.example.com"].
- `email_accounts` — any[]. The email accounts to migrate (objects or addresses, as you have them).
- `domains` — string[]. Domain names involved in the migration, e.g. ["example.com"].
- `note` — string. A free-text note for the migration team (max 5000 chars).
- `attempt_key` — string. Idempotency key for this intent. Keep it stable across retries so a timed-out retry cannot buy the same thing twice. Up to 128 characters.

## Request

```bash
curl -X POST "https://mcp.inleed.com/api/v1/migrations" \
  -H "Authorization: Bearer inl_live_…" \
  -H "Content-Type: application/json" \
  -d '{"control_panel":{"type":"A","host":"example.se","username":"inleed42","password":"example.se"},"websites":{"ftp_server":"example.se","ftp_username":"inleed42","ftp_password":"example.se","additional_information":"example.se","websites":["example.se"]},"email_accounts":[],"domains":["example.se"],"note":"Resolved via the owning account.","attempt_key":"example.se"}'
```

## Response · 200

```json
{
  "status": "active",
  "pendingActionId": "example.se",
  "confirmationUrl": "https://mcp.inleed.com/…",
  "expiresAt": "2026-08-30T09:12:44.000Z",
  "preview": []
}
```

## Errors

- **401** No token was presented, or the token is revoked, expired or unknown. — codes: unauthorized, token_expired, token_revoked
- **403** The token lacks a required scope, or this account does not own the resource. — codes: insufficient_scope
- **422** Validation error — codes: validation_failed
- **429** The rate limit for this token is exhausted. See `Retry-After`. — codes: rate_limited
- **500** Something went wrong on our side. The failure is logged against `requestId`. — codes: internal_error

## Related

- GET /api/v1/migrations — https://api.inleed.com/reference/migrations/list-migrations
- GET /api/v1/migrations/{migration} — https://api.inleed.com/reference/migrations/get-migration
- POST /api/v1/migrations/{migration}/actions/cancel — https://api.inleed.com/reference/migrations/cancel-migration

