Move a portfolio in understandable steps
Import, dry-run, approve the exact plan, then run it in batches you can pause, retry and roll back.
Bulk work is built so that nothing changes until a person has seen and approved the exact plan. You need a connection with portfolios:read, portfolios:write, portfolios:execute and approvals:request, plus the casa scopes for the actions you plan.
Import the inventory
POST /workspaces/{id}/portfolios takes a CSV with the header item_key,domain,source_url,world_handle,template_id,content_language or the same fields as items[], up to 1000 rows, with preserve_existing_mx: true. Each row is checked on its own: domains are normalized, duplicates and unsafe URLs are blocked, and text found at a source is stored as untrusted data. Nothing else happens yet.
Prepare and read a dry-run plan
POST /workspaces/{id}/bulk-plans takes the actions you want (create_draft, apply_import, set_dna, publish and the domain steps), budget caps and rollout_batches such as [5, 95]: a canary of five, then the rest. The answer is an immutable manifest and its plan_hash. Read it with GET /bulk-plans/{plan_id}: every step per item, what it would change and how it can be rolled back. DNS steps only touch website records and keep mail records as they are. Plans expire after 24 hours.
Ask the owner to approve
POST /workspaces/{id}/approvals binds the exact plan_hash, the caps and an expiry, and returns an approval_url. Only an owner can decide it, in the browser, after signing in again, by confirming the hash they were shown. A changed plan can never reuse an approval, and a token can never approve.
Run, watch and steer
POST /bulk-plans/{plan_id}/executewith theplan_hashandapproval_idstarts the one run that approval allows. The canary batch runs first;continuestarts the rest.- Watch
GET /bulk-runs/{run_id}or thejob.updatedandjob.item.updatedwebhooks. pause,resume,cancelandretry(finished steps are not repeated) steer the run.rollbackundoes what the run wrote while it is still unchanged.
Registrations, sent messages and elapsed DNS propagation are not reversible and are never reported as rolled back. Revoking the token stops new work at the next step.
What is live today
Import, validation, dry-run plans and approvals work everywhere. Execution runs end to end against simulated domain, DNS and certificate providers in development and test environments, and stays switched off in production until real provider connections are in place. GET /capabilities reports this as bulk.execute.