This tutorial shows you how to use [Claude Code](https://www.deployhq.com/blog/getting-started-with-claude-code-the-ai-coding-assistant-for-your-terminal) to build deployment automation scripts that interact with the [DeployHQ API](https://www.deployhq.com/support/api). By the end, you'll have a working Python script that triggers deployments, polls for status, handles errors, and integrates with GitHub Actions — all generated through AI prompting.

```
flowchart LR
    A[You] -->|Prompt| B[Claude Code]
    B -->|Generates| C[Python Script]
    C -->|API Call| D[DeployHQ]
    D -->|Deploys| E[Your Server]
```

## What You'll Build

- A Python script that triggers [DeployHQ deployments](https://www.deployhq.com/blog/deployment-automation-a-quick-overview) via the API
- Deployment status polling that waits for completion
- Error handling and retry logic
- A GitHub Actions workflow that runs the script automatically on merge

## Prerequisites

- [Claude Code installed](https://www.deployhq.com/blog/getting-started-with-claude-code-the-ai-coding-assistant-for-your-terminal) (`npm install -g @anthropic-ai/claude-code`)
- Familiarity with the slash commands and MCP setup covered in our [Claude Code cheatsheet](https://www.deployhq.com/cheatsheets/claude-code) (optional but useful for adapting the prompts below)
- A [DeployHQ](https://www.deployhq.com) account with a configured project and server
- Python 3.8+ with the `requests` library
- Your [DeployHQ](https://www.deployhq.com) API key (found in **Settings \> Security** )

## Step 1: Get Your DeployHQ API Credentials

The [DeployHQ](https://www.deployhq.com) API uses HTTP Basic Authentication. You'll need three things:

1. **Your email address** — used as the username
2. **Your API key** — a 40-character string from Settings \> Security
3. **Your project and server permalinks** — visible in the URL when viewing your project in [DeployHQ](https://www.deployhq.com) (e.g., `https://youraccount.deployhq.com/projects/my-project/servers/production`)

All API requests go to `https://<your-account>.deployhq.com/` with `Accept: application/json` and `Content-Type: application/json` headers. The full [API reference is available at api.deployhq.com/docs](https://api.deployhq.com/docs).

## Step 2: Prompt Claude Code to Generate the Deployment Script

Open your terminal in your project directory, start Claude Code with `claude`, and give it this prompt:

> Write a Python script that triggers a deployment using the [DeployHQ](https://www.deployhq.com) API. The API uses HTTP Basic Auth with email as username and a 40-character API key as password. The base URL is `https://{account}.deployhq.com`. The script should:
> 
> 1. Read credentials from environment variables (DEPLOYHQ\_ACCOUNT, DEPLOYHQ\_EMAIL, DEPLOYHQ\_API\_KEY, DEPLOYHQ\_PROJECT, DEPLOYHQ\_SERVER)
> 2. Trigger a deployment via POST to `/projects/{project}/deployments`
> 3. Poll the deployment status until it completes or fails
> 4. Exit with code 0 on success, 1 on failure
> 5. Use the `requests` library and include proper error handling

Claude Code will generate something like this:

```
#!/usr/bin/env python3
"""Trigger and monitor a DeployHQ deployment via the API."""

import os
import sys
import time
import requests
from requests.auth import HTTPBasicAuth

# Configuration from environment
ACCOUNT = os.environ.get("DEPLOYHQ_ACCOUNT")
EMAIL = os.environ.get("DEPLOYHQ_EMAIL")
API_KEY = os.environ.get("DEPLOYHQ_API_KEY")
PROJECT = os.environ.get("DEPLOYHQ_PROJECT")
SERVER = os.environ.get("DEPLOYHQ_SERVER")

REQUIRED_VARS = {
    "DEPLOYHQ_ACCOUNT": ACCOUNT,
    "DEPLOYHQ_EMAIL": EMAIL,
    "DEPLOYHQ_API_KEY": API_KEY,
    "DEPLOYHQ_PROJECT": PROJECT,
    "DEPLOYHQ_SERVER": SERVER,
}

missing = [k for k, v in REQUIRED_VARS.items() if not v]
if missing:
    print(f"Missing environment variables: {', '.join(missing)}")
    sys.exit(1)

BASE_URL = f"https://{ACCOUNT}.deployhq.com"
AUTH = HTTPBasicAuth(EMAIL, API_KEY)
HEADERS = {
    "Accept": "application/json",
    "Content-Type": "application/json",
}

def trigger_deployment():
    """Trigger a new deployment for the configured project and server."""
    url = f"{BASE_URL}/projects/{PROJECT}/deployments"
    payload = {
        "deployment": {
            "parent_identifier": "HEAD",
            "server_identifier": SERVER,
        }
    }

    print(f"Triggering deployment: {PROJECT} -> {SERVER}")
    response = requests.post(url, json=payload, auth=AUTH, headers=HEADERS, timeout=30)
    response.raise_for_status()

    data = response.json()
    deploy_id = data.get("identifier") or data.get("id")
    print(f"Deployment triggered: {deploy_id}")
    return deploy_id

def poll_status(deploy_id, interval=10, max_attempts=60):
    """Poll deployment status until completion or failure."""
    url = f"{BASE_URL}/projects/{PROJECT}/deployments/{deploy_id}"

    for attempt in range(1, max_attempts + 1):
        response = requests.get(url, auth=AUTH, headers=HEADERS, timeout=30)
        response.raise_for_status()

        data = response.json()
        status = data.get("status", "unknown")

        print(f" [{attempt}/{max_attempts}] Status: {status}")

        if status == "completed":
            print("Deployment completed successfully.")
            return True
        elif status in ("failed", "cancelled"):
            print(f"Deployment {status}.")
            return False

        time.sleep(interval)

    print("Timed out waiting for deployment to complete.")
    return False

def main():
    try:
        deploy_id = trigger_deployment()
        success = poll_status(deploy_id)
        sys.exit(0 if success else 1)
    except requests.exceptions.HTTPError as e:
        print(f"API error: {e.response.status_code} - {e.response.text}")
        sys.exit(1)
    except requests.exceptions.ConnectionError:
        print(f"Connection failed. Check that '{ACCOUNT}' is your correct DeployHQ account name.")
        sys.exit(1)
    except requests.exceptions.Timeout:
        print("Request timed out. The DeployHQ API may be experiencing issues.")
        sys.exit(1)

if __name__ == " __main__":
    main()
```

Save this as `deploy.py` in your project.

## Step 3: Test the Script Locally

Install the dependency and set your credentials:

```
pip install requests

export DEPLOYHQ_ACCOUNT="your-account-name"
export DEPLOYHQ_EMAIL="you@example.com"
export DEPLOYHQ_API_KEY="your-40-character-api-key"
export DEPLOYHQ_PROJECT="my-project"
export DEPLOYHQ_SERVER="production"
```

Run it:

```
python deploy.py
```

You should see output like:

```
Triggering deployment: my-project -> production
Deployment triggered: abc123
  [1/60] Status: running
  [2/60] Status: running
  [3/60] Status: completed
Deployment completed successfully.
```

## Step 4: Integrate with GitHub Actions

The real power comes when you connect this to your CI/CD pipeline. Ask Claude Code:

> Create a [GitHub Actions](https://www.deployhq.com/compare/deployhq-vs-github-actions) workflow that runs deploy.py when code is pushed to the main branch. Use repository secrets for the [DeployHQ](https://www.deployhq.com) credentials.

```
# .github/workflows/deploy.yml
name: Deploy via DeployHQ

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"

      - run: pip install requests

      - name: Trigger deployment
        env:
          DEPLOYHQ_ACCOUNT: ${{ secrets.DEPLOYHQ_ACCOUNT }}
          DEPLOYHQ_EMAIL: ${{ secrets.DEPLOYHQ_EMAIL }}
          DEPLOYHQ_API_KEY: ${{ secrets.DEPLOYHQ_API_KEY }}
          DEPLOYHQ_PROJECT: ${{ secrets.DEPLOYHQ_PROJECT }}
          DEPLOYHQ_SERVER: ${{ secrets.DEPLOYHQ_SERVER }}
        run: python deploy.py
```

Add your credentials as [repository secrets](https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions) in GitHub Settings \> Secrets and variables \> Actions. Never commit API keys to your repository.

```
flowchart TD
    A[Push to main] --> B[GitHub Actions]
    B --> C[Run deploy.py]
    C --> D[DeployHQ API]
    D --> E{Status?}
    E -->|completed| F[Success]
    E -->|failed| G[Alert team]
    E -->|running| H[Poll again]
    H --> D
```

## Step 5: Add a Rollback Script

Deployments can fail. Ask Claude Code to generate a rollback companion:

> Write a Python function that triggers a rollback to the previous deployment using the [DeployHQ](https://www.deployhq.com) API. Use the same authentication pattern as deploy.py.

```
def rollback_deployment():
    """Trigger a rollback to the previous successful deployment."""
    url = f"{BASE_URL}/projects/{PROJECT}/deployments"
    payload = {
        "deployment": {
            "parent_identifier": "HEAD~1",
            "server_identifier": SERVER,
        }
    }

    print(f"Rolling back: {PROJECT} -> {SERVER}")
    response = requests.post(url, json=payload, auth=AUTH, headers=HEADERS, timeout=30)
    response.raise_for_status()

    data = response.json()
    deploy_id = data.get("identifier") or data.get("id")
    print(f"Rollback deployment triggered: {deploy_id}")
    return deploy_id
```

You can add this to the same `deploy.py` file and call it with a `--rollback` flag, or keep it as a separate `rollback.py` script.

## Troubleshooting Common Issues

**401 Unauthorized** Your email or API key is wrong. Double-check both in [DeployHQ](https://www.deployhq.com) Settings \> Security. The API key is not the same as your account password.

**404 Not Found** The project or server permalink is incorrect. Check the URL in your browser when viewing the project — the permalink is the slug in the URL, not the display name.

**422 Validation Error** The deployment payload is invalid. Common causes: the server identifier doesn't match, or there are no new commits to deploy. The response body contains details keyed by attribute name.

**Connection Error** The account name is wrong. The API URL is `https://<account>.deployhq.com`, where `<account>` is your [DeployHQ](https://www.deployhq.com) subdomain.

**Deployment Stuck in Running** Increase the `max_attempts` parameter in `poll_status()`. Large deployments with build steps can take several minutes. The default 60 attempts at 10-second intervals gives a 10-minute window.

## What Else Can You Automate?

The [DeployHQ API](https://www.deployhq.com/blog/using-deployhq-s-api-automating-your-deployment-workflows-with-scripts-and-webhooks) exposes many more endpoints. Here are some prompts you can give Claude Code:

- _Write a script that lists all my [DeployHQ](https://www.deployhq.com) projects and their last deployment status_
- _Create a Slack notification that fires when a deployment completes or fails_
- _Build a script that deploys to staging first, runs smoke tests, then deploys to production_
- _Wire DeployHQ's [deployment verification checks](https://www.deployhq.com/features/deployment-checks) into the polling loop so the script fails fast when a pre-build or post-deploy probe fails_
- _Write a cron job that checks for failed deployments in the last 24 hours and sends an email alert_

Each of these is a single Claude Code prompt away from a working script. The pattern is always the same: describe what you want, let Claude Code generate the script, test it, then wire it into your [CI/CD pipeline](https://www.deployhq.com/blog/building-a-ci-cd-pipeline-from-scratch-with-deployhq-a-step-by-step-guide).

* * *

Ready to automate your deployments? [Sign up for DeployHQ](https://www.deployhq.com/signup) and connect your first project in minutes. For questions, reach out to our support team at [support@deployhq.com](mailto:support@deployhq.com) or find us on [Twitter](https://x.com/deployhq).

