Sycord Deployer API

v0.9.5 · integration.json · spec.json · All responses are JSON

Your Sycord backend server calls Syte over HTTPS. Store SYTE_API_KEY in env — never in the browser.

Your database columns

syte_uuidrequired From project_connectresponse.uuid
syte_domainFrom response.project.domain e.g. myapp.sycord.site
syte_urlFrom response.project.url — show this link to users when live
deploy_statusMirror createddeployingrunning
preview_urlOptional cache from preview_start / preview_status
Step 1 — User creates project

POST /sycord/api/project_connect · Content-Type: application/json

You send

{ "name": "myapp", "stack": "nextjs" }

Syte returns JSON

{ "ok": true, "uuid": "myapp-a1b2c3", "project": { "domain": "myapp.sycord.site", "url": "https://myapp.sycord.site", "status": "created" } }

Your backend does

  • INSERT row with syte_uuid = response.uuid
  • Save syte_domain, syte_url from response.project
  • Return your internal project id + syte_url to your frontend
Step 2 — Upload files (optional)

POST /sycord/api/upload · Content-Type: multipart/form-data

You send

uuid=myapp-a1b2c3
path=app/app/page.tsx
file=<binary>

Syte returns JSON

{ "ok": true, "uuid": "myapp-a1b2c3", "bytes": 2048, "message": "Uploaded…" }

Your backend does

  • Load syte_uuid from your DB for this project
  • Forward file from your user or generate code server-side
  • Skip this step if the scaffold from step 1 is enough
Step 3 — Start dev preview (optional, fast)

POST /sycord/api/preview_start · Content-Type: application/json

You send

{ "uuid": "myapp-a1b2c3" }

Syte returns JSON

{ "ok": true, "preview_url": "https://previewk-myapp.sycord.site", "preview_ready": true, "preview_running": true }

Your backend does

  • Show preview_url to user in an iframe on sycord.com or any site — embed allowed by default
  • If preview_ready === false, poll step 4 every 1–2s
  • Stop with POST /sycord/api/preview_stop when done
Step 4 — Poll preview (if not ready)

GET /sycord/api/preview_status?uuid=myapp-a1b2c3

Syte returns JSON

{ "ok": true, "preview_ready": true, "preview_url": "https://previewk-myapp.sycord.site", "preview_status": "running" }

Your backend does

  • While preview_ready === false and preview_running === true → keep polling
  • When preview_ready === true → show preview_url
Step 5 — User clicks Deploy

POST /sycord/api/issue_deployment · Content-Type: application/json

You send

{ "uuid": "myapp-a1b2c3" }

Syte returns JSON

{ "ok": true, "status": "deploying", "stream_url": "/api/projects/myapp-a1b2c3/logs/stream?live=1" }

Your backend does

  • Set deploy_status = 'deploying'
  • Start polling step 4 every 3–5 seconds
Step 6 — Poll until live

GET /sycord/api/container_get?uuid=myapp-a1b2c3

You send

Query param uuid only (no body).

Syte returns JSON

{ "ok": true, "running": true, "url": "https://myapp.sycord.site", "status": "running" }

Your backend does

  • While running === false and status === 'deploying' → keep polling
  • When running === true → update syte_url = response.url, deploy_status = 'running'
  • Show response.url to user as the live site link
Step 7 — Custom domain (optional)

POST /sycord/api/domain

You send

{ "uuid": "myapp-a1b2c3", "domain": "shop.example.com" }

Syte returns JSON

{ "ok": true, "project": { "domain": "shop.example.com", "url": "https://shop.example.com" } }

Your backend does

  • Update syte_domain and syte_url from response.project

Full backend example (Node.js)

const SYTE = process.env.SYTE_URL; // https://sycord.site
const KEY = process.env.SYTE_API_KEY;

async function createSycordProject(name, stack) {
  const res = await fetch(`${SYTE}/sycord/api/project_connect`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', 'X-API-Key': KEY },
    body: JSON.stringify({ name, stack }),
  });
  const data = await res.json();
  if (!res.ok) throw new Error(data.detail?.message || 'connect failed');

  await db.query(
    `INSERT INTO projects (name, stack, syte_uuid, syte_domain, syte_url, deploy_status)
     VALUES ($1,$2,$3,$4,$5,$6)`,
    [name, stack, data.uuid, data.project.domain, data.project.url, data.project.status]
  );
  return data;
}

