Skip to content

API Reference

API Reference

pvdifyd REST API v1

Base URL: https://pvdify.win/api/v1

Authentication

All requests require a Bearer token:

Terminal window
curl -H "Authorization: Bearer $PVDIFY_TOKEN" \
https://pvdify.win/api/v1/apps

Tokens are issued via:

  • pvdify login (CLI)
  • Admin UI settings
  • GitHub App installation

Apps

List Apps

GET /apps

Response:

{
"apps": [
{
"name": "myapp",
"environment": "production",
"status": "running",
"image": "ghcr.io/org/app:v1.2.3",
"created_at": "2026-01-01T10:00:00Z"
}
]
}

Get App

GET /apps/{name}

Response:

{
"name": "myapp",
"environment": "production",
"status": "running",
"image": "ghcr.io/org/app:v1.2.3",
"processes": {
"web": { "command": "npm start", "count": 2 },
"worker": { "command": "npm run worker", "count": 1 }
},
"bind_port": 3001,
"domains": ["myapp.com", "www.myapp.com"],
"resources": { "memory": "512M", "cpu": 0.5 },
"healthcheck": { "path": "/health", "interval": "30s" },
"created_at": "2026-01-01T10:00:00Z",
"updated_at": "2026-01-05T10:30:00Z"
}

Create App

POST /apps

Request:

{
"name": "myapp",
"environment": "production"
}

Response: 201 Created

{
"name": "myapp",
"environment": "production",
"status": "pending",
"bind_port": 3001,
"created_at": "2026-01-05T10:30:00Z"
}

Delete App

DELETE /apps/{name}

Response: 204 No Content


Releases

List Releases

GET /apps/{name}/releases

Response:

{
"releases": [
{
"version": 42,
"image": "ghcr.io/org/app:v1.2.3",
"status": "active",
"created_at": "2026-01-05T10:30:00Z",
"created_by": "gh-actions"
},
{
"version": 41,
"image": "ghcr.io/org/app:v1.2.2",
"status": "superseded",
"created_at": "2026-01-04T10:00:00Z",
"created_by": "user@example.com"
}
]
}

Get Release

GET /apps/{name}/releases/{version}

Response:

{
"version": 42,
"image": "ghcr.io/org/app:v1.2.3",
"config_version": "v3",
"status": "active",
"created_at": "2026-01-05T10:30:00Z",
"created_by": "gh-actions",
"deploy_log": "https://pvdify.win/api/v1/apps/myapp/releases/42/log"
}

Create Release (Deploy)

POST /apps/{name}/releases

Request:

{
"image": "ghcr.io/org/app:v1.2.3"
}

Response: 201 Created

{
"version": 43,
"image": "ghcr.io/org/app:v1.2.3",
"status": "deploying",
"created_at": "2026-01-05T11:00:00Z"
}

Rollback

POST /apps/{name}/rollback

Request (optional):

{
"version": 41
}

Response:

{
"version": 44,
"image": "ghcr.io/org/app:v1.2.2",
"status": "deploying",
"rollback_from": 43,
"rollback_to": 41
}

Config

Get Config

GET /apps/{name}/config

Response:

{
"version": "v3",
"vars": {
"NODE_ENV": "production",
"DATABASE_URL": "postgres://...",
"API_KEY": "[REDACTED]"
},
"secrets": ["API_KEY"],
"updated_at": "2026-01-05T10:30:00Z"
}

Set Config

PATCH /apps/{name}/config

Request:

{
"vars": {
"NEW_VAR": "value",
"EXISTING_VAR": "updated"
}
}

Response:

{
"version": "v4",
"changes": ["NEW_VAR", "EXISTING_VAR"],
"updated_at": "2026-01-05T11:00:00Z"
}

Set Secret

POST /apps/{name}/config/secrets

Request:

{
"name": "API_KEY",
"value": "sk_live_..."
}

Response: 201 Created

{
"name": "API_KEY",
"version": "v4",
"updated_at": "2026-01-05T11:00:00Z"
}

