API Reference
API Reference
pvdifyd REST API v1
Base URL: https://pvdify.win/api/v1
Authentication
All requests require a Bearer token:
curl -H "Authorization: Bearer $PVDIFY_TOKEN" \ https://pvdify.win/api/v1/appsTokens are issued via:
pvdify login(CLI)- Admin UI settings
- GitHub App installation
Apps
List Apps
GET /appsResponse:
{ "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 /appsRequest:
{ "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}/releasesResponse:
{ "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}/releasesRequest:
{ "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}/rollbackRequest (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}/configResponse:
{ "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}/configRequest:
{ "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/secretsRequest:
{ "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/versionsResponse:
{ "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}/domainsResponse:
{ "domains": [ { "name": "myapp.com", "status": "active", "ssl": true }, { "name": "www.myapp.com", "status": "active", "ssl": true } ]}Add Domain
POST /apps/{name}/domainsRequest:
{ "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}/verifyInitiates 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}/psResponse:
{ "processes": [ { "type": "web", "count": 2, "status": "running" }, { "type": "worker", "count": 1, "status": "running" } ]}Scale Processes
POST /apps/{name}/ps/scaleRequest:
{ "web": 3, "worker": 2}Response:
{ "processes": [ { "type": "web", "count": 3, "status": "scaling" }, { "type": "worker", "count": 2, "status": "scaling" } ]}Restart Processes
POST /apps/{name}/ps/restartRequest (optional):
{ "type": "web"}Response:
{ "restarted": ["web"], "timestamp": "2026-01-05T11:00:00Z"}Logs
Stream Logs
GET /apps/{name}/logsQuery Parameters:
| Param | Type | Description |
|---|---|---|
follow | bool | Stream new logs (SSE) |
lines | int | Number of lines (default 100) |
process | string | Filter by process type |
since | string | Start 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}/previewsRequest:
{ "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 /healthResponse:
{ "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
| Code | HTTP Status | Description |
|---|---|---|
unauthorized | 401 | Invalid or missing token |
forbidden | 403 | Insufficient permissions |
not_found | 404 | Resource not found |
conflict | 409 | Resource already exists |
invalid_request | 422 | Validation error |
internal_error | 500 | Server error |
Rate Limits
| Endpoint | Limit |
|---|---|
| All endpoints | 100 req/min |
/logs (streaming) | 10 concurrent |
/releases (deploy) | 10 req/min |
Rate limit headers:
X-RateLimit-Limit: 100X-RateLimit-Remaining: 95X-RateLimit-Reset: 1704456000