Skip to main content

PAP Agents API Reference

This document provides comprehensive API documentation for creating and managing PAP agents.

Base URL

https://plugged.in/api/agents

Authentication

All endpoints require API key authentication via the Authorization header:
Authorization: Bearer YOUR_API_KEY
API Keys: Generate API keys from your Plugged.in project settings. Keys are scoped to profiles within projects.

Endpoints

List Agents

Retrieve all agents for the authenticated user’s active profile.
curl https://plugged.in/api/agents \
  -H "Authorization: Bearer YOUR_API_KEY"

Response

[
  {
    "uuid": "123e4567-e89b-12d3-a456-426614174000",
    "name": "my-agent",
    "dns_name": "my-agent.is.plugged.in",
    "state": "ACTIVE",
    "kubernetes_namespace": "agents",
    "kubernetes_deployment": "my-agent",
    "created_at": "2025-11-13T08:00:00Z",
    "provisioned_at": "2025-11-13T08:00:15Z",
    "activated_at": "2025-11-13T08:00:45Z",
    "terminated_at": null,
    "last_heartbeat_at": "2025-11-13T08:05:30Z",
    "metadata": {
      "description": "My autonomous agent",
      "image": "nginxinc/nginx-unprivileged:alpine",
      "resources": {
        "cpu_request": "100m",
        "memory_request": "256Mi",
        "cpu_limit": "1000m",
        "memory_limit": "1Gi"
      }
    }
  }
]

Response Fields

FieldTypeDescription
uuidUUIDUnique agent identifier
namestringDNS-safe agent name
dns_namestringFull DNS hostname ({name}.is.plugged.in)
stateenumCurrent lifecycle state (see Lifecycle)
kubernetes_namespacestringKubernetes namespace (typically “agents”)
kubernetes_deploymentstringDeployment name in Kubernetes
created_attimestampWhen agent was created
provisioned_attimestampWhen Kubernetes resources were deployed
activated_attimestampWhen agent sent first heartbeat
terminated_attimestampWhen agent was terminated (null if active)
last_heartbeat_attimestampLast heartbeat received (null if no heartbeats yet)
metadataobjectAgent configuration and metadata

Create Agent

Deploy a new PAP agent to Kubernetes infrastructure.
curl -X POST https://plugged.in/api/agents \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "my-agent",
    "description": "My autonomous agent",
    "resources": {
      "cpu_request": "100m",
      "memory_request": "256Mi",
      "cpu_limit": "1000m",
      "memory_limit": "1Gi"
    }
  }'

Request Body

FieldTypeRequiredDescription
namestringYesDNS-safe agent name (lowercase, alphanumeric, hyphens)
descriptionstringNoHuman-readable description
imagestringNoContainer image (default: nginxinc/nginx-unprivileged:alpine)
resourcesobjectNoResource requests and limits
resources.cpu_requeststringNoCPU request (e.g., “100m”, default: “100m”)
resources.memory_requeststringNoMemory request (e.g., “256Mi”, default: “256Mi”)
resources.cpu_limitstringNoCPU limit (e.g., “1000m”, default: “1000m”)
resources.memory_limitstringNoMemory limit (e.g., “1Gi”, default: “1Gi”)
DNS-Safe Names: Agent names must match the pattern ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$. Invalid names will return HTTP 400.

Response (Success)

{
  "agent": {
    "uuid": "123e4567-e89b-12d3-a456-426614174000",
    "name": "my-agent",
    "dns_name": "my-agent.is.plugged.in",
    "state": "NEW",
    "kubernetes_namespace": "agents",
    "kubernetes_deployment": "my-agent",
    "created_at": "2025-11-13T08:00:00Z",
    "provisioned_at": null,
    "activated_at": null,
    "terminated_at": null,
    "last_heartbeat_at": null,
    "metadata": {
      "description": "My autonomous agent",
      "resources": {
        "cpu_request": "100m",
        "memory_request": "256Mi",
        "cpu_limit": "1000m",
        "memory_limit": "1Gi"
      }
    }
  },
  "deployment": {
    "success": true,
    "message": "Agent my-agent deployed successfully",
    "deploymentName": "my-agent"
  }
}

Error Responses

StatusErrorDescription
400Name is requiredMissing name field
400Name must be DNS-safe: lowercase alphanumeric and hyphens onlyInvalid name format
401UnauthorizedMissing or invalid API key
409Agent with this name already existsDuplicate agent name in profile
500Failed to create agentInternal server error

Get Agent Details

Retrieve comprehensive information about a specific agent, including recent heartbeats, metrics, and lifecycle events.
curl https://plugged.in/api/agents/AGENT_UUID \
  -H "Authorization: Bearer YOUR_API_KEY"

Response

