pfcloud / Developers

Guides

Deploy and roll back

Deploy a site, follow the deployment, roll back, use webhooks and auto deploy, and understand the code scan.

When to use this

You want new code live, or you want the previous version back. Scopes: deployments:write to start, deployments:read to follow.

Deploy

curl -s -X POST $MYFORGE/sites/SITE_ID/deploy \
  -H "Authorization: Bearer $TOKEN" -H "Idempotency-Key: deploy-shop-20261009-1"

The answer is 202 and a deployment:

Field Meaning
id Public id of the deployment.
kind deploy or rollback.
status queued, running, succeeded or failed.
branch, commit, commit_message What is being deployed.
started_by The person (or empty for a push).
started_at, finished_at, duration_seconds Timing.
code_findings Present when the code scan found something.
log Last lines of the output (only in the single-deployment answer, or with ?log=1).

Deploys use releases: the new version is built next to the live one and the current link switches only when it is ready, so there is no downtime. Imported sites can deploy in place.

Follow it

curl -s -H "Authorization: Bearer $TOKEN" $MYFORGE/sites/SITE_ID/deployments/DEPLOYMENT_ID

Poll every 10 seconds until succeeded or failed. GET /sites/{site}/deployments lists the latest 25 (newest first).

Roll back

curl -s -X POST $MYFORGE/sites/SITE_ID/rollback \
  -H "Authorization: Bearer $TOKEN" -H "Idempotency-Key: rollback-shop-20261009-1"

This makes a deployment of kind rollback that switches to the previous release. Follow it like any deployment. Rollback does not undo database changes. Restore a backup for that: Backups and restore.

When a deploy is refused: 409

  • The site is not active, is watch-only, or has no repository yet.
  • A deployment is already queued or running, or the site is being moved.

Automatic deploys

  • GitHub App: sites connected to a GitHub repository deploy when someone pushes to their branch, if auto_deploy is on.
  • Webhook: any site with auto_deploy on has a webhook URL. See Webhooks.
  • Turn it on with PATCH /sites/{site} and {"auto_deploy": true}. The answer shows the webhook secret once.

Health check

Set health_check_path (for example /up) with PATCH /sites/{site}. After a release is built pfcloud requests that path locally. If it fails, pfcloud switches back to the previous release and the deployment fails.

The code scan

Before any build step runs, every deploy is scanned for malicious code: web shells, rm -rf /, reverse shells, miners, and install hooks that download code. If something serious is found:

  • The deployment status is failed and code_findings lists each finding as {severity, rule, location, detail}, where severity is critical or warning and location is file:line.
  • Nothing changes on the live site.
  • The team's owners and admins are emailed.

Suspicious-but-not-proven items are shown as warnings and do not stop the deploy.

What to do: read the findings, look at the commit in Git, and find out who wrote it. If the code is yours and safe, a team member who can manage the site opens the failed deployment in the dashboard (site, Deployments) and approves that exact commit ("I reviewed it, approve this commit"), then deploys again. Approval is a human decision on purpose: an API token cannot approve a commit. The approval is recorded in the audit log. Details: the in-app help guide "Code scan before every deploy".

An AI assistant that sees code_findings should stop and tell a person. It must not try to work around the scan.

Environments and promote

A site can have environments such as staging, each a full site linked to the production site.

curl -s -H "Authorization: Bearer $TOKEN" $MYFORGE/sites/SITE_ID/environments
curl -s -X POST $MYFORGE/sites/SITE_ID/environments \
  -H "Authorization: Bearer $TOKEN" -H "Idempotency-Key: env-staging-1" -H "Content-Type: application/json" \
  -d '{"name":"staging","domain":"staging.example.com","server":"SERVER_ID","branch":"develop","create_database":true,"copy_env":true}'

copy_env starts the .env from production's, without the database, app key, URL and similar values. Environments count as sites on your plan.

To put an environment's last good commit on production:

curl -s -X POST $MYFORGE/sites/PRODUCTION_SITE_ID/environments/ENVIRONMENT_SITE_ID/promote \
  -H "Authorization: Bearer $TOKEN" -H "Idempotency-Key: promote-1"

This needs deployments:write. It answers 202, or 409 when there is nothing to promote. Pull request previews are set with PUT /sites/{site}/previews. All endpoints: Environments.

Deploy from CI

A CI step needs only sites:read, deployments:read, deployments:write, ideally limited to one site and to the CI runner's IP address. Fire the deploy, poll until succeeded, and fail the job on failed. Examples are in OpenAPI and clients. The command line does the same: php artisan myforge:deploy {site} --wait.