Quickstart
Create a test, import, run, poll, and export using only an API key
This guide walks through the most common API flow with a single key: create a visual test, create a script test, import a ZIP, trigger a run, poll until it finishes, and export results.
Prerequisites
Create an API key with scopes tests:read, tests:create, tests:run, and testRuns:read. See Authentication. You also need the UUID of your target project; call projects.list with a projects:read key if you do not have it yet.
export SMOOTHDEPLOY_API_KEY="sd_..."
export PROJECT_ID="3f8a1b2c-1111-2222-3333-444455556666"Every call below is /v1/actions/<name>. GET actions take query parameters; the others take a JSON body.
1. Create a visual test
TEST_ID=$(curl -s -X POST https://api.smoothdeploy.com/v1/actions/tests.create \
-H "x-api-key: $SMOOTHDEPLOY_API_KEY" \
-H "x-project-id: $PROJECT_ID" \
-H "Content-Type: application/json" \
-d '{"testData":{"name":"Home page smoke","status":"active","metadata":{"type":"visual"},"config":{"use":{"browserName":"chromium","baseURL":"https://example.com"}}}}' \
| jq -r .data.id)
echo "Created test $TEST_ID"2. Create a script test
A script test is a Playwright spec file stored as a single script step. Set metadata.type to "script", metadata.lang to "ts" or "js", and put the file contents in action.code. Build the JSON with jq so the file is escaped correctly.
jq -n --rawfile code login.spec.ts '{
testData: {
name: "Login spec",
status: "active",
metadata: { type: "script", lang: "ts" },
steps: [{ id: "6f1c2d3e-0000-4000-8000-000000000001", name: "Script", order: 0,
action: { name: "script", code: $code } }]
}
}' > body.json
SCRIPT_TEST_ID=$(curl -s -X POST https://api.smoothdeploy.com/v1/actions/tests.create \
-H "x-api-key: $SMOOTHDEPLOY_API_KEY" \
-H "x-project-id: $PROJECT_ID" \
-H "Content-Type: application/json" \
--data @body.json \
| jq -r .data.id)
echo "Created script test $SCRIPT_TEST_ID"The spec must contain exactly one top-level test() and may only import packages from the organization allowlist. A spec that breaks either rule returns 400 with the reason in error.
3. Import a ZIP
The ZIP must be a SmoothDeploy export archive: a tests/ directory with one JSON file per test (e.g. tests/Login flow.json). Use tests.export or the console to produce the file. Send the archive base64-encoded in the JSON body.
base64 < smoothdeploy-tests.zip | tr -d '\n' > archive.b64
jq -n --rawfile b archive.b64 '{contentBase64: $b}' \
| curl -s -X POST https://api.smoothdeploy.com/v1/actions/tests.import \
-H "x-api-key: $SMOOTHDEPLOY_API_KEY" \
-H "x-project-id: $PROJECT_ID" \
-H "Content-Type: application/json" \
--data @- \
| jq .data4. Trigger a run
RUN=$(curl -s -X POST https://api.smoothdeploy.com/v1/actions/tests.run-many \
-H "x-api-key: $SMOOTHDEPLOY_API_KEY" \
-H "x-project-id: $PROJECT_ID" \
-H "Content-Type: application/json" \
-d "{\"testIds\":[\"$TEST_ID\"]}")
RUN_ID=$(echo "$RUN" | jq -r .data.runId)
echo "Run started: $RUN_ID"5. Poll until complete
while :; do
STATUS=$(curl -s "https://api.smoothdeploy.com/v1/actions/test-runs.get?runId=$RUN_ID" \
-H "x-api-key: $SMOOTHDEPLOY_API_KEY" \
-H "x-project-id: $PROJECT_ID" \
| jq -r .data.status)
case "$STATUS" in
completed) echo "All tests passed"; exit 0 ;;
failed) echo "Tests failed"; exit 1 ;;
cancelled) echo "Run cancelled"; exit 1 ;;
*) echo "Status: $STATUS - waiting..."; sleep 10 ;;
esac
done6. Export as ZIP
tests.export returns the archive base64-encoded in data.contentBase64.
curl -s -X POST https://api.smoothdeploy.com/v1/actions/tests.export \
-H "x-api-key: $SMOOTHDEPLOY_API_KEY" \
-H "x-project-id: $PROJECT_ID" \
-H "Content-Type: application/json" \
-d "{\"testIds\":[\"$TEST_ID\"]}" \
| jq -r .data.contentBase64 | base64 --decode > my-test.zip