{
  "agent": {
    "uuid": "123e4567-e89b-12d3-a456-426614174000",
    "name": "my-agent",
    "dns_name": "my-agent.is.plugged.in",
    "state": "ACTIVE",
    "created_at": "2025-11-13T08:00:00Z",
    "last_heartbeat_at": "2025-11-13T08:05:30Z",
    "metadata": {...}
  },
  "recentHeartbeats": [
    {
      "id": "1001",
      "agent_uuid": "123e4567-e89b-12d3-a456-426614174000",
      "mode": "IDLE",
      "uptime_seconds": 330,
      "timestamp": "2025-11-13T08:05:30Z"
    }
  ],
  "recentMetrics": [
    {
      "id": "2001",
      "agent_uuid": "123e4567-e89b-12d3-a456-426614174000",
      "cpu_percent": 12,
      "memory_mb": 128,
      "requests_handled": 45,
      "custom_metrics": {},
      "timestamp": "2025-11-13T08:05:00Z"
    }
  ],
  "lifecycleEvents": [
    {
      "id": "3001",
      "agent_uuid": "123e4567-e89b-12d3-a456-426614174000",
      "event_type": "ACTIVATED",
      "from_state": "PROVISIONED",
      "to_state": "ACTIVE",
      "metadata": {
        "triggered_by": "system"
      },
      "timestamp": "2025-11-13T08:00:45Z"
    }
  ],
  "kubernetesStatus": {
    "ready": true,
    "replicas": 1,
    "readyReplicas": 1,
    "unavailableReplicas": 0,
    "conditions": [
      {
        "type": "Available",
        "status": "True",
        "reason": "MinimumReplicasAvailable",
        "message": "Deployment has minimum availability."
      }
    ]
  }
}

Response Fields

FieldTypeDescription
agentobjectCore agent metadata (same as list response)
recentHeartbeatsarrayLast 10 heartbeats (ordered newest first)
recentMetricsarrayLast 10 metric reports (ordered newest first)
lifecycleEventsarrayComplete lifecycle event history (ordered newest first)
kubernetesStatusobjectReal-time Kubernetes deployment status (null if not deployed)

Error Responses

StatusErrorDescription
401UnauthorizedMissing or invalid API key
404Agent not foundAgent doesn’t exist or doesn’t belong to profile
500Failed to fetch agentInternal server error

Delete Agent

Terminate and delete an agent, removing all Kubernetes resources.
curl -X DELETE https://plugged.in/api/agents/AGENT_UUID \
  -H "Authorization: Bearer YOUR_API_KEY"

Response (Success)

{
  "message": "Agent terminated successfully",
  "kubernetes": {
    "success": true,
    "message": "Agent my-agent deleted successfully"
  }
}
State Transition: User-initiated deletion transitions agent to TERMINATED state. Only the Station (control plane) can issue KILLED state.

Cleanup Operations

The DELETE operation removes:
  • Kubernetes Deployment
  • Kubernetes Service
  • Kubernetes Ingress
  • TLS Secret (Let’s Encrypt certificate)
The agent record remains in database with state=TERMINATED for audit purposes.

Error Responses

StatusErrorDescription
401UnauthorizedMissing or invalid API key
404Agent not foundAgent doesn’t exist or doesn’t belong to profile
500Failed to delete agentInternal server error

Export Agent Data

Export complete agent data including telemetry history for backup or analysis.
curl -X POST https://plugged.in/api/agents/AGENT_UUID/export \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "include_telemetry": true,
    "telemetry_limit": 1000
  }'

Request Body

FieldTypeRequiredDescription
include_telemetrybooleanNoInclude heartbeat and metrics history (default: true)
telemetry_limitintegerNoMaximum telemetry records to include (default: 100)

Response

Returns complete agent data including configuration, lifecycle events, and telemetry:
{
  "agent": {
    "uuid": "...",
    "name": "my-agent",
    "dns_name": "my-agent.is.plugged.in",
    "state": "ACTIVE",
    ...
  },
  "heartbeats": [...],
  "metrics": [...],
  "lifecycle_events": [...],
  "metadata": {
    "exported_at": "2025-11-13T08:15:00Z",
    "triggered_by": "user-uuid",
    "total_heartbeats": 250,
    "total_metrics": 240
  }
}

Submit Heartbeat

Agents send heartbeats to signal liveness. Heartbeats contain ONLY liveness data (zombie prevention).
CRITICAL: Heartbeats must contain ONLY mode and uptime_seconds. Never include resource data (CPU, memory) in heartbeats—use the Metrics endpoint instead. This separation is the core of PAP’s zombie prevention.
curl -X POST https://plugged.in/api/agents/AGENT_UUID/heartbeat \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "mode": "IDLE",
    "uptime_seconds": 330
  }'

Request Body

FieldTypeRequiredDescription
modeenumYesHeartbeat mode: EMERGENCY (5s), IDLE (30s), SLEEP (15min)
uptime_secondsnumberYesAgent uptime in seconds
Heartbeat Intervals:
  • EMERGENCY: Every 5 seconds (for critical situations)
  • IDLE: Every 30 seconds (default)
  • SLEEP: Every 15 minutes (for low-priority background agents)