async function deployProject(syteUuid) {
  await postJson('/sycord/api/issue_deployment', { uuid: syteUuid });
  for (let i = 0; i < 60; i++) {
    await sleep(5000);
    const st = await getJson(`/sycord/api/container_get?uuid=${syteUuid}`);
    if (st.running) return st.url;
  }
  throw new Error('deploy timeout');
}

At a glance

WhenHTTPYou sendYou save / use
Create projectPOST project_connect{"name","stack"}uuid → syte_uuid
Upload filePOST uploadmultipart uuid+path+file
Dev previewPOST preview_start{"uuid"}preview_url
Poll previewGET preview_status?uuid=preview_url when ready
DeployPOST issue_deployment{"uuid"}status=deploying
Poll statusGET container_get?uuid=url when running=true
Custom domainPOST domain{"uuid","domain"}project.url
Read full guideGET integration.jsonMachine-readable steps
Read API specGET spec.jsonAll schemas
Rule: Every call after step 1 uses the uuid you saved from project_connect.
External API for Sycord websites and connected projects. project_connect creates a Syte deployment and returns a uuid your app must store.

Workflow

  1. POST /sycord/api/project_connectsave uuid
  2. POST /sycord/api/upload — push files (optional if using scaffold)
  3. POST /sycord/api/preview_start — fast dev preview (next dev / vite, HMR)
  4. GET /sycord/api/preview_status?uuid= — poll until preview ready
  5. POST /sycord/api/issue_deployment — docker build + deploy
  6. GET /sycord/api/container_get?uuid= — verify running
  7. POST /sycord/api/domain — optional custom hostname

Stacks

stackScaffolded template
nextjsNext.js 14 + Dockerfile standalone (default)
pythonFastAPI + uvicorn
javascriptExpress Node.js
html5Static HTML + nginx

Auto subdomain

On project_connect, Syte assigns https://{slug}.sycord.site (or your GUI zone). DNS wildcard must point to the server.

HEADERX-API-Key: syte_…
API key authentication

All endpoints except GET /sycord/api/spec.json require an API key.

HeaderX-API-Key: syte_xxxxxxxx
AlternativeAuthorization: Bearer syte_xxxxxxxx
Create tokenSyte GUI → Users → Create token, or POST /api/tokens

curl example

curl -X POST https://sycord.site/sycord/api/project_connect \
  -H "X-API-Key: syte_YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "myapp", "stack": "nextjs"}'
Required: Save uuid from project_connect in your database before any other call.

What to save

uuid requiredTop-level response field — Syte project id (e.g. myapp-a1b2c3)
persist.uuidSame value, with save instructions
project.uuidSame value inside the project object
project.domainAssigned hostname — optional to cache
project.urlHTTPS URL when live

Your database example

// After project_connect — store before upload/deploy
const res = await sycordApi.projectConnect({ name: "myapp", stack: "nextjs" });

await db.projects.update({
  syte_uuid: res.uuid,           // REQUIRED — use for all Syte calls
  syte_domain: res.project.domain,
  syte_url: res.project.url,
});

Custom UUID (optional)

Pass uuid in the request body if your system already has a stable id:

{ "name": "myapp", "stack": "nextjs", "uuid": "my-custom-id-001" }

Endpoints that need uuid

  • POST /sycord/api/upload — form field uuid
  • POST /sycord/api/preview_start — JSON {"uuid":"…"}
  • GET /sycord/api/preview_status?uuid=
  • POST /sycord/api/preview_stop — JSON {"uuid":"…"}
  • POST /sycord/api/issue_deployment — JSON {"uuid":"…"}
  • GET /sycord/api/container_get?uuid=
  • POST /sycord/api/domain — JSON {"uuid":"…","domain":"…"}
POST/sycord/api/project_connect
Create project — returns uuid to save

Creates workspace, scaffolds stack, assigns https://{slug}.sycord.site.

Request body

name requiredProject name — subdomain slug derived from this
stacknextjs · python · javascript · html5 (default nextjs)
uuidOptional custom Syte project id
env_varsOptional {"KEY":"value"} object
{
  "name": "testproject",
  "stack": "nextjs",
  "env_vars": {}
}

Response — save uuid

