DocsOverviewQuick StartFrameworksDeploymentsDomainsEnv VarsFeature FlagsAI GatewayAPI ReferenceWebhooks

API Reference

REST API for programmatic access to Deploxa resources.

Contents

AuthenticationErrorsPaginationProjectsDeploymentsEnvironment VariablesOrganizationsWebhooksSignature Verification

Authentication

All API requests must include a Personal Access Token in the Authorization header. Tokens can be created at /settings/tokens.

REQUEST HEADER

Authorization: Bearer dpx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

EXAMPLE (curl)

curl -H "Authorization: Bearer dpx_..." \
  https://deploxa.com/api/v1/projects

EXAMPLE (Node.js)

const res = await fetch("https://deploxa.com/api/v1/projects", {
  headers: { Authorization: "Bearer dpx_..." }
});
const { data } = await res.json();

Errors

The API uses standard HTTP status codes. All error responses include an error field.

400Bad RequestInvalid parameters or missing required fields
401UnauthorizedMissing or invalid token
403ForbiddenToken lacks permission for this action
404Not FoundResource doesn't exist or you lack access
429Too Many RequestsRate limit or build slot exhausted
500Server ErrorInternal error — try again

ERROR RESPONSE

{ "error": "Project not found" }

Pagination

List endpoints return a pagination object. Pass cursor as a query param to fetch the next page.

{
  "data": [...],
  "pagination": {
    "hasMore": true,
    "nextCursor": "clm1abc...",
    "limit": 20
  }
}

Projects

GET/api/v1/projects

List all projects the authenticated user has access to.

Query Parameters

orgqueryFilter by organization slug
limitqueryNumber of results (max 100, default 20)
cursorqueryPagination cursor from previous response

Response

{ "data": [{ "id": "...", "name": "my-app", "slug": "my-app", "framework": "NEXTJS", "current_deployment": { "status": "READY" } }], "pagination": { "hasMore": false, "nextCursor": null } }
POST/api/v1/projects

Create a new project.

Request Body (JSON)

namestringProject name
required
orgSlugstringOrganization to create the project under
frameworkstringFramework: NEXTJS | REACTJS | VITE | NODEJS
appTypestringApp type: STATIC | NODEJS
descriptionstringOptional project description

Response

{ "data": { "id": "...", "name": "my-app", "slug": "my-app", "created_at": "2026-01-01T00:00:00Z" } }
GET/api/v1/projects/:id

Get a project by ID.

Response

{ "data": { "id": "...", "name": "my-app", "slug": "my-app", "domains": [...], "current_deployment": { ... } } }
PATCH/api/v1/projects/:id

Update a project's settings.

Request Body (JSON)

namestringNew project name
descriptionstringProject description
build_commandstringBuild command
install_commandstringInstall command
output_dirstringOutput directory
DELETE/api/v1/projects/:id

Delete a project. Only the project owner can delete.

Response

{ "deleted": true }

Deployments

GET/api/v1/projects/:id/deployments

List deployments for a project.

Query Parameters

statusqueryFilter by status: QUEUED | BUILDING | READY | ERROR
limitqueryNumber of results (max 100)
cursorqueryPagination cursor

Response

{ "data": [{ "id": "...", "status": "READY", "branch": "main", "deployment_domain": "my-app.deploxa.com" }] }
POST/api/v1/projects/:id/deployments

Trigger a new deployment for a project.

Request Body (JSON)

branchstringBranch to deploy (defaults to last deployed branch)
commitMessagestringCommit message label for this deployment
commitShastringCommit SHA to associate with this deployment

Response

{ "data": { "id": "...", "status": "QUEUED" } }
GET/api/v1/deployments/:id

Get a single deployment by ID.

Response

{ "data": { "id": "...", "status": "READY", "branch": "main", "buildDurationMs": 45000, "bundleSizeKb": 1024 } }

Environment Variables

GET/api/v1/projects/:id/env-vars

List all environment variable keys for a project. Values are not returned for security.

Response

{ "data": [{ "id": "...", "key": "DATABASE_URL", "targets": ["production"], "sensitive": false }] }
POST/api/v1/projects/:id/env-vars

