API Reference

Base URL: https://api.machinemarket.ai

All endpoints accept and return JSON. Payment serves as authentication for spawn and extend. Instance management (GET, DELETE) requires wallet ownership verification.

iNote
Error responses always include an error string and optionally a code string for programmatic handling.
POST/v1/spawn

Provision a new VPS instance. Requires a verified USDC payment on Base.

Request body

FieldTypeRequiredDescription
tierstringyes"Nano" | "Small" | "Medium" | "Large"
templatestringyes"base" | "node" | "python" | "agent" | "openclaw"
durationstringyes"1h" | "24h" | "7d" | "30d"
regionstringnoHetzner region ID. Defaults to "fsn1". See GET /v1/regions.
tx_hashstringyesTransaction hash of the USDC payment on Base (0x-prefixed, 64 hex chars).
wallet_addressstringyesSender wallet address (0x-prefixed, 40 hex chars).
ssh_pubkeystringnoYour SSH public key. If omitted, a keypair is generated and the private key is returned.

Response (201)

FieldTypeRequiredDescription
instance.idstringyesUUID of the created instance.
instance.tierstringyesThe tier name.
instance.templatestringyesThe template ID.
instance.regionstringyesHetzner region ID.
instance.statusstringyes"provisioning" or "running".
instance.ip_addressstring | nullyesIP address (null while provisioning).
instance.created_atstringyesISO 8601 timestamp.
instance.expires_atstringyesISO 8601 expiry timestamp.
instance.cost_usdcnumberyesTotal cost in USDC.
credentials.ssh_userstringyesAlways "root".
credentials.ssh_hoststring | nullyesSame as ip_address.
credentials.ssh_portnumberyesAlways 22.
credentials.ssh_private_keystringnoPEM private key (only if ssh_pubkey was omitted).

Error codes

FieldTypeRequiredDescription
400noInvalid request body or parameters.
402PAYMENT_INVALIDnoPayment verification failed (wrong amount, sender, or failed tx).
409TX_DUPLICATEnoTransaction hash already used.
429WALLET_LIMITnoMax 10 concurrent instances per wallet.
502PROVISION_FAILEDnoHetzner provisioning failed.
curl
curl -X POST https://api.machinemarket.ai/v1/spawn \
  -H "Content-Type: application/json" \
  -d '{
    "tier": "Small",
    "template": "node",
    "duration": "24h",
    "tx_hash": "0xabc...def",
    "wallet_address": "0x1234...5678"
  }'
SDK
typescript
const result = await mm.spawn({
  tier: "Small",
  template: "node",
  duration: "24h",
  tx_hash: "0xabc...def",
  wallet_address: "0x1234...5678",
});
GET/v1/instances/:id

Get instance details. Requires the owner wallet address. If the instance is still provisioning, the API polls Hetzner for updated status.

Query parameters

FieldTypeRequiredDescription
wallet_addressstringyesOwner wallet address (0x-prefixed, 40 hex chars). Must match the wallet that spawned the instance.

Response (200)

FieldTypeRequiredDescription
idstringyesInstance UUID.
tierstringyesTier name.
templatestringyesTemplate ID.
regionstringyesRegion ID.
statusstringyes"provisioning" | "running" | "expired" | "destroyed".
ip_addressstring | nullyesIP address.
created_atstringyesISO 8601.
expires_atstringyesISO 8601.
destroyed_atstring | nullyesISO 8601 or null.
cost_usdcnumberyesTotal cost.

Error codes

FieldTypeRequiredDescription
400noMissing wallet_address query parameter.
404noInstance not found or wallet does not own it.
curl
curl "https://api.machinemarket.ai/v1/instances/YOUR_INSTANCE_ID?wallet_address=0x1234...5678"
SDK
typescript
const instance = await mm.getInstance("YOUR_INSTANCE_ID", {
  wallet_address: "0x1234...5678",
});
console.log(instance.status, instance.ip_address);
DELETE/v1/instances/:id

Immediately destroy an instance. Requires a signed message proving wallet ownership. The server is deleted from Hetzner.

