🤖 Deploy Code lên Zeni Cloud — 1 API Call

Hướng dẫn cho AI Agents (Claude Sessions, ChatGPT, Cursor, Replit Agents). Một endpoint POST /deploy/quick để deploy bất kỳ app nào lên production trong 60-90 giây.

✅ Production-ready endpoint: POST https://zenicloud.io/api/v1/deploy/quick?ws=$WORKSPACE
Auth: Authorization: Bearer zeni_pat_xxx (PAT hoặc JWT)

🚀 Bắt đầu — 30 giây

Bước 1: Lấy ZENI_TOKEN

Login dashboard zenicloud.io/app → Tab API Tokens → "+ New Token" → copy token bắt đầu bằng zeni_pat_

Bước 2: Chọn 1 trong 3 cách deploy

🐳 Cách 1: Docker Image (NHANH NHẤT — 30 giây)

Đã có image trên Docker Hub / Artifact Registry / GCR samples? Deploy ngay:

curl -X POST "https://zenicloud.io/api/v1/deploy/quick?ws=$WORKSPACE" \
  -H "Authorization: Bearer $ZENI_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "image": "docker.io/library/nginx:alpine",
    "name": "my-static-site",
    "port": 80
  }'

Response (202):

{
  "deploy_id": "...",
  "method": "docker_image",
  "status": "deploying",
  "project_id": "uuid",
  "poll_url": "https://zenicloud.io/api/v1/projects/{id}?ws=...",
  "estimated_live_in_sec": 30
}

Poll poll_url sau 30s → status=running → có domain URL live.

📦 Cách 2: ZIP base64 (KHÔNG CẦN GITHUB hoặc Docker — 90 giây)

Có code local? Zip + base64 + POST:

# Bash + Python (POSIX)
ZIP_B64=$(zip -qr - ./my-app/ | base64 -w0)
curl -X POST "https://zenicloud.io/api/v1/deploy/quick?ws=$WORKSPACE" \
  -H "Authorization: Bearer $ZENI_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"zip_base64\":\"$ZIP_B64\",\"name\":\"my-app\",\"framework\":\"auto\"}"

Python (cross-platform):

import requests, zipfile, io, base64

buf = io.BytesIO()
with zipfile.ZipFile(buf, 'w', zipfile.ZIP_DEFLATED) as z:
    z.writestr('index.html', '<h1>Hello World</h1>')
    z.writestr('package.json', '{"name":"my-app"}')

r = requests.post(
    'https://zenicloud.io/api/v1/deploy/quick',
    params={'ws': 'your-workspace'},
    headers={'Authorization': 'Bearer zeni_pat_xxx'},
    json={
        'zip_base64': base64.b64encode(buf.getvalue()).decode(),
        'name': 'my-app',
        'framework': 'auto',  # auto-detect from package.json/requirements.txt
        'port': 8080
    }
)
print(r.json())
# → {"deploy_id":"...", "poll_url":"...", "status":"queued"}

Poll poll_url mỗi 10s. Status: queued → extracting → building → deploying → success

🐙 Cách 3: GitHub Public Repo (120 giây)

Repo public trên GitHub? Paste URL → Zeni clone + build + deploy:

curl -X POST "https://zenicloud.io/api/v1/deploy/quick?ws=$WORKSPACE" \
  -H "Authorization: Bearer $ZENI_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "repo_url": "https://github.com/owner/repo",
    "branch": "main",
    "name": "my-app",
    "framework": "auto"
  }'
⚠ Phase 1: Hỗ trợ public repo only. Phase 2 (đang phát triển): GitHub OAuth cho private repo + auto-clone.

🎯 Auto-detect Framework

Zeni Cloud tự nhận diện framework từ files trong ZIP/repo:

Detect fileFrameworkAuto-DockerfileDefault port
next.config.jsNext.jsnode:20-alpine + standalone build3000
vite.config.jsReact/Vitenode:20 build → nginx serve80
vue.config.jsVue.jsnode:20 build → nginx serve80
requirements.txtFastAPI (default Python)python:3.12-slim + uvicorn8080
package.json (no Next/Vite)Express.jsnode:20-alpine + npm start3000
index.html onlyStatic HTMLnginx:alpine + serve80
Dockerfile existsCustomUse repo's Dockerfile as-is(detected)

Override bằng "framework": "nextjs|react|vue|fastapi|express|static"

📊 Poll Deploy Status

curl "$POLL_URL" -H "Authorization: Bearer $ZENI_TOKEN"

# Response:
{
  "deploy_id": "...",
  "status": "building",       # queued|extracting|building|deploying|success|failed
  "name": "my-app",
  "framework": "express",
  "image_url": null,          # populated khi build SUCCESS
  "deploy_url": null,         # populated khi deploy SUCCESS
  "error": null,
  "completed_at": null
}

# Khi success:
{
  "deploy_id": "...",
  "status": "success",
  "image_url": "us-central1-docker.pkg.dev/zeni-cloud-core/zeni-images/zeni-myws-myapp:abc123",
  "deploy_url": "https://my-app-xxx-uc.a.run.app",
  "completed_at": "2026-05-03T..."
}

🛠 Working Examples for AI Agents

Claude Code Session (clone repo + deploy)

// Pseudocode for Claude Code:
1. User: "Deploy my Next.js app at /home/user/my-app to Zeni Cloud"
2. Bash: cd /home/user/my-app && zip -qr /tmp/app.zip ./
3. Python: read /tmp/app.zip, base64 encode
4. curl POST /deploy/quick with zip_base64
5. Loop: poll /deploy/quick/{id} every 10s until status='success'
6. Return deploy_url to user

ChatGPT Code Interpreter

import requests, zipfile, base64
from pathlib import Path

# Upload + deploy in one cell
def deploy_to_zeni(folder_path, ws, token, name=None, framework='auto'):
    buf = io.BytesIO()
    with zipfile.ZipFile(buf, 'w', zipfile.ZIP_DEFLATED) as z:
        for f in Path(folder_path).rglob('*'):
            if f.is_file() and 'node_modules' not in str(f) and '.git' not in str(f):
                z.write(f, f.relative_to(folder_path))

    r = requests.post(f'https://zenicloud.io/api/v1/deploy/quick',
        params={'ws': ws},
        headers={'Authorization': f'Bearer {token}'},
        json={'zip_base64': base64.b64encode(buf.getvalue()).decode(),
              'name': name or folder_path.split('/')[-1], 'framework': framework})
    return r.json()

Cursor Composer / Replit Agent

Same pattern: zip current workspace → POST /deploy/quick → poll → return URL.

💡 Tips for AI Agents

📋 Endpoint Reference

EndpointPurpose
POST /api/v1/deploy/quick?ws=XOne-call deploy (3 input methods)
GET /api/v1/deploy/quick/{id}?ws=XPoll status
POST /api/v1/upload/source?ws=XMultipart ZIP upload (alternative to base64)
GET /api/v1/projects?ws=XList all deployed projects
POST /api/v1/projects?ws=XFull custom deploy (more options)

🤖 Designed for AI agents. Tối giản, idempotent, single-call. Built by Zeni Cloud.