Docs API

Running commands and jobs

Execute WP-CLI and shell code across environments, choose between synchronous and queued execution, then poll, stream or cancel the resulting job.

CaptainCore does not touch customer servers from WordPress. It hands work to the CaptainCore CLI, which connects over SSH and reports back. Three routes start that work: POST /run/code for freeform code, POST /sites/cli for named built-in commands, and POST /sites/bulk-tools for one tool across many environments.

All three behave the same way with respect to timing, and all three are permission checked per target. Targets you cannot reach are skipped silently. If nothing remains, you get 403.

Quick commands, synchronous

If your request has no X-WP-Nonce header, which is the normal case for curl plus an application password, the command runs inline and you get the output back. The ceiling is five minutes.

curl -X POST -u user:app-password \
  -H "Content-Type: application/json" \
  -d '{
    "code": "wp option get home",
    "environments": [{"site_id": 135, "environment": "production"}]
  }' \
  https://your-manager.example.com/wp-json/captaincore/v1/run/code
{"status": "completed", "response": "https://example.com\n"}

Long-running commands, queued

Add "async": true for anything that might exceed five minutes: backups, migrations, bulk updates. The call returns immediately with a token.

curl -X POST -u user:app-password \
  -H "Content-Type: application/json" \
  -d '{
    "code": "wp plugin update --all",
    "environments": [{"site_id": 135, "environment": "production"}],
    "async": true
  }' \
  https://your-manager.example.com/wp-json/captaincore/v1/run/code
{"status": "queued", "token": "nwaBFBISZEsT"}

async works on /run/code, /sites/cli and /sites/bulk-tools. When the request carries a nonce, meaning it came from the dashboard, these routes always return a token regardless of async.

POST /run/code parameters

Field Type Required Description
code string Yes The script to run. Empty gives 400 missing_code.
environments array Yes Targets, formats below
async boolean No API requests only, queue instead of waiting

Three target formats are accepted, and you can mix them in one array.

Integer environment ids:

{ "code": "wp option get home", "environments": [3365, 3358] }

Objects carrying environment_id (the misspelling enviroment_id is also accepted, for backward compatibility):

{ "code": "wp option get home", "environments": [{"environment_id": 3365}] }

Objects carrying site_id plus an environment name, case insensitive:

{ "code": "wp option get home", "environments": [{"site_id": 135, "environment": "production"}] }

If no target survives the permission check, the response is 403 invalid_targets.

POST /sites/cli named commands

Use this when you want one of CaptainCore’s own operations rather than arbitrary code.

Field Type Required Description
post_id integer or array Yes Site id, or ids for a bulk run
command string Yes One of the named commands
environment string No Production, Staging or Both, capitalized. Only Staging appends -staging. Empty means production.
value mixed No Command specific
async boolean No Queue instead of waiting
background boolean No Force background dispatch
commit / hash string No Quicksave hash
version string No Rollback version
addon_type string No plugin or theme, for rollback
filters array No Snapshot filters: database, themes, plugins, uploads
arguments object No For manage: { "value": "command", "input": "wp ..." }

An unknown command returns 400 with Unknown command.

Frequently used commands:

Command What it does
sync-data Refresh plugins, themes, users and usage
update-wp Apply core, plugin and theme updates
backup Full backup
quick_backup Generate a quicksave
snapshot Build a downloadable snapshot, value is the notify email
launch Launch the site onto a domain, value is the domain
migrate Overwrite the site from a backup zip URL
copy Copy this site onto another CaptainCore site, value is the destination site id
production-to-staging / staging-to-production Environment deploys
reset-permissions Reset filesystem permissions
activate / deactivate Leave or enter maintenance mode
recipe Run a saved recipe, value is the recipe id
rollback / quicksave_rollback / quicksave_file_restore Roll back a component, a whole quicksave, or one file
remove Destructive CLI site delete
curl -X POST -u user:app-password \
  -H "Content-Type: application/json" \
  -d '{"post_id":135,"command":"reset-permissions","environment":"Production"}' \
  https://your-manager.example.com/wp-json/captaincore/v1/sites/cli

Some foreground commands return the raw CLI output as a string rather than the {status, response} wrapper, so handle both.

Jobs

Job tokens are stored against the user who created them, in captaincore_job_tokens. The token in the path matches [a-zA-Z0-9]+, no hyphens.

Poll a job

GET /my-jobs/{token}

The lookup is by token and current user id, so an unknown token or someone else’s token returns 404.

curl -u user:app-password \
  https://your-manager.example.com/wp-json/captaincore/v1/my-jobs/nwaBFBISZEsT

While running:

{"status": "started", "token": "nwaBFBISZEsT"}

If the CLI reports progress, it is passed through untouched:

{"status": "started", "token": "nwaBFBISZEsT", "progress": {"phase": "copy", "percent": 40}}

When finished:

{"status": "completed", "response": "...command output...", "token": "nwaBFBISZEsT"}

Stream a job

GET /my-jobs/{token}/stream

Same ownership check, then the CLI output is proxied as Server-Sent Events with Content-Type: text/event-stream.

curl -N -u user:app-password \
  https://your-manager.example.com/wp-json/captaincore/v1/my-jobs/nwaBFBISZEsT/stream

Browser EventSource cannot set an Authorization header, so the dashboard uses the login cookie plus ?_wpnonce= on this route instead.

Cancel a job

DELETE /my-jobs/{token}
curl -X DELETE -u user:app-password \
  https://your-manager.example.com/wp-json/captaincore/v1/my-jobs/nwaBFBISZEsT
{"status": "cancelled"}

Administrator job views

Administrators get a wider view of what the CLI server is doing:

Method Path Description
GET /jobs/{id} Any job by id, not just your own
GET /running/ Currently running commands (any logged-in user)
GET /progress/ Progress feed
GET /progress/{pid} Progress for one process
DELETE /progress/{pid} Kill a process
POST /listen-processes Subscribe to the process stream

Scheduled scripts

To run code later rather than now, schedule it. Scripts are stored in captaincore_scripts against an environment.

Method Path Description
POST /scripts/schedule Schedule code on one environment
POST /scripts/{script_id} Update a scheduled script
DELETE /scripts/{script_id} Cancel it
curl -X POST -u user:app-password \
  -H "Content-Type: application/json" \
  -d '{
    "environment_id": 3365,
    "code": "wp plugin update --all",
    "run_at": {"date": "2026-09-10", "time": "02:00", "timezone": "America/New_York"}
  }' \
  https://your-manager.example.com/wp-json/captaincore/v1/scripts/schedule

Recipes are the reusable equivalent: named scripts stored in captaincore_recipes and run with POST /sites/cli using command: recipe. See Security and operations.