Skip to content

Duplicate site (async)

POST
/wp-json/wp2/site-duplicator/v1/sites/{blog_id}/duplicate
curl --request POST \
--url https://example.com/wp-json/wp2/site-duplicator/v1/sites/1/duplicate \
--header 'Content-Type: application/json' \
--header 'X-WP-Nonce: <X-WP-Nonce>' \
--data '{ "title": "example", "slug": "example", "description": "example", "status_id": 1, "category_ids": [ 1 ] }'

Enqueues a full duplicate of the given site. title and slug are required. Returns 202 with a job id. This does not create a blank site — use Site Manager POST /sites without source_blog_id for that.

blog_id
required
integer

Network site ID. Optional on a single site.

Media typeapplication/json
object
title
required

Title.

string
slug
required

Slug (site, post, or section).

string
description

Field “description” as returned or accepted by PHP.

string
status_id

Site status ID.

integer
category_ids

Field “category_ids” as returned or accepted by PHP.

Array<integer>
Examplegenerated
{
"title": "example",
"slug": "example",
"description": "example",
"status_id": 1,
"category_ids": [
1
]
}

Job accepted

Media typeapplication/json
object
job_id

Job UUID (PlatformJob::$job_id). Site Manager GET returns 404 job_not_found if the type does not start with site_manager. or the row is missing.

string format: uuid
type

Machine job type. Site Manager: site_manager.create_from_source, site_manager.bulk. Site Duplicator uses its own prefixes of the same PlatformJob.

string
status

Lifecycle status (pending / running / completed / failed; PHP may also return cancelled as terminal).

string
Allowed values: pending running completed failed
phase

Current worker phase (short progress label, e.g. bulk), not an HTTP status.

string
progress

Progress counters (percent / current / total) as the worker stored them in PlatformJob::$progress.

object
percent

Percent complete 0–100, if the worker writes it.

integer
current

How many units have been processed.

integer
total

How many units in total (e.g. number of blog_ids in bulk).

integer
message

Human-readable worker status (not a PIN and not a WP-CLI log).

string
user_id

Who enqueued the job. GET of another user’s job without manage_network — 403 forbidden. The jobs list returns only the current user’s jobs.

integer
network_id

Network where the job was created. Another network — 404 job_not_in_network (message “Job not found.”).

integer
payload

Worker input (for bulk — blog_ids/action/patch/drop_tables; for create_from_source — source_blog_id and new-site fields).

object
result

Result after completed (for bulk — succeeded/failed/total/processed). null until the job finishes successfully.

object
error

Error on failed. PHP stores {code, message} in PlatformJob::$error; null if it did not fail.

string
nullable
created_at

Job created time (GMT, gmdate('c')).

string format: date-time
updated_at

Last progress/status update time.

string format: date-time
completed_at

Time of transition to a terminal status; null while the job is running.

string format: date-time
nullable
Example
{
"status": "pending"
}
Location
string
Retry-After
integer

Not authenticated. WordPress REST: rest_not_logged_in / rest_forbidden. Use cookie + X-WP-Nonce or Application Password.

Media typeapplication/json
object
code

Machine-readable error or event code.

string
message

Message text (log, PIN, or password reset).

string
data

Extra WP_Error or license payload.

object
Examplegenerated
{
"code": "example",
"message": "example",
"data": {}
}

Insufficient capability or invalid REST nonce. WordPress REST: rest_forbidden / rest_cookie_invalid_nonce.

Media typeapplication/json
object
code

Machine-readable error or event code.

string
message

Message text (log, PIN, or password reset).

string
data

Extra WP_Error or license payload.

object
Examplegenerated
{
"code": "example",
"message": "example",
"data": {}
}