Skip to content
LogoLogo

Deploy Flow

The MPP deploy flow uses HTTP 402 responses to communicate payment requirements. The agent calls the deploy endpoint, handles the 402, pays on-chain, and retries.

Step 1: Request Deploy (Get Quote)

Call POST /agent/deploy without a payment header. The gateway checks your credit balance and active projects:

POST /agent/deploy
Content-Type: application/json
X-Wallet-Address: 0x...
X-Signature: 0x...
X-Timestamp: 1711500000000
X-Nonce: unique-uuid

{
  "uniqueName": "my-app",
  "displayName": "My App",
  "upload": {
    "type": "files",
    "files": [
      { "path": "index.js", "content": "base64..." },
      { "path": "package.json", "content": "base64..." }
    ]
  }
}

Response Cases

Has credits, no active projects - deploys immediately (200):

{ "projectId": "uuid", "deploymentId": "uuid", "status": "deploying" }

Has credits, active projects exist - returns 402 with a warning:

{
  "error": "Payment required",
  "warning": "You have 2 active project(s) sharing credits...",
  "amount_usd": 0.5,
  "current_credit_balance_usd": 1.20,
  "active_projects": 2,
  "pay_to": "0x7EA5...",
  "payment_chain": "arbitrum",
  "token": "usdc",
  "decimals": 6,
  "supported_chains": [...]
}

To deploy using existing credits (reduces runtime of other projects), retry with header X-Use-Existing-Credits: true.

No credits - returns 402 with payment details:

{
  "error": "Payment required",
  "amount_usd": 0.5,
  "amount_token": "500000",
  "current_credit_balance_usd": 0,
  "active_projects": 0,
  "pay_to": "0x7EA5...",
  "payment_chain": "arbitrum",
  "token": "usdc",
  "decimals": 6,
  "supported_chains": [
    { "chain": "arbitrum", "chain_id": 42161, "tokens": ["usdc", "usdt"] },
    { "chain": "base", "chain_id": 8453, "tokens": ["usdc", "usdt"] }
  ]
}

Step 2: Check Balance

Before paying, verify the wallet has enough tokens:

GET /agent/balance/0xYourWallet?chain=arbitrum
{
  "address": "0x...",
  "chain": "arbitrum",
  "balances": [
    { "token": "usdc", "symbol": "USDC", "balance": "18.000000", "decimals": 6 }
  ]
}

If the balance is insufficient, prompt the user to fund the wallet on one of the supported chains.

Step 3: Pay On-Chain

Send an ERC20 transfer to the pay_to address from the 402 response:

import { createWalletClient, createPublicClient, http } from "viem";
import { arbitrum } from "viem/chains";
 
const ERC20_ABI = [
  {
    name: "transfer",
    type: "function",
    stateMutability: "nonpayable",
    inputs: [
      { name: "to", type: "address" },
      { name: "value", type: "uint256" },
    ],
    outputs: [{ name: "", type: "bool" }],
  },
] as const;
 
const txHash = await walletClient.writeContract({
  address: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", // USDC on Arbitrum
  abi: ERC20_ABI,
  functionName: "transfer",
  args: [quote.pay_to, BigInt(quote.amount_token)],
});
 
await publicClient.waitForTransactionReceipt({ hash: txHash });

Step 4: Deploy with Payment Proof

Retry the deploy request with the transaction hash:

POST /agent/deploy
Content-Type: application/json
X-Payment-Tx: 0xTransactionHash
X-Payment-Chain: arbitrum
X-Payment-Token: usdc
X-Wallet-Address: 0x...
X-Signature: 0x...
X-Timestamp: 1711500000000
X-Nonce: new-unique-uuid

Same body as Step 1. Response:

{ "projectId": "uuid", "deploymentId": "uuid", "status": "deploying" }

Step 5: Poll Status

Poll the status endpoint every 5 seconds until the deployment is ready:

GET /agent/deploy/{projectId}/{deploymentId}/status

Possible responses:

StatusMeaning
deployingBuild/deploy in progress
readyLive at endpoint URL
failedDeployment failed with reason
{ "status": "ready", "endpoint": "https://my-app.nodeops.network" }

Upload Types

Files - array of base64-encoded files:

{
  "type": "files",
  "files": [
    { "path": "index.js", "content": "base64..." },
    { "path": "package.json", "content": "base64..." }
  ]
}

Zip - base64-encoded zip archive:

{
  "type": "zip",
  "data": "base64-zip-content",
  "filename": "code.zip"
}

Exclude from uploads: node_modules/, dist/, build/, .next/, .env, .git/, __pycache__/, venv/