{
  "ok": true,
  "uuid": "testproject-a1b2c3",
  "message": "Empty project created. Scaffolded: app/package.json…",
  "persist": {
    "save_uuid": true,
    "uuid": "testproject-a1b2c3",
    "instruction": "Save uuid in your application database…",
    "endpoints_using_uuid": ["POST /sycord/api/upload", "…"]
  },
  "project": {
    "uuid": "testproject-a1b2c3",
    "name": "testproject",
    "domain": "testproject.sycord.site",
    "url": "https://testproject.sycord.site",
    "stack": "nextjs",
    "status": "created",
    "port": 3010,
    "workspace_path": "/var/syte/workspaces/testproject-a1b2c3",
    "app_path": "/var/syte/workspaces/testproject-a1b2c3/app",
    "created_at": "2026-07-04T18:00:00Z"
  },
  "subdomain_pattern": "{slug}.sycord.site",
  "next_steps": {
    "save_uuid": "testproject-a1b2c3",
    "upload": "POST /sycord/api/upload",
    "preview": "POST /sycord/api/preview_start",
    "deploy": "POST /sycord/api/issue_deployment",
    "container": "GET /sycord/api/container_get?uuid=testproject-a1b2c3"
  }
}
GET/sycord/api/container_get?uuid=
Container status
uuid requiredQuery param — from project_connect
{
  "ok": true,
  "uuid": "testproject-a1b2c3",
  "container_name": "syte-testproject-a1b2c3",
  "exists": true,
  "running": true,
  "state": "running",
  "image": "syte-testproject-a1b2c3",
  "url": "https://testproject.sycord.site",
  "domain": "testproject.sycord.site",
  "host_port": 3010,
  "status": "running"
}
POST/sycord/api/upload
Upload file to workspace

multipart/form-data

uuid requiredSyte project uuid
path requiredRelative path e.g. app/app/page.tsx
file requiredFile binary
curl -X POST https://sycord.site/sycord/api/upload \
  -H "X-API-Key: syte_…" \
  -F "uuid=testproject-a1b2c3" \
  -F "path=app/app/page.tsx" \
  -F "file=@page.tsx"
POST/sycord/api/preview_start
Start dev preview (fast HMR)

Starts next dev or vite in seconds — no Docker build. Requires a dev script in package.json.

{ "uuid": "testproject-a1b2c3" }
{
  "ok": true,
  "uuid": "testproject-a1b2c3",
  "message": "Preview on https://previewk-testproject.sycord.site — ready (HMR live)",
  "preview_url": "https://previewk-testproject.sycord.site",
  "preview_domain": "previewk-testproject.sycord.site",
  "preview_ready": true,
  "preview_running": true,
  "preview_port": 4001,
  "preview_status": "running",
  "preview_stream_url": "/api/projects/testproject-a1b2c3/preview/logs/stream?live=1"
}
GET/sycord/api/preview_status?uuid=
Preview status

Poll every 1–2s after preview_start until preview_ready=true.

{
  "ok": true,
  "uuid": "testproject-a1b2c3",
  "preview_url": "https://previewk-testproject.sycord.site",
  "preview_ready": true,
  "preview_running": true,
  "preview_status": "running"
}
POST/sycord/api/preview_stop
Stop preview
{ "uuid": "testproject-a1b2c3" }
{ "ok": true, "uuid": "testproject-a1b2c3", "message": "Preview stopped", "preview_running": false, "preview_status": "stopped" }
POST/sycord/api/domain
Set production domain
{ "uuid": "testproject-a1b2c3", "domain": "custom.sycord.site" }

Caddy issues TLS once DNS points to the server.

POST/sycord/api/issue_deployment
Build & deploy
{ "uuid": "testproject-a1b2c3" }

Runs in background. Stream logs: GET /api/projects/{uuid}/logs/stream?live=1

{
  "ok": true,
  "uuid": "testproject-a1b2c3",
  "message": "Deploy issued…",
  "stream_url": "/api/projects/testproject-a1b2c3/logs/stream?live=1",
  "status": "deploying"
}

Error format

{ "detail": { "error": "not_found", "message": "Project not found" } }
401 missing_api_keyNo X-API-Key header
401 invalid_api_keyToken revoked or wrong
400 invalid_stackUnknown stack value
400 connect_failedSubdomain taken or validation failed
400 upload_failedBad path or missing project
400 preview_failedNo dev script or preview process exited
404 not_founduuid does not exist