Concepts

A deeper look at how MachineMarket works under the hood: architecture, providers, templates, instance lifecycle, and security.

Architecture overview

System architecture
┌─────────────────────────────────────────────────────────────┐
│                        AI Agent                              │
│  1. GET /v1/pricing → calculate cost                        │
│  2. Send USDC on Base → ERC-20 transfer                     │
│  3. POST /v1/spawn { tx_hash, tier, template, duration }    │
└────────────────────────────┬────────────────────────────────┘
                             │
                             ▼
┌─────────────────────────────────────────────────────────────┐
│                    MachineMarket API                         │
│  Next.js App Router (API routes under /api/v1/*)            │
│                                                              │
│  ┌──────────┐  ┌──────────────┐  ┌────────────────────┐    │
│  │ Payment  │  │   Provider   │  │     Supabase       │    │
│  │ Verifier │  │   Registry   │  │  (instances, txs)  │    │
│  │ (viem)   │  │  (Hetzner)   │  │                    │    │
│  └──────────┘  └──────────────┘  └────────────────────┘    │
└────────────────────────────┬────────────────────────────────┘
                             │
                             ▼
┌──────────────┐     ┌─────────────┐
│  Base Chain  │     │   Hetzner   │
│  (verify tx) │     │  Cloud API  │
└──────────────┘     └─────────────┘

Provider system

MachineMarket uses a provider registry pattern. Currently the only provider is Hetzner, but the architecture supports adding new providers (AWS, DigitalOcean, etc.) behind the same interface:

typescript
interface VpsProvider {
  createServer(config: CreateServerConfig): Promise<ServerResult>;
  getServer(providerId: string): Promise<ServerStatus>;
  deleteServer(providerId: string): Promise<void>;
}

The provider maps MachineMarket tiers to Hetzner server types:

  • Nano → cpx11 (2 vCPU, 4 GB, 40 GB)
  • Small → cpx21 (4 vCPU, 8 GB, 80 GB)
  • Medium → cpx31 (8 vCPU, 16 GB, 160 GB)
  • Large → cpx41 (16 vCPU, 32 GB, 320 GB)

Templates

Each template is a cloud-init script that runs on first boot. All templates start with Ubuntu 24.04 and install Docker + SSH.

base

Ubuntu 24.04, Docker, SSH, core utilities (curl, wget, git, jq, htop). A clean slate for any workload.

node

Everything in base plus Node.js 22, pnpm, and PM2. Ready for JavaScript/TypeScript services.

python

Everything in base plus Python 3.12, pip, and venv. Ready for ML workloads and data processing.

agent

Everything in base plus Node.js 22, pnpm, tmux, and git. Designed for deploying other AI agents.

SSH key generation

When spawning an instance, you can either:

  1. Provide your own public key via the ssh_pubkey field. The API installs it on the server.
  2. Let the API generate a keypair. The API creates an Ed25519 keypair, installs the public key, and returns the private key in the response. Store it — it's only returned once.
!Warning
If the API generates a keypair, the private key is returned only in the spawn response. It is not stored by MachineMarket. If you lose it, you lose SSH access.

Instance lifecycle

State machine
                    spawn()
                       │
                       ▼
              ┌─────────────────┐
              │  provisioning   │
              │  (no IP yet)    │
              └────────┬────────┘
                       │  server ready
                       ▼
              ┌─────────────────┐
              │    running      │◄── extend()
              │  (IP assigned)  │
              └───┬─────────┬───┘
                  │         │
        destroy() │         │ expires_at reached
                  ▼         ▼
           ┌──────────┐  ┌──────────┐
           │ destroyed │  │ expired  │
           └──────────┘  └──────────┘
  • provisioning — Server is being created at Hetzner. IP may not be assigned yet. Poll GET /v1/instances/:id until status becomes running.
  • running — Server is active and accessible via SSH. Can be extended with additional payment.
  • expired — The expires_at timestamp passed. A cron job marks it and deletes the Hetzner server.
  • destroyed — Agent called DELETE /v1/instances/:id. Server is immediately removed.

Auto-teardown

A cron endpoint (/api/v1/cron/teardown) runs periodically to find instances past their expires_at time. It deletes the Hetzner server and marks the instance as expired.

Security model

  • No API keys — Payment is authentication. The tx_hash proves you paid; the wallet_address identifies you.
  • On-chain verification — The API reads the transaction receipt and Transfer event directly from Base. It verifies sender, recipient, and amount.
  • Deduplication — Each tx_hash can only be used once, preventing replay attacks.
  • Wallet limits — Max 10 concurrent instances per wallet to prevent abuse.
  • SSH access only — Servers are accessed via SSH. No web panel or shared credentials.
~Tip
For implementation details, see the API Reference and Payment Flow pages.