---
title: "Move a WordPress site, step by step"
method: POST
path: "/sites/migrate-wordpress"
tags: ["Sites"]
---

# Move a WordPress site, step by step

`POST /sites/migrate-wordpress`

## Request

- Base URL: `https://api.hypamoon.com/api/v1`
- URL: `https://api.hypamoon.com/api/v1/sites/migrate-wordpress`
- Auth: one of:
  - HTTP bearer
  - OAuth 2 (authorization code, authorization URL `https://app.hypamoon.com/oauth/authorize`, token URL `https://api.hypamoon.com/oauth/token`, scopes: `sites:write`)

Moves a WordPress site to Hypamoon server to server, without the user downloading or uploading anything. action plan (the default) shows what can move and what is missing and changes nothing; import publishes pages and posts like import_wordpress (with an application password from the vault also drafts and private pages, kept in a private collection); media copies the media library to Media in rounds (cursor); woocommerce copies products with variations and stock, and customers and orders only with include_personal_data and the user's answer in confirm_text; backup reads a .zip or .tar.gz backup link (uploads and posts, pages and attachments from the database dump; nothing is run); finish advises revoking the passwords and, with confirm, removes them from the vault. Every step except plan needs a domain this project connected or proved. Passwords and keys only come from the vault (request_secret), never from the request.

## Request body

- WordpressMigrateInput
  - `url` string, required: The https address of the WordPress site, like https://www.example.com.
  - `action` 'plan' | 'import' | 'media' | 'woocommerce' | 'backup' | 'finish': plan (default): see what can move and what is missing, changes nothing. import: pages and posts to a site. media: the media library to Media, in rounds. woocommerce: products (and only with an explicit yes, customers and orders). backup: read a backup link from the hosting. finish: advice to revoke the passwords, and with confirm remove them from the vault.
  - `wordpress_secret` string: Optional. The name of the vault secret with the WordPress application password (default wordpress_app_password).
  - `woocommerce_secret` string: Optional. The name of the vault secret with the WooCommerce API key (default woocommerce_api_key).
  - `cursor` string: Only for media, woocommerce and backup: the cursor from the previous answer, to continue where it stopped.
  - `site_id` string, uuid: Only for import: an existing site of this project to put the import in. Without it, a new site is created.
  - `keep_existing` boolean: Only for import with site_id: add or replace only the imported files. Needs if_match_version.
  - `if_match_version` string: With keep_existing: the version of the site from get_site.
  - `name` string: Only for import: a name for the new site.
  - `slug` string: Only for import: the address of a new site.
  - `max_posts` integer: Only for import: read at most this many posts, newest first.
  - `source` 'site' | 'backup': Only for import: site (default) reads the live site; backup uses the pages and posts from the database dump that action backup found. If the site's content API is closed, import uses the backup on its own when there is one.
  - `include_personal_data` boolean: Only for woocommerce: true to also move customers and orders. Only after the user said yes in this conversation; send their answer in confirm_text.
  - `confirm_text` string: The user's own answer, word for word, when they agreed to move personal data or to remove the secrets. Kept in the audit log.
  - `backup_url` string: Only for backup: an https link to a .zip or .tar.gz backup of the site, made at the hosting.
  - `confirm` boolean: Only for finish: true removes the WordPress and WooCommerce secrets of this site from the vault, after the user agreed.

## Response `200`

The result of the step, with next_step (and cursor when there is more).

## Other responses

- `201`: import: the new site, with import, data and migration.
- `202`: import with four-eyes approval on: the imported site waits for another owner or builder.
- `400`: Bad Request: invalid_json.
- `401`: Unauthorized: unauthorized, missing_api_key, invalid_api_key, api_key_revoked, project_deleted.
- `402`: Payment Required: plan_limit_reached.
- `403`: Forbidden: project_not_enabled, key_mode_mismatch, missing_scope, verification_required, forbidden, site_offline.
- `404`: Not Found: not_found.
- `409`: Conflict: conflict, version_conflict, plan_limit_reached, slug_taken.
- `412`: Precondition Failed: version_conflict.
- `422`: Unprocessable Content: validation_failed, site_limit_reached, slug_reserved, site_too_large, site_blocked.
- `429`: Too Many Requests: rate_limited, deploy_limit_reached.
- `500`: Internal Server Error: internal_error.
- `503`: Service Unavailable: service_unavailable.

---

[API](https://skmtc.dev/hypamoon/apis/hypamoon-api.md) · [All operations](https://skmtc.dev/hypamoon/apis/hypamoon-api/llms.txt) · [OpenAPI document](https://skmtc.dev/hypamoon/apis/hypamoon-api/revisions/9f0b90004c06?raw)
