amnt docs
DevelopersREST API

Run an agent

POST /api/v1/run — the endpoint you will use most. Parameters, output shapes, status codes, refunds and timeouts.

POST https://www.amnt.io/api/v1/run

One POST runs any agent on the marketplace, charges your credits, pays the creator and returns the result.

Why one endpoint

The agent is named in the body, not the URL. Switching agents is a config change rather than a code change, and one rate limit and one retry policy covers everything you call.

Request body

FieldTypeDescription
agentstringrequiredThe agent to run, as handle/slug — the same two parts as its page URL. Case-insensitive
inputobjectrequiredThe agent's inputs, keyed by field name. Read the exact fields from the detail endpoint
Request
{
  "agent": "alice/product-description",
  "input": {
    "prompt": "a walnut desk lamp",
    "tone": "warm"
  }
}

Unknown keys are ignored, missing ones are not

Input is validated against the agent's published fields. A missing required field is a 400; a value that breaks a rule (too long, not one of the allowed choices) is a 422. Keys the creator never declared are dropped rather than passed through — an agent cannot be steered by a field that is not on its published list, including a raw prompt.

Most agents also accept extraInstructions: a free-text note appended to the creator's recipe. It is the one place to add something the fields do not cover.

Response

FieldTypeDescription
successbooleanCheck this, not the status code. A failed agent returns 200 with success: false and a refund already applied
outputobjectThe result. Shape depends on the agent — see below
credits_usedintegerWhat this run cost. 0 on failure and on free agents
credits_remainingintegerYour balance after the run
receiptobject | nullPresent only for agents that write to Hedera. Carries the transaction identifiers
errorstringPresent when success is false. Written to be shown to a person

Output shapes

An agent's connector decides the shape. Branch on what is present rather than assuming — a creator can republish an agent on a different connector.

Text
{
  "success": true,
  "output": { "kind": "text", "text": "Warm walnut, brushed brass..." },
  "credits_used": 3,
  "credits_remaining": 497
}
Images
{
  "success": true,
  "output": {
    "images": ["https://...supabase.co/storage/v1/object/public/..."]
  },
  "credits_used": 12,
  "credits_remaining": 485
}
Structured JSON
{
  "success": true,
  "output": { "kind": "json", "data": { "score": 82, "flags": [] } },
  "credits_used": 2,
  "credits_remaining": 483
}
On-chain
{
  "success": true,
  "output": { "kind": "receipt", "status": "SUCCESS", "transactionId": "0.0.123@176..." },
  "credits_used": 5,
  "credits_remaining": 478,
  "receipt": { "topicId": "0.0.4567", "sequence": 42 }
}
Failure
{
  "success": false,
  "error": "The model refused this request.",
  "credits_used": 0,
  "credits_remaining": 497
}

Image URLs

Images are stored by amnt and served over HTTPS — they are not temporary provider links that expire in an hour. Still, download anything you need to keep: an agent's gallery can be moderated by its owner.

Status codes

CodeWhat it meansWhat to do
200Request handled. Read success to know whether the agent workedBranch on success
400Bad JSON, missing agent, missing input, or a required field absentFix the payload. Nothing was charged
401Missing, malformed, invalid or revoked keySee Authentication
402Not enough creditsTop up. credits_required says how many the run needs
404No such agent, or it is not liveCheck handle/slug against the list endpoint
422A value broke one of the agent's declared rulesThe message names the field. Nothing was charged
429Rate limitedWait Retry-After seconds. See Rate limits
500The agent is misconfigured, or something broke on our sideRetry once. Nothing was charged
503The agent's owner could not be verified, so it will not runTemporary. This fails closed on purpose rather than paying the wrong account

Timeouts and long runs

  • Runs are synchronous — the connection stays open until the agent finishes. An image agent can take 30 to 90 seconds.
  • Set a client timeout of at least 180 seconds. Node's fetch has no default timeout at all and Python's requests has none either; neither default is what you want here.
  • If your client gives up, the run continues server-side and the charge stands. That is the one case where you can pay for a result you never read. More in Long runs and retries.

Retries are not free

There is no idempotency key yet. A retry is a second run and a second charge. Retry on 429, on 503, and on a network error — never blindly on success: false, which usually means the input was wrong and will fail again.

A complete client

TypeScript
type RunResult =
  | { success: true; output: unknown; credits_used: number; credits_remaining: number }
  | { success: false; error: string; credits_remaining: number };

export async function runAgent(
  agent: string,
  input: Record<string, unknown>,
): Promise<RunResult> {
  const res = await fetch("https://www.amnt.io/api/v1/run", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.AMNT_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ agent, input }),
    // Image agents routinely need a minute or more.
    signal: AbortSignal.timeout(180_000),
  });

  if (res.status === 429) {
    const wait = Number(res.headers.get("retry-after") ?? 60);
    await new Promise((r) => setTimeout(r, wait * 1000));
    return runAgent(agent, input);
  }

  if (!res.ok) {
    const body = await res.json().catch(() => ({}));
    throw new Error(body.error ?? `amnt returned ${res.status}`);
  }

  return res.json();
}
Python
import os, time, requests

BASE = "https://www.amnt.io/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['AMNT_API_KEY']}"}

def run_agent(agent: str, payload: dict, retries: int = 2):
    for attempt in range(retries + 1):
        res = requests.post(
            f"{BASE}/run",
            headers=HEADERS,
            json={"agent": agent, "input": payload},
            timeout=180,
        )

        if res.status_code == 429 and attempt < retries:
            time.sleep(int(res.headers.get("Retry-After", 60)))
            continue

        res.raise_for_status()
        data = res.json()

        if not data.get("success"):
            raise RuntimeError(data.get("error", "Agent run failed"))

        return data["output"]

    raise RuntimeError("Rate limited, gave up")

On this page