Missing one interval triggers AGENT_UNHEALTHY (error code 480).

Response

{
  "message": "Heartbeat recorded"
}

Submit Metrics

Agents send metrics separately from heartbeats. Metrics contain resource telemetry only.
Separation is Key: Metrics are sent on a separate channel from heartbeats (typically every 60 seconds). This ensures large telemetry payloads cannot starve the control path.
curl -X POST https://plugged.in/api/agents/AGENT_UUID/metrics \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "cpu_percent": 12.5,
    "memory_mb": 128,
    "requests_handled": 45,
    "custom_metrics": {
      "queue_depth": 3,
      "cache_hit_rate": 0.85
    }
  }'

Request Body

FieldTypeRequiredDescription
cpu_percentnumberYesCPU usage percentage (0-100)
memory_mbnumberYesMemory usage in megabytes
requests_handledintegerYesTotal requests handled since start
custom_metricsobjectNoAgent-specific custom metrics

Response

{
  "message": "Metrics recorded"
}

Common Patterns

Create and Wait for Activation

#!/bin/bash

# Create agent
RESPONSE=$(curl -s -X POST https://plugged.in/api/agents \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "test-agent"}')

AGENT_UUID=$(echo $RESPONSE | jq -r '.agent.uuid')
echo "Created agent: $AGENT_UUID"

# Poll until ACTIVE
while true; do
  STATE=$(curl -s https://plugged.in/api/agents/$AGENT_UUID \
    -H "Authorization: Bearer $API_KEY" \
    | jq -r '.agent.state')

  echo "Current state: $STATE"

  if [ "$STATE" = "ACTIVE" ]; then
    echo "Agent is now ACTIVE!"
    break
  fi

  sleep 5
done

List Healthy Agents

// Fetch all agents and filter by state
const response = await fetch('https://plugged.in/api/agents', {
  headers: { 'Authorization': `Bearer ${API_KEY}` }
});

const agents = await response.json();

const healthy = agents.filter(agent =>
  agent.state === 'ACTIVE' &&
  agent.last_heartbeat_at &&
  (Date.now() - new Date(agent.last_heartbeat_at) < 60000) // < 1 minute ago
);

console.log(`${healthy.length} healthy agents`);

Bulk Termination

import requests

# Get all agents
response = requests.get(
    'https://plugged.in/api/agents',
    headers={'Authorization': f'Bearer {API_KEY}'}
)
agents = response.json()

# Filter agents to terminate (e.g., by name pattern)
to_terminate = [a for a in agents if a['name'].startswith('test-')]

# Terminate each
for agent in to_terminate:
    response = requests.delete(
        f'https://plugged.in/api/agents/{agent["uuid"]}',
        headers={'Authorization': f'Bearer {API_KEY}'}
    )
    print(f"Terminated {agent['name']}: {response.json()}")

Rate Limits

API endpoints are subject to rate limits to ensure fair usage:
TierRequests per MinuteBurst
Free6010
Pro30050
Enterprise1000100
Rate limit headers:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1699999999
429 Too Many Requests: If you exceed rate limits, wait for the reset time indicated in X-RateLimit-Reset header.

Webhook Events (Coming Soon)

Subscribe to agent lifecycle events via webhooks:
{
  "event": "agent.activated",
  "agent_uuid": "...",
  "agent_name": "my-agent",
  "timestamp": "2025-11-13T08:00:45Z",
  "data": {
    "from_state": "PROVISIONED",
    "to_state": "ACTIVE"
  }
}
Available Events:
  • agent.created
  • agent.provisioned
  • agent.activated
  • agent.draining
  • agent.terminated
  • agent.killed
  • agent.unhealthy

SDK Support

Official Plugged.in SDKs now include agent management:

SDK Examples

import { PluggedInClient } from 'pluggedinkit-js';

const client = new PluggedInClient({
  apiKey: process.env.PLUGGEDIN_API_KEY
});

// Create an agent
const result = await client.agents.create({
  name: 'my-agent',
  description: 'My first PAP agent',
  resources: {
    cpu_request: '100m',
    memory_request: '256Mi',
    cpu_limit: '1000m',
    memory_limit: '1Gi'
  }
});

console.log(`Agent created: ${result.agent.uuid}`);
console.log(`DNS: ${result.agent.dns_name}`);

// List all agents
const agents = await client.agents.list();

// Get agent details
const details = await client.agents.get(agentId);

// Send heartbeat (from within agent)
await client.agents.heartbeat(agentId, {
  mode: 'IDLE',
  uptime_seconds: process.uptime()
});

// Send metrics (from within agent)
await client.agents.metrics(agentId, {
  cpu_percent: 12.5,
  memory_mb: 128,
  requests_handled: 45
});

// Export agent data
const exportData = await client.agents.export(agentId, {
  include_telemetry: true,
  telemetry_limit: 1000
});

// Delete agent
await client.agents.delete(agentId);

Next Steps