Skip to main content
Pullbase supports native TLS. Enable it with PULLBASE_TLS_ENABLED=true and provide certificate paths. Alternatively, use a reverse proxy for TLS termination. Admin and viewer accounts authenticate with bearer tokens, while agents use their agent token.

Interactive API Documentation

Pullbase includes an interactive Swagger UI for exploring and testing the API.

GET /swagger/*

Serves the interactive Swagger UI documentation. Access it at https://pullbase.example.com/swagger/index.html.
The Swagger UI is auto-generated from code annotations and always reflects the current API implementation.

Public endpoints

These endpoints do not require authentication.

GET /healthz

Kubernetes-style liveness probe. Returns healthy if the service is running and the database is reachable.
{
  "status": "healthy",
  "service": "pullbase-server",
  "checks": {
    "database": {
      "status": "healthy",
      "latency_ms": 2
    }
  }
}

GET /readyz

Kubernetes-style readiness probe. Returns healthy if the service is ready to accept traffic, including database connectivity and migration status.
{
  "status": "healthy",
  "service": "pullbase-server",
  "checks": {
    "database": {
      "status": "healthy",
      "latency_ms": 3
    },
    "migrations": {
      "status": "healthy",
      "version": 22
    }
  }
}

GET /serverinfo/{serverID}

Returns Git configuration for a server. Used by agents during initial bootstrap to fetch repository details before authenticating.
serverID
string
required
Server identifier.
{
  "repo_url": "https://github.com/your-org/configs.git",
  "branch": "main",
  "deploy_path": "environments/staging/config.yaml",
  "target_commit_hash": "8a9d3c...",
  "auto_reconcile": true
}

GET /bootstrap/status

Returns whether bootstrap is available (first admin not yet created).
{
  "bootstrap_available": true
}

POST /bootstrap/admin

Creates the first admin user using the bootstrap secret.
curl -X POST $BASE_URL/bootstrap/admin \
  -H 'Content-Type: application/json' \
  -d '{
    "bootstrap_secret": "secret-from-file",
    "username": "admin_user",
    "password": "ChangeMeNow123!"
  }'
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "user": {
    "id": 1,
    "username": "admin_user",
    "role": "admin"
  }
}

Authentication

POST /auth/login

curl -X POST $BASE_URL/auth/login \
  -H 'Content-Type: application/json' \
  -d '{
    "username": "admin_user",
    "password": "ChangeMeNow123!"
  }'
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "user": {
    "id": 1,
    "username": "admin_user",
    "role": "admin"
  }
}

GET /auth/me

Returns the authenticated user. Requires Authorization: Bearer <token>.
{
  "id": 1,
  "username": "admin_user",
  "role": "admin"
}

Environments

GET /environments

[
  {
    "id": 5,
    "name": "staging",
    "repo_url": "https://github.com/your-org/configs.git",
    "branch": "main",
    "deploy_path": "environments/staging/config.yaml",
    "auto_reconcile": true,
    "status": "active",
    "deployed_commit": "8a9d3c...",
    "notification_webhook_url": "https://hooks.slack.com/..."
  }
]

POST /environments

curl -X POST $BASE_URL/environments \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "staging",
    "description": "Staging web servers",
    "repo_url": "https://github.com/your-org/configs.git",
    "branch": "main",
    "deploy_path": "environments/staging/config.yaml",
    "notification_webhook_url": "https://hooks.slack.com/...",
    "github_app": {
      "installation_id": 89968159,
      "repository_id": 964854370,
      "app_slug": "pullbase-config"
    }
  }'
{
  "id": 5,
  "name": "staging",
  "auto_reconcile": true,
  "created_at": "2025-01-15T12:34:56Z"
}

GET /environments/{environmentID}

Returns a single environment by ID.

PUT /environments/{environmentID}

Updates an environment. Supports updating notification_webhook_url for webhook notifications.

DELETE /environments/{environmentID}

Deleting an environment cascades to servers in that environment. De-register servers first if you want a clean transition.

POST /environments/{environmentID}/toggle-auto-reconcile

Toggles the auto-reconcile setting for an environment.

POST /environments/{id}/rollback

Initiates a rollback to a previous commit.
curl -X POST $BASE_URL/environments/5/rollback \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
    "target_commit": "8a9d3cba2f...",
    "reason": "Reverting faulty nginx config"
  }'

GET /environments/{id}/rollbacks

Lists rollback events for an environment.
limit
integer
default:"20"
Maximum number of rollbacks to return (1-100).
offset
integer
default:"0"
Pagination offset.
{
  "rollbacks": [
    {
      "id": 42,
      "environment_id": 5,
      "from_commit": "f6e5d4c...",
      "to_commit": "a1b2c3d...",
      "initiated_by": "admin_user",
      "status": "completed",
      "reason": "Reverting broken nginx config",
      "created_at": "2025-01-15T12:30:00Z",
      "completed_at": "2025-01-15T12:31:00Z"
    }
  ],
  "limit": 20,
  "offset": 0
}

GET /environments/{id}/commits

Returns available commits for rollback selection.
limit
integer
default:"20"
Maximum number of commits to return (1-50).
{
  "commits": [
    {
      "hash": "a1b2c3d...",
      "applied_at": "2025-01-14T10:00:00Z",
      "message": "Update nginx config for production"
    },
    {
      "hash": "b2c3d4e...",
      "applied_at": "2025-01-13T15:30:00Z",
      "message": "Add rate limiting rules"
    }
  ],
  "limit": 20
}

GET /rollbacks/{id}

Returns the status of a specific rollback operation.
id
integer
required
Rollback event ID.
{
  "id": 42,
  "environment_id": 5,
  "from_commit": "f6e5d4c...",
  "to_commit": "a1b2c3d...",
  "initiated_by": "admin_user",
  "status": "completed",
  "reason": "Reverting broken nginx config",
  "created_at": "2025-01-15T12:30:00Z",
  "completed_at": "2025-01-15T12:31:00Z"
}
Rollback statuses:
  • pending - Rollback created but not yet started
  • in_progress - Agents are applying the rollback
  • completed - All agents have applied the target commit
  • failed - Rollback failed (check error_message)

POST /environments/{id}/test-webhook

Sends a test webhook notification to verify the configured webhook URL.
curl -X POST $BASE_URL/environments/5/test-webhook \
  -H "Authorization: Bearer $ADMIN_TOKEN"
{
  "success": true,
  "message": "Test webhook sent successfully"
}

GET /environments/health

Returns health status for all environments.

Servers

POST /servers

curl -X POST $BASE_URL/servers \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
    "id": "web-01",
    "name": "staging-web-01",
    "environment_id": 5
  }'
{
  "server": {
    "id": "web-01",
    "name": "staging-web-01",
    "environment_id": 5
  },
  "token": "pbt_9BFz...",
  "installation_info": {
    "instructions": "Run the install script on your target server:",
    "install_command": "curl -fsSL 'https://pullbase.example.com/api/v1/servers/web-01/install-script?token=pbt_9BFz...' | sudo bash"
  }
}

GET /servers

Lists all servers with their latest status.
environment_id
integer
Filter servers by environment ID.

GET /servers/{serverID}

Returns a single server by ID, including last status, agent version, and drift state.

PUT /servers/{serverID}

Updates a server.

DELETE /servers/{serverID}

Deletes a server, revoking its tokens and clearing status history.

POST /servers/{serverID}/toggle-auto-reconcile

Toggles auto-reconcile for a server.

GET /servers/{serverID}/status/history

Returns chronological status entries including commit hash, drift flag, agent version, and timestamp.

GET /servers/{serverID}/drift

Returns detailed drift information for a server, including which packages, services, or files have drifted from the desired state. The drift_details field follows the DriftDetails schema: packages / services / files arrays of DriftItem objects (type, name, expected, actual, message) plus an optional summary.
{
  "server_id": "web-01",
  "server_name": "Production Web 1",
  "is_drifted": true,
  "commit_hash": "a1b2c3d...",
  "detected_at": "2025-01-15T12:30:00Z",
  "drift_details": {
    "packages": [
      {"type": "package", "name": "nginx", "expected": "1.24.0", "actual": "1.22.0", "message": "version mismatch"}
    ],
    "files": [
      {"type": "file", "name": "/etc/nginx/nginx.conf", "expected": "managed", "actual": "modified", "message": "content drift"}
    ],
    "services": [],
    "summary": "nginx downgraded; config modified"
  }
}

GET /servers/{serverID}/install-script

Returns a shell script for installing the agent on the target server.
token
string
required
Agent token for authentication.
version
string
default:"latest"
Agent version to install. When omitted or set to latest, the parameter is not sent.
ca_cert
string
Base64-encoded CA certificate for custom TLS.
curl -fsSL "$BASE_URL/servers/web-01/install-script?token=pbt_xxx" | sudo bash
The script:
  • Downloads the agent binary from GitHub releases
  • Creates a pullbase service user
  • Configures /etc/pullbase/agent.env
  • Installs a hardened systemd service
  • Starts the agent

Token management

  • GET /servers/{serverID}/tokens – list tokens
  • POST /servers/{serverID}/tokens – create token (description, expires_in)
  • DELETE /servers/{serverID}/tokens/{tokenID} – deactivate token

GET /servers/{serverID}/install

Returns installation instructions for the agent.

Token expiration

GET /tokens/expiring

Returns tokens that are expiring within a specified number of days.
days
integer
default:"7"
Number of days to look ahead (max 365).
curl -H "Authorization: Bearer $ADMIN_TOKEN" \
  "$BASE_URL/tokens/expiring?days=14"
{
  "tokens": [
    {
      "token_id": 5,
      "server_id": "web-01",
      "server_name": "Production Web 1",
      "environment_name": "production",
      "description": "initial token",
      "expires_at": "2025-01-20T12:00:00Z",
      "days_until_expiry": 5
    }
  ],
  "count": 1
}

Config validation

POST /validate-config

Validates a config.yaml file before committing to Git.
curl -X POST $BASE_URL/validate-config \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "Content-Type: text/yaml" \
  --data-binary @config.yaml
{
  "valid": true,
  "errors": []
}
Validates:
  • YAML syntax with line/column error positions
  • Package states: present, latest, absent
  • Service states: running, stopped
  • File modes: valid octal (e.g., 0644, 0755)
  • Service managers: systemd, supervisor, supervisord, docker-supervisor, openrc

User management

GET /users

Supports pagination and role filtering.
limit
integer
default:"100"
Maximum number of users per page (1-500).
offset
integer
default:"0"
Pagination offset.
role
string
Filter by role (admin, user, viewer).

POST /users

curl -X POST $BASE_URL/users \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
    "username": "ops_user",
    "password": "StrongPassword!2024",
    "role": "viewer"
  }'

DELETE /users/{userID}

curl -X DELETE $BASE_URL/users/7 \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{ "confirm_username": "ops_user" }'

Agent endpoints

These endpoints require agent token authentication (Authorization: Bearer <agent_token>).

GET /agent/serverinfo

Returns Git configuration and target commit for the authenticated agent’s server.
{
  "repo_url": "https://github.com/your-org/configs.git",
  "branch": "main",
  "deploy_path": "environments/staging/config.yaml",
  "target_commit_hash": "8a9d3c...",
  "auto_reconcile": true
}

GET /agent/git-token

Returns a short-lived GitHub installation token when the environment uses a GitHub App.
{
  "token": "ghs_...",
  "expires_at": "2025-01-15T13:34:56Z",
  "repo_url": "https://github.com/your-org/configs.git",
  "provider": "github",
  "installation_id": 89968159,
  "authentication": "github_app"
}

PUT /agent/status

Reports agent status to the server.
curl -X PUT $BASE_URL/agent/status \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
    "commit_hash": "8a9d3c...",
    "is_drifted": false,
    "status": "Applied",
    "error_message": null,
    "agent_version": "v1.0.0"
  }'
The agent_version field is optional but recommended. It’s displayed in the UI and helps track agent deployments.

Webhooks

POST /webhooks/{provider}

Receives webhooks from Git providers. Currently supports github. The webhook payload is validated using HMAC signature verification with PULLBASE_WEBHOOK_SECRET_KEY.

Notification webhooks

Pullbase can send webhook notifications when drift is detected or errors occur during reconciliation.

Configuration

Set notification_webhook_url when creating or updating an environment:
curl -X PUT $BASE_URL/environments/5 \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
    "notification_webhook_url": "https://hooks.slack.com/services/..."
  }'

Webhook payload

{
  "event": "drift_detected",
  "timestamp": "2025-01-15T10:30:00Z",
  "environment_id": 5,
  "environment_name": "production",
  "server_id": "web-01",
  "server_name": "Web Server 1",
  "details": "File /etc/nginx/nginx.conf content differs from desired state",
  "commit_hash": "abc123"
}
Event types:
  • drift_detected - Agent detected configuration drift
  • apply_error - Error occurred during reconciliation
  • test - Test webhook from the UI or API

Retry behavior

Failed webhook deliveries are retried up to 3 times with exponential backoff (1s, 2s, 4s delays).

GET /webhook-statuses

Returns the current webhook delivery status for all environments.
{
  "webhook_statuses": {
    "5": {
      "last_delivery": "2025-01-15T12:30:00Z",
      "last_status": 200,
      "consecutive_failures": 0
    }
  }
}

Web UI

Pullbase includes an embedded web dashboard accessible at /ui/. The UI is a single-page application (SPA) that communicates with the API.

Routes

PathDescription
/Redirects to /ui/
/ui/Dashboard home (requires authentication)
/ui/loginLogin page
/ui/serversServer list and management
/ui/environmentsEnvironment list and management
/ui/assets/*Static assets (JS, CSS, fonts)

Authentication

The web UI uses cookie-based session authentication:
  1. User submits credentials to POST /ui/login
  2. Server validates and sets session_token cookie
  3. Subsequent requests include the cookie automatically
  4. Protected routes redirect to /ui/login if unauthenticated
The web UI uses the same API endpoints documented above. You can use the Swagger UI at /swagger/ to explore and test endpoints interactively.

Metrics

Pullbase provides metrics endpoints for monitoring drift events, reconciliation success rates, and agent connectivity.

GET /metrics/drift

Returns drift event metrics over a specified time period.
days
integer
default:"7"
Number of days to include (1-90).
{
  "period": "7 days",
  "total_events": 12,
  "time_series": [
    {"timestamp": "2025-01-09T00:00:00Z", "value": 2},
    {"timestamp": "2025-01-10T00:00:00Z", "value": 0},
    {"timestamp": "2025-01-11T00:00:00Z", "value": 3},
    {"timestamp": "2025-01-12T00:00:00Z", "value": 1},
    {"timestamp": "2025-01-13T00:00:00Z", "value": 4},
    {"timestamp": "2025-01-14T00:00:00Z", "value": 0},
    {"timestamp": "2025-01-15T00:00:00Z", "value": 2}
  ]
}

GET /metrics/reconciliation

Returns reconciliation success/failure metrics over time.
days
integer
default:"7"
Number of days to include (1-90).
{
  "period": "7 days",
  "total_applied": 145,
  "total_failed": 3,
  "success_rate": 97.97,
  "time_series": [
    {"timestamp": "2025-01-09T00:00:00Z", "value": 20},
    {"timestamp": "2025-01-10T00:00:00Z", "value": 22},
    {"timestamp": "2025-01-11T00:00:00Z", "value": 18},
    {"timestamp": "2025-01-12T00:00:00Z", "value": 21},
    {"timestamp": "2025-01-13T00:00:00Z", "value": 25},
    {"timestamp": "2025-01-14T00:00:00Z", "value": 19},
    {"timestamp": "2025-01-15T00:00:00Z", "value": 20}
  ]
}

GET /metrics/connectivity

Returns agent online/offline status for all servers.
{
  "total_agents": 5,
  "online_agents": 4,
  "offline_agents": 1,
  "stale_threshold": "5m0s",
  "agent_statuses": [
    {
      "server_id": "web-01",
      "server_name": "Production Web 1",
      "last_seen": "2025-01-15T12:34:00Z",
      "is_online": true,
      "status": "Applied"
    },
    {
      "server_id": "api-01",
      "server_name": "API Server",
      "last_seen": "2025-01-15T12:00:00Z",
      "is_online": false,
      "status": "Applied"
    }
  ]
}

Error handling

  • 400 Bad Request – validation failure (details in the error field)
  • 401 Unauthorized – missing or invalid token
  • 403 Forbidden – caller lacks the required role (for example, viewer attempting an admin action)
  • 404 Not Found – resource does not exist or has been deleted
  • 429 Too Many Requests – rate limited (check Retry-After header)
  • 500 Internal Server Error – unexpected server error (check server logs)
For production, enable native TLS (PULLBASE_TLS_ENABLED=true) or use HTTPS via a reverse proxy.