Request body

FieldTypeRequiredDescription
wallet_addressstringyesOwner wallet address (0x-prefixed, 40 hex chars). Must match the wallet that spawned the instance.
signaturestringyesWallet signature of the message "machinemarket:delete:<instance_id>". Proves you own the wallet.

Response (200)

FieldTypeRequiredDescription
idstringyesInstance UUID.
statusstringyesAlways "destroyed".

Error codes

FieldTypeRequiredDescription
400noMissing wallet_address or signature.
403INVALID_SIGNATUREnoSignature does not match wallet.
404noInstance not found or wallet does not own it.
409noInstance already terminated.
502noFailed to delete server from provider.
curl
# Sign the message "machinemarket:delete:YOUR_INSTANCE_ID" with your wallet, then:
curl -X DELETE https://api.machinemarket.ai/v1/instances/YOUR_INSTANCE_ID \
  -H "Content-Type: application/json" \
  -d '{
    "wallet_address": "0x1234...5678",
    "signature": "0xabcd...ef01"
  }'
viem
typescript
import { privateKeyToAccount } from "viem/accounts";

const account = privateKeyToAccount(PRIVATE_KEY);
const instanceId = "YOUR_INSTANCE_ID";

// Sign the ownership proof
const signature = await account.signMessage({
  message: `machinemarket:delete:${instanceId}`,
});

const result = await mm.destroyInstance(instanceId, {
  wallet_address: account.address,
  signature,
});
console.log(result.status); // "destroyed"
POST/v1/instances/:id/extend

Extend an active instance with a new USDC payment. The paying wallet must match the wallet that spawned the instance. The new duration is added to the current expiry.

Request body

FieldTypeRequiredDescription
durationstringyes"1h" | "24h" | "7d" | "30d".
tx_hashstringyesTransaction hash of the extension payment.
wallet_addressstringyesSender wallet address. Must match the wallet that spawned the instance.

Response (200)

FieldTypeRequiredDescription
idstringyesInstance UUID.
expires_atstringyesNew ISO 8601 expiry.
extension_cost_usdcnumberyesCost of this extension.
total_cost_usdcnumberyesCumulative cost.

Error codes

FieldTypeRequiredDescription
400noInvalid parameters.
402PAYMENT_INVALIDnoPayment verification failed.
403NOT_OWNERnoWallet does not own this instance.
404noInstance not found.
409TX_DUPLICATEnoTransaction hash already used.
409noCan only extend active instances.
curl
curl -X POST https://api.machinemarket.ai/v1/instances/YOUR_ID/extend \
  -H "Content-Type: application/json" \
  -d '{
    "duration": "24h",
    "tx_hash": "0xdef...789",
    "wallet_address": "0x1234...5678"
  }'
SDK
typescript
const result = await mm.extendInstance("YOUR_ID", {
  duration: "24h",
  tx_hash: "0xdef...789",
  wallet_address: "0x1234...5678",
});
console.log("New expiry:", result.expires_at);
GET/v1/pricing

Get all available pricing tiers and durations.

Response (200)

FieldTypeRequiredDescription
tiersPricingTier[]yesArray of tier objects with name, vcpu, ram, storage, hourly/daily/monthly rates.
durationsDuration[]yesArray of duration objects with label, value, hours.
currencystringyesAlways "USDC".
chainstringyesAlways "Base".
curl
curl https://api.machinemarket.ai/v1/pricing
SDK
typescript
const pricing = await mm.getPricing();
pricing.tiers.forEach(t =>
  console.log(`${t.name}: $${t.hourly}/hr`)
);
GET/v1/regions

Get available deployment regions.

Response (200)

FieldTypeRequiredDescription
regionsRegionInfo[]yesArray of region objects with id, name, country, available.
defaultstringyesDefault region ID ("fsn1").
curl
curl https://api.machinemarket.ai/v1/regions
SDK
typescript
const regions = await mm.getRegions();
const available = regions.regions.filter(r => r.available);
console.log(available);
~Tip
See the SDK Reference for TypeScript type definitions and error handling patterns.