Delete Config Var

DELETE /apps/{name}/config/{key}

Response: 204 No Content

Config Versions

GET /apps/{name}/config/versions

Response:

{
"versions": [
{ "version": "v3", "created_at": "2026-01-05T10:30:00Z", "changes": ["API_KEY"] },
{ "version": "v2", "created_at": "2026-01-03T10:00:00Z", "changes": ["DATABASE_URL"] },
{ "version": "v1", "created_at": "2026-01-01T10:00:00Z", "changes": ["NODE_ENV"] }
]
}

Get Config Version

GET /apps/{name}/config/versions/{version}

Response:

{
"version": 3,
"vars": {
"NODE_ENV": "production",
"DATABASE_URL": "postgres://...",
"API_KEY": "[REDACTED]"
},
"created_at": "2026-01-05T10:30:00Z"
}

Domains

List Domains

GET /apps/{name}/domains

Response:

{
"domains": [
{ "name": "myapp.com", "status": "active", "ssl": true },
{ "name": "www.myapp.com", "status": "active", "ssl": true }
]
}

Add Domain

POST /apps/{name}/domains

Request:

{
"name": "api.myapp.com"
}

Response: 201 Created

{
"name": "api.myapp.com",
"status": "provisioning",
"ssl": false
}

Remove Domain

DELETE /apps/{name}/domains/{domain}

Response: 204 No Content

Verify Domain

POST /apps/{name}/domains/{domain}/verify

Initiates domain ownership verification via Cloudflare DNS.

Response: 202 Accepted

{
"domain": "myapp.com",
"status": "verifying",
"verify_token": "token123",
"dns_record": "_pvdify-verify.myapp.com TXT token123"
}

Processes

List Processes

GET /apps/{name}/ps

Response:

{
"processes": [
{ "type": "web", "count": 2, "status": "running" },
{ "type": "worker", "count": 1, "status": "running" }
]
}

Scale Processes

POST /apps/{name}/ps/scale

Request:

{
"web": 3,
"worker": 2
}

Response:

{
"processes": [
{ "type": "web", "count": 3, "status": "scaling" },
{ "type": "worker", "count": 2, "status": "scaling" }
]
}

Restart Processes

POST /apps/{name}/ps/restart

Request (optional):

{
"type": "web"
}

Response:

{
"restarted": ["web"],
"timestamp": "2026-01-05T11:00:00Z"
}

Logs

Stream Logs

GET /apps/{name}/logs

Query Parameters:

ParamTypeDescription
followboolStream new logs (SSE)
linesintNumber of lines (default 100)
processstringFilter by process type
sincestringStart time (RFC3339)

Response (SSE for follow=true):

data: {"timestamp":"2026-01-05T11:00:00Z","process":"web.1","message":"Server started on :3001"}
data: {"timestamp":"2026-01-05T11:00:01Z","process":"web.1","message":"Request: GET /health"}

Previews

Create Preview

POST /apps/{name}/previews

Request:

{
"pr_number": 123,
"image": "ghcr.io/org/app:pr-123"
}

Response: 201 Created

{
"name": "myapp-pr-123",
"url": "https://myapp-pr-123.pvdify.win",
"status": "deploying",
"pr_number": 123
}

Delete Preview

DELETE /apps/{name}/previews/{pr_number}

Response: 204 No Content


Health

API Health

GET /health

Response:

{
"status": "healthy",
"version": "1.0.0",
"uptime": "72h15m30s"
}

Error Responses

All errors follow this format:

{
"error": {
"code": "not_found",
"message": "App 'myapp' not found"
}
}

Error Codes

CodeHTTP StatusDescription
unauthorized401Invalid or missing token
forbidden403Insufficient permissions
not_found404Resource not found
conflict409Resource already exists
invalid_request422Validation error
internal_error500Server error

Rate Limits

EndpointLimit
All endpoints100 req/min
/logs (streaming)10 concurrent
/releases (deploy)10 req/min

Rate limit headers:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1704456000