# spawn.prim.sh VPS in one API call. Deploy, scale, destroy. Per-second billing. Base URL: https://spawn.prim.sh Auth: x402 (USDC on Base Sepolia). GET /, GET /pricing, GET /v1/metrics are free. Chain: Base Sepolia (eip155:84532) during beta. Install: curl -fsSL https://spawn.prim.sh/install.sh | sh Limits: Max concurrent servers per wallet: 3 Available types: small (2 vCPU, 4 GB RAM) only during beta Locations: nyc3, sfo3, ams3, lon1, fra1, sgp1, tor1, blr1, syd1 (DigitalOcean) Images: ubuntu-24.04, ubuntu-22.04, debian-12, fedora-41 --- ## Quick Start 1. POST /v1/ssh-keys with name + public_key → register SSH key 2. POST /v1/servers with name, type, image, location → create server ($0.01) 3. Poll GET /v1/servers/:id until status is "running" → get IP address 4. DELETE /v1/servers/:id when done → release resources and get deposit refund ## Tips - Server returns immediately with status 'initializing' — poll until 'running' for the IP. - Register SSH keys first via POST /v1/ssh-keys to enable passwordless SSH access. - Unused deposit is refunded on DELETE. Budget for the expected runtime. - Only 'small' type (2 vCPU, 4 GB RAM) is available during beta. - user_data field accepts cloud-init scripts to automate first-boot setup. - Server must be stopped before resize. stop → resize → start. --- ## x402 Payment 1. Make request. Server returns 402 with Payment-Required header. 2. Sign EIP-3009 transferWithAuthorization. 3. Retry with Payment-Signature header (base64-encoded signed authorization). Error envelope: {"error": {"code": "", "message": ""}} Error codes: not_found forbidden invalid_request insufficient_deposit provider_error rate_limited not_implemented server_limit_exceeded type_not_allowed --- ## Endpoints ### GET / Health check. Free. Response (200): service string "spawn.sh" status string "ok" --- ### GET /pricing Machine-readable pricing for all endpoints. Free. Response (200): service string "spawn.prim.sh" currency string "USDC" network string "eip155:8453" routes array Route pricing list .method string HTTP method .path string URL path .price_usdc string Price in USDC (decimal string) .description string Human-readable description --- ### GET /v1/metrics Operational metrics. Uptime, request counts, latency percentiles, error rates. Free. Response (200): service string "spawn.prim.sh" uptime_s number Seconds since last restart requests object Request counts and latencies by endpoint payments object Payment counts by endpoint errors object Error counts by status code --- ### POST /v1/servers Provision a new VPS. Returns immediately with status 'initializing'. Poll GET /v1/servers/:id until status is 'running' to get IP address. Price: $0.01 Request: name string required Server name (provider-level label). type string required Server type slug. Only "small" (2 vCPU, 4 GB RAM) available in beta. image string required OS image slug (e.g. "ubuntu-24.04", "debian-12"). location string required Data center slug (e.g. "nyc3", "sfo3", "lon1"). provider string optional Cloud provider. Default "digitalocean". ssh_keys string[] optional SSH key IDs from POST /v1/ssh-keys to install on the server. user_data string optional Cloud-init script to run on first boot. Response (201): server ServerResponse Created server object (initial status: "initializing"). action ActionResponse Action object tracking the provisioning progress. deposit_charged string USDC charged for this server as a decimal string. deposit_remaining string Remaining USDC deposit balance as a decimal string. Errors: 400 invalid_request Missing required fields 402 payment_required x402 payment needed 403 server_limit_exceeded Wallet has reached 3 concurrent server limit 502 provider_error Cloud provider API error --- ### GET /v1/servers List all servers owned by the calling wallet Price: $0.001 Query params: limit integer optional 1-100, default 20 page integer optional 1-based page number, default 1 Response (200): ServerListResponse Errors: 402 payment_required x402 payment needed 403 forbidden Missing wallet in payment --- ### GET /v1/servers/:id Get full details for a single server. Poll this until status='running'. Price: $0.001 Path params: id string required id parameter Response (200): id string Prim server ID (e.g. "srv_abc123"). provider string Cloud provider (e.g. "digitalocean"). provider_id string Provider-assigned server ID. name string Server name (label). type string Server type slug (e.g. "small"). status ServerStatus Current server lifecycle status. image string OS image slug (e.g. "ubuntu-24.04"). location string Data center slug (e.g. "nyc3"). public_net PublicNet Public IP addresses. owner_wallet string Ethereum address of the server owner. created_at string ISO 8601 timestamp when the server was created. Errors: 402 payment_required x402 payment needed 403 forbidden Server belongs to a different wallet 404 not_found Server not found --- ### DELETE /v1/servers/:id Destroy a server and release its resources. Unused deposit is refunded. Price: $0.005 Path params: id string required id parameter Response (200): status "deleted" Always "deleted" on success. deposit_refunded string USDC refunded to wallet as a decimal string. Errors: 402 payment_required x402 payment needed 403 forbidden Server belongs to a different wallet 404 not_found Server not found 502 provider_error Cloud provider API error --- ### POST /v1/servers/:id/start Start a stopped server Price: $0.002 Path params: id string required id parameter Response (200): action ActionResponse Action object for the requested operation. Errors: 402 payment_required x402 payment needed 403 forbidden Server belongs to a different wallet 404 not_found Server not found 502 provider_error Cloud provider API error --- ### POST /v1/servers/:id/stop Stop a running server (graceful shutdown) Price: $0.002 Path params: id string required id parameter Response (200): action ActionResponse Action object for the requested operation. Errors: 402 payment_required x402 payment needed 403 forbidden Server belongs to a different wallet 404 not_found Server not found 502 provider_error Cloud provider API error --- ### POST /v1/servers/:id/reboot Reboot a running server Price: $0.002 Path params: id string required id parameter Response (200): action ActionResponse Action object for the requested operation. Errors: 402 payment_required x402 payment needed 403 forbidden Server belongs to a different wallet 404 not_found Server not found 502 provider_error Cloud provider API error --- ### POST /v1/servers/:id/resize Change server type (CPU/RAM). Server must be stopped first. Deposit adjusted. Price: $0.01 Path params: id string required id parameter Request: type string required Target server type slug. upgrade_disk boolean optional Upgrade disk along with CPU/RAM. Irreversible if true. Default false. Response (200): action ActionResponse Action object (command: "resize"). new_type string Target server type after resize. deposit_delta string USDC deposit change as a decimal string. Positive = charged, negative = refunded. Errors: 400 invalid_request Missing type field or invalid value 402 payment_required x402 payment needed 403 forbidden Server belongs to a different wallet 404 not_found Server not found 502 provider_error Cloud provider API error --- ### POST /v1/servers/:id/rebuild Reinstall from a fresh OS image. All data on server is destroyed. Price: $0.005 Path params: id string required id parameter Request: image string required OS image slug to rebuild with (e.g. "debian-12"). Response (200): action ActionResponse Action object (command: "rebuild"). root_password string | null New root password if no SSH keys configured. Null if SSH keys are installed. Errors: 400 invalid_request Missing image field 402 payment_required x402 payment needed 403 forbidden Server belongs to a different wallet 404 not_found Server not found 502 provider_error Cloud provider API error --- ### POST /v1/ssh-keys Register a public SSH key. Returned ID can be used in ssh_keys when creating a server. Price: $0.001 Request: name string required Human-readable label for this SSH key. public_key string required Public key string (e.g. "ssh-ed25519 AAAA..."). Response (201): id string Prim SSH key ID (e.g. "key_abc123"). provider string Cloud provider. provider_id string Provider-assigned key ID. name string Key label. fingerprint string SSH key fingerprint. owner_wallet string Ethereum address of the key owner. created_at string ISO 8601 timestamp when the key was registered. Errors: 400 invalid_request Missing name or public_key 402 payment_required x402 payment needed 502 provider_error Cloud provider API error --- ### GET /v1/ssh-keys List all SSH keys registered by the calling wallet Price: $0.001 Response (200): SshKeyListResponse Errors: 402 payment_required x402 payment needed 403 forbidden Missing wallet in payment --- ### DELETE /v1/ssh-keys/:id Remove an SSH key. Keys in use by active servers remain until server is rebuilt. Price: $0.001 Path params: id string required id parameter Response (200): {} (empty object) Errors: 402 payment_required x402 payment needed 403 forbidden Key belongs to a different wallet 404 not_found SSH key not found 502 provider_error Cloud provider API error --- ## Ownership All servers and SSH keys are scoped to the wallet address extracted from the x402 payment.