Automate Deployments with Claude Code and the DeployHQ API

AI, Devops & Infrastructure, Python, and Tutorials

Automate Deployments with Claude Code and the DeployHQ API

This tutorial shows you how to use Claude Code to build deployment automation scripts that interact with the DeployHQ 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 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 (npm install -g @anthropic-ai/claude-code)
  • A DeployHQ account with a configured project and server
  • Python 3.8+ with the requests library
  • Your DeployHQ API key (found in Settings > Security)

Step 1: Get Your DeployHQ API Credentials

The DeployHQ 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 (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.

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 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 workflow that runs deploy.py when code is pushed to the main branch. Use repository secrets for the DeployHQ 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 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 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 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 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 exposes many more endpoints. Here are some prompts you can give Claude Code:

  • Write a script that lists all my DeployHQ 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
  • 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.


Ready to automate your deployments? Sign up for DeployHQ and connect your first project in minutes. For questions, reach out to our support team at support@deployhq.com or find us on Twitter.