BlueForge Docs

Deployments

Deployments track the build and release lifecycle for hosting projects, supporting both git-triggered builds and pre-built artifact uploads with real-time log streaming.

Endpoint

MethodPathAuthIdempotent
GET
/api/deployments
Beareryes
POST
/api/deployments
Bearerno
POST
/api/deployments/upload
Bearerno
GET
/api/deployments/:id
Beareryes
GET
/api/deployments/:id/stream
Bearerno
GET
/api/deployments/:id/logs
Bearerno
PATCH
/api/deployments/:id
Bearerno

Parameters

NameTypeRequiredDefaultNotes
projectId
query (GET) / body (POST)optional / requiredFilter or assign the deployment to a project
branch
stringyes (POST body)Git branch being deployed; set to
"upload"
for artifact uploads
commitSha
stringyes (POST body)Git commit SHA; set to
"artifact-upload"
for artifact uploads
targetHost
JSONno
{ id?, slug?, sshHost, sshUser }
— overrides build-worker SSH target for fleet routing
id
stringyes (path)Deployment UUID
repo
stringyes (upload form)Repository name; resolves against
projects.name
or
projects.slug
app
stringyes (upload form)Application name for the uploaded artifact
artifact
fileyes (upload form)Pre-built artifact file (
< 100MB
, stored in MinIO)
component
query (logs)noComponent name filter for container logs; must match
^[a-z0-9][a-z0-9-]*$
since
query (logs)no
"10m"
Log look-back window
follow
query (logs)noSet to
"1"
to follow log output
status
stringyes (PATCH body)New deployment status (worker-side transition)

Response

// GET /api/deployments — list deployments
Array<{
  id: string;
  projectId: string;
  status: string;
  branch: string;
  commitSha: string;
  createdAt: string;
  // ... other deployment fields ...
}>

// POST /api/deployments (201) — git-triggered deployment
{
  id: string;
  projectId: string;
  status: string;
  branch: string;
  commitSha: string;
  createdAt: string;
  // ... other deployment fields ...
}

// POST /api/deployments/upload (201) — artifact upload deployment
{
  id: string;
  status: string;
}

// GET /api/deployments/:id — single deployment
{
  id: string;
  projectId: string;
  status: string;
  branch: string;
  commitSha: string;
  resolvedBuildConfig: { repo: string } | null;
  // ... other deployment fields ...
}

// GET /api/deployments/:id/stream — SSE text/event-stream
// event: ping
// data: {}
//
// event: update
// data: { "status": "building", "message": "..." }

// PATCH /api/deployments/:id — updated deployment
{
  id: string;
  status: string;
  // ... updated fields ...
}

// Error envelopes
{ error: "Deployment ${id} not found" }               // 404
{ error: "repo, app, and artifact (file) are required" } // 400
{ error: "Project \"${repo}\" not found" }             // 400

Examples

# List deployments filtered by project
curl -H "Authorization: Bearer $BF_API_KEY" \
  "https://api.blueforge.studio/api/deployments?projectId=prj_xxx"

# Trigger a git-triggered deployment
curl -X POST https://api.blueforge.studio/api/deployments \
  -H "Authorization: Bearer $BF_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"projectId": "prj_xxx", "branch": "main", "commitSha": "abc123"}'

# Upload a pre-built artifact
curl -X POST https://api.blueforge.studio/api/deployments/upload \
  -H "Authorization: Bearer $BF_API_KEY" \
  -F "repo=my-app" \
  -F "app=web" \
  -F "artifact=@./build.tar.gz"

# Stream deployment logs via SSE
curl -N -H "Authorization: Bearer $BF_API_KEY" \
  https://api.blueforge.studio/api/deployments/dep_xxx/stream

# Get deployment container logs
curl -H "Authorization: Bearer $BF_API_KEY" \
  "https://api.blueforge.studio/api/deployments/dep_xxx/logs?component=web&since=30m&follow=1"
import { Client } from "@blueforge/client"

const client = new Client({ apiKey: process.env.BF_API_KEY })

// List deployments
const deployments = await client.get("/api/deployments", { projectId: "prj_xxx" })

// Trigger git-triggered deployment
const deployment = await client.post("/api/deployments", {
  projectId: "prj_xxx",
  branch: "main",
  commitSha: "abc123",
})

// Get deployment status
const status = await client.get(`/api/deployments/${deployment.id}`)

Pitfalls

  • POST /api/deployments/upload
    must be registered BEFORE
    GET /api/deployments/:id
    in the route chain; otherwise Hono matches
    upload
    as a UUID param and returns 404.
  • Artifact uploads must be
    < 100MB
    . Files are staged in MinIO at
    deployments/{id}/artifact.tar.gz
    before the build-worker pulls them.
  • The SSE stream (
    /stream
    ) requires Redis for pub/sub on channel
    deployments:{id}
    . The connection auto-closes when the client aborts; a 30-second ping keeps the connection alive.
  • The
    targetHost
    override is an explicit pre-resolved SSH target. When omitted, the server falls back to the app's synced Hetzner host config, then to the
    DEPLOY_SSH_HOST
    env var.
  • Log streaming (
    /logs
    ) resolves the deployment to its app slug via
    resolvedBuildConfig.repo
    . If the deployment row lacks this field, the route returns 422.
  • The
    PATCH /:id
    route transitions deployment status. Validation is minimal — invalid status values are stored as-is.

See also

Tested against

  • @blueforge/hosting-api: 2.4.1
  • Last verified: 2026-07-15