Create or update an environment variable.

Request Body (JSON)

keystringVariable name (must match [A-Za-z_][A-Za-z0-9_]*)
required
valuestringVariable value (stored encrypted)
required
targetsstring[]Environments: production | preview | development
sensitivebooleanMark as sensitive (masked in UI)

Response

{ "data": { "id": "...", "key": "DATABASE_URL", "targets": ["production"] } }
DELETE/api/v1/projects/:id/env-vars/:key

Delete an environment variable by key.

Response

{ "deleted": true }

Organizations

GET/api/v1/orgs

List all organizations the authenticated user belongs to.

Response

{ "data": [{ "id": "...", "name": "Acme Corp", "slug": "acme", "role": "owner" }] }
GET/api/v1/orgs/:slug

Get a single organization by slug.

Response

{ "data": { "id": "...", "name": "Acme Corp", "slug": "acme", "_count": { "members": 5, "projects": 12 } } }
GET/api/v1/orgs/:slug/members

List all members of an organization.

Response

{ "data": [{ "id": "...", "role": "ADMIN", "user": { "email": "alice@acme.com" } }] }

Webhooks

Configure webhooks in your project's Integrations settings. Deploxa sends HTTP POST requests to your URL for the events you subscribe to.

Available Events

deployment.startedDeployment has been queued/started
deployment.readyDeployment successfully completed
deployment.failedDeployment failed with an error
deployment.rollbackA rollback was performed

Payload Example

POST https://your-server.com/webhook
Content-Type: application/json
X-Deploxa-Signature: sha256=abc123...
X-Deploxa-Event: deployment.ready

{
  "event": "deployment.ready",
  "deployment": {
    "id": "clm1abc...",
    "status": "READY",
    "branch": "main",
    "url": "https://my-app.deploxa.com"
  },
  "project": { "id": "...", "name": "my-app", "slug": "my-app" }
}

Webhook Signature Verification

Every webhook request includes a X-Deploxa-Signature header. Verify it to confirm the request came from Deploxa and was not tampered with.

How it works

  1. Deploxa computes HMAC-SHA256(rawBody, webhookSecret)
  2. The hex digest is sent as X-Deploxa-Signature: sha256=<hex>
  3. You compute the same HMAC and compare using a timing-safe comparison

Node.js

import { createHmac, timingSafeEqual } from "crypto";

function verifySignature(rawBody: string, secret: string, signature: string) {
  const expected = "sha256=" + createHmac("sha256", secret)
    .update(rawBody)
    .digest("hex");
  const a = Buffer.from(expected, "utf8");
  const b = Buffer.from(signature, "utf8");
  return a.length === b.length && timingSafeEqual(a, b);
}

// In your webhook handler:
app.post("/webhook", express.raw({ type: "*/*" }), (req, res) => {
  const sig = req.headers["x-deploxa-signature"] as string;
  if (!verifySignature(req.body.toString(), process.env.WEBHOOK_SECRET!, sig)) {
    return res.status(401).send("Invalid signature");
  }
  const payload = JSON.parse(req.body.toString());
  console.log("Event:", payload.event);
  res.sendStatus(200);
});

Python

import hmac
import hashlib

def verify_signature(raw_body: bytes, secret: str, signature: str) -> bool:
    expected = "sha256=" + hmac.new(
        secret.encode(), raw_body, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature)

# In your Flask/FastAPI handler:
@app.post("/webhook")
async def webhook(request: Request):
    raw = await request.body()
    sig = request.headers.get("x-deploxa-signature", "")
    if not verify_signature(raw, WEBHOOK_SECRET, sig):
        raise HTTPException(status_code=401, detail="Invalid signature")
    payload = json.loads(raw)
    print("Event:", payload["event"])
    return {"ok": True}

Go

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/hex"
    "fmt"
)

func verifySignature(body []byte, secret, signature string) bool {
    mac := hmac.New(sha256.New, []byte(secret))
    mac.Write(body)
    expected := "sha256=" + hex.EncodeToString(mac.Sum(nil))
    return hmac.Equal([]byte(expected), []byte(signature))
}