Developers
Code examples
A typed TypeScript client, a Python helper, batching, a Next.js proxy route, and shell one-liners.
Copy-paste starting points. Each one handles the three things that actually
bite: the timeout, the 429, and success: false.
A small TypeScript client
const BASE = "https://www.amnt.io/api/v1";
export class AmntError extends Error {
constructor(message: string, readonly status: number) {
super(message);
}
}
async function call(path: string, init: RequestInit = {}) {
const res = await fetch(BASE + path, {
...init,
headers: {
Authorization: `Bearer ${process.env.AMNT_API_KEY}`,
"Content-Type": "application/json",
...init.headers,
},
// Image agents can take well over a minute.
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 call(path, init);
}
const body = await res.json().catch(() => ({}));
if (!res.ok) throw new AmntError(body.error ?? `HTTP ${res.status}`, res.status);
return body;
}
export const amnt = {
run: async (agent: string, input: Record<string, unknown>) => {
const body = await call("/run", { method: "POST", body: JSON.stringify({ agent, input }) });
// A failed agent is a 200. This is the line everyone forgets.
if (!body.success) throw new AmntError(body.error ?? "Agent run failed", 200);
return body;
},
list: (params: Record<string, string> = {}) =>
call("/agents?" + new URLSearchParams(params)),
get: (agent: string) => call(`/agents/${agent}`),
balance: () => call("/balance"),
};Python
import os, time, requests
BASE = "https://www.amnt.io/api/v1"
class AmntError(RuntimeError):
pass
def _session() -> requests.Session:
s = requests.Session()
s.headers.update({"Authorization": f"Bearer {os.environ['AMNT_API_KEY']}"})
return s
def run(agent: str, payload: dict, retries: int = 2) -> dict:
s = _session()
for attempt in range(retries + 1):
res = s.post(f"{BASE}/run", 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
if res.status_code == 402:
body = res.json()
raise AmntError(
f"Out of credits: need {body['credits_required']}, have {body['credits_remaining']}"
)
res.raise_for_status()
body = res.json()
if not body.get("success"):
raise AmntError(body.get("error", "Agent run failed"))
return body
raise AmntError("Rate limited, gave up")A Next.js route that proxies an agent
The pattern that keeps your key server-side: your front end calls your route, your route calls amnt.
export async function POST(req: Request) {
const { product } = await req.json();
const res = await fetch("https://www.amnt.io/api/v1/run", {
method: "POST",
headers: {
// Server-side only. Never NEXT_PUBLIC_ anything.
Authorization: `Bearer ${process.env.AMNT_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
agent: "alice/product-description",
input: { prompt: product },
}),
});
const body = await res.json();
if (!res.ok || !body.success) {
// Do not leak our error text straight to the browser.
return Response.json({ error: "Could not write that description." }, { status: 502 });
}
return Response.json({ text: body.output.text });
}Running a batch without hitting the limit
const products = ["walnut desk lamp", "brushed steel kettle", "linen throw"];
const results = [];
for (const product of products) {
const { output, credits_remaining } = await amnt.run("alice/product-description", {
prompt: product,
});
results.push(output.text);
// Stop before the balance does, rather than after.
if (credits_remaining < 10) {
console.warn("Low balance - stopping at", results.length, "of", products.length);
break;
}
await new Promise((r) => setTimeout(r, 1000));
}Why sequential
Parallel calls are allowed, but a run holds a connection for as long as the agent takes. Ten at once means ten open sockets and a bill that arrives ten times faster. Sequential with a small delay is easier to reason about and easier to stop.
Shell
curl -s -X POST https://www.amnt.io/api/v1/run \
-H "Authorization: Bearer $AMNT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"agent":"alice/product-description","input":{"prompt":"a walnut desk lamp"}}' \
| jq -r '.output.text'curl -s -X POST https://www.amnt.io/api/v1/run \
-H "Authorization: Bearer $AMNT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"agent":"studio/logo-mark","input":{"prompt":"a fox, minimal"}}' \
| jq -r '.output.images[]' \
| xargs -n1 -I{} curl -sO {}curl -s https://www.amnt.io/api/v1/balance \
-H "Authorization: Bearer $AMNT_API_KEY" | jq -r '.credits'