Liftpad / Developers / Developer docs / Quickstart: deploy with curl

Quickstart: deploy with curl

Six calls from an empty account to a live site. You need curl 7.76 or later, jq and a deploy token.

The whole flow

#!/usr/bin/env bash
# Save as quickstart.sh, then run: bash quickstart.sh
# set -e and --fail-with-body stop the script at the first call that fails
set -euo pipefail
LIFTPAD_TOKEN=lp_your_token
API=https://api.liftpad.app/v1
AUTH="Authorization: Bearer $LIFTPAD_TOKEN"
# Site names are shared by everyone on Liftpad: keep this random one or pick your own
SITE=my-site-$RANDOM

# 1. Create the site
curl -sS --fail-with-body -X POST "$API/sites" -H "$AUTH" -H "content-type: application/json" \
  -d "{\"name\":\"$SITE\"}"

# 2. A page, and the SHA-256 of its bytes (macOS: shasum -a 256)
mkdir -p public
printf '<!doctype html><html lang="en"><title>Hello</title><h1>Hello</h1></html>' > public/index.html
HASH=$(sha256sum public/index.html | cut -d' ' -f1)

# 3. Start a deploy with every path and its digest
DEPLOY=$(curl -sS --fail-with-body -X POST "$API/sites/$SITE/deploys" -H "$AUTH" -H "content-type: application/json" \
  -d "{\"files\":{\"/index.html\":\"$HASH\"},\"title\":\"First deploy\"}" | jq -r .id)

# 4. Upload only the files listed in "required" (here, the one page)
curl -sS --fail-with-body -X PUT "$API/deploys/$DEPLOY/blobs/$HASH" -H "$AUTH" \
  -H "content-type: application/octet-stream" --data-binary @public/index.html

# 5. Finish: launch checks run and the preview address works
curl -sS --fail-with-body -X POST "$API/deploys/$DEPLOY/finalize" -H "$AUTH"

# 6. Publish (publishing an older deploy id is a rollback)
curl -sS --fail-with-body -X POST "$API/sites/$SITE/publish" -H "$AUTH" -H "content-type: application/json" \
  -d "{\"deployId\":\"$DEPLOY\"}"
echo
echo "Live in about 5 seconds: https://$SITE.liftpad.ca"

What each step does

  1. createSite: the name is 3 to 40 characters (a-z, 0-9, single hyphens). If you belong to several teams, add "team": "your-team".
  2. The digest is the lowercase hex SHA-256 of the file's exact bytes.
  3. createDeploy takes every path (starting with /) and its digest. The answer's required lists the digests to upload. Files your team uploaded before are not asked again, so a second deploy of a big site sends only what changed.
  4. uploadDeployFile takes the raw bytes of one required file. Liftpad checks them against the digest and refuses a mismatch.
  5. finalizeDeploy answers with "state": "ready", the preview address and a summary with the launch check score. If a file is missing it answers 409 missing_blobs with the digests to upload: send them and finalize again.
  6. publishDeploy makes it live within about 5 seconds. To roll back, publish an earlier deploy id (listDeploys shows them).

The site is now at https://$SITE.liftpad.ca, the address the script prints. Site names are unique across Liftpad, so step 1 answers 409 exists when the name is taken, and the script stops there: pick another name and run it again. Connect your own domain with addDomain, or in the dashboard.

Next

For real folders, the CLI does all of this, in parallel, with retries.