hosting

POST /v1/sites/{siteId}/migrations/managed-request

Ask our team to migrate this site for you — free, no limit.

All hosting endpoints

All developer docs →

Authentication

Send an API key as a bearer token. The key must carry the hosting.import.manage permission; a key without it is refused with 403, not 404.

This endpoint takes no organisation id. Your key already identifies the organisation it belongs to, and the response is scoped to it.

Try it

Replace anything in angle brackets with your own values, and the key placeholder with a key from your dashboard.

curl -X POST https://api.zinndigital.com/v1/sites/{siteId}/migrations/managed-request \
  -H "Authorization: Bearer zdk_live_…" \
  -H "Content-Type: application/json" \
  -d '{  }'

Signed in? The API console in your dashboard fills in your real organisation id and your own key, and runs the request against the live API so you can see the actual response. Open this endpoint in the API console

Details

Books a free manual migration: our staff move the site for the customer. Owner ruling 2026-10-14 — migrations are free for every customer with no limits, and self-service (createSiteMigration, the zinn-migrate plugin archive import, cPanel, Plesk, DirectAdmin, FTP/SFTP and SSH sources) is the main, fastest route; this is the route when the customer would rather we did it, or a source cannot be automated. It records an ExtraPurchase of the managed_migration service at a price of 0 (waived for every organization, whatever the catalogue row says), not a migration job: the fulfilment workflow raises it to the staff Extras queue, staff are alerted by e-mail and Telegram, and the 72-hour SLA clock starts. Returns the purchase, so the client can show its status and SLA due time. There is no per-site or per-account limit — a second request is a second job. An environment whose catalogue has never been seeded answers 503 rather than 404, because the service exists and is advertised. The staff note travels on the purchase. ⛔ Send no credentials here — the body has nowhere to put them, and staff collect them out of band from a human they can verify. Requires hosting.import.manage, the same authority as a self-service migration: nothing is charged.

Parameters

NameTypeRequiredWhat it is
siteId (path)UuidYesSite ID (UUIDv7).
Idempotency-Key (header)stringNoClient-generated key that makes an unsafe request replay-safe: the server stores the first response and returns it verbatim for repeats.

Request body

NameTypeRequiredWhat it is
source_hoststringNoWhere the site is hosted today, so the fulfilment queue is actionable without a round trip. A hostname, never a login. Optional.
notestringNoAnything else staff should know before they start.
currencystringNoThe currency the customer was quoted in. Validated and refused if no gateway can charge it — this is a charge, and silently substituting the base currency would bill a different…

Response

NameTypeRequiredWhat it is
idUuidYesUUIDv7 identifier — sortable by creation time (docs/02 §8).
org_idUuidYesUUIDv7 identifier — sortable by creation time (docs/02 §8).
extra_idUuidYesUUIDv7 identifier — sortable by creation time (docs/02 §8).
site_idobjectNo—
domain_idobjectNo—
order_idobjectNoThe order this purchase was charged on — or, while awaiting_payment (Q225), is waiting to be paid on: settle it with payOrder. null for a staff comp or a purchase paid from…
statusExtraPurchaseStatusYesAn extra purchase's lifecycle state. awaiting_payment (Q225): placed by a one-click buy with nothing on file to charge, waiting for the customer to pay its order on-session —…
categorystringYes—
fulfilment_typeExtraFulfilmentTypeYesHow an extra is delivered.
intervalExtraIntervalYesOne-off charge or a recurring subscription. annual is a PURCHASE term only — an SEO tool bought twelve months at a time at V1's yearly saving (D19, 2026-09-25). No catalogue row…
priceMoneyAmountYesA money value — integer minor units + an ISO 4217 code (CLAUDE.md §2.8).
recurrencestring<none, active, ended>YesWhether the recurrence behind this purchase is still live. none = it never recurred (a one-off); active = a scheduled charge exists; ended = it recurred and no longer does.…
next_renewal_onobjectNoThe next charge date, or null. Also null for a live charge that has no date scheduled yet, so read recurrence — not this field — to decide whether a purchase renews at all.
renews_asnull | objectNoQ321 — the smaller tier of the same SEO tool chosen for the next renewal (scheduleExtraTierSwitch), or null when the purchase renews as itself.
arrearsnull | ExtraPurchaseArrearsNos1014 R40 GAP-5/6/7 (docs/747 §2b, V1 parity). null, or this add-on's unpaid renewal: grace — it keeps working until freezes_on (3 days after the renewal fell due); frozen…
sla_due_atobjectNo—
completed_atobjectNo—
failure_reasonstringNo—
created_atstringYes—
updated_atstringYes—

Errors this endpoint can return

401 · 403 · 404 · 422 · 429 · 503