Interfaces
SDKs
Typed clients for JavaScript/TypeScript and Python, for the code around your agent: your backend, a CI job, a webhook receiver, an admin script.
Install
npm install @server4agent/sdkQuickstart
Both clients read your key from the SERVER4AGENT_API_KEY environment variable if you don't pass one explicitly. Every method maps 1:1 to a REST endpoint, the SDK just gives it a type.
import { Server4Agent } from "@server4agent/sdk";
// Reads SERVER4AGENT_API_KEY from the environment if you don't pass one.
const client = new Server4Agent();
const server = await client.servers.create({ task: "landing page builder" });
await client.tasks.create(
server.id,
"Build a waitlist landing page and deploy it.",
);Handling errors
Any non-2xx response raises Server4AgentError with the HTTP status, a machine-readable code, and the same message you'd get back over plain REST.
import { Server4AgentError } from "@server4agent/sdk";
try {
await client.servers.get("srv_does_not_exist");
} catch (err) {
if (err instanceof Server4AgentError) {
console.error(err.status, err.code, err.message); // 404 not_found "server not found"
}
}Verifying webhooks
Both clients export a verify_webhook_signature /verifyWebhookSignature helper that checks the Server4Agent-Signatureheader against your webhook's secret. Always verify against the raw request body, before you parse it as JSON, parsing and re-serializing changes the bytes and breaks the signature.
Real examples
Ephemeral preview environments in CI. Provision a real, disposable server per pull request, deploy the branch to it, and clean it up when the PR closes.
// Run from CI on every PR: give it a real, disposable URL, then tear it
// down when the PR closes. lifecycle: "ephemeral" marks it for cleanup.
import { Server4Agent } from "@server4agent/sdk";
const client = new Server4Agent();
const prNumber = process.env.PR_NUMBER!;
const server = await client.servers.create({ task: `pr-${prNumber}` });
const project = await client.projects.create(server.id, {
name: `pr-${prNumber}`,
visibility: "public",
lifecycle: "ephemeral",
});
await client.tasks.create(
server.id,
"Install dependencies, build the app, and deploy it.",
);
console.log(`Preview: ${project.url}`);
// On PR close: await client.projects.cleanup(project.id);A webhook receiver that reacts to deployments. Subscribe once (see Webhooks), then verify and act on each delivery.
import express from "express";
import { verifyWebhookSignature } from "@server4agent/sdk";
const app = express();
app.post("/hooks/server4agent", express.text({ type: "*/*" }), async (req, res) => {
// req.body must be the raw string — verify before you JSON.parse it.
const ok = await verifyWebhookSignature(
process.env.SERVER4AGENT_WEBHOOK_SECRET!,
req.body,
req.header("Server4Agent-Signature"),
);
if (!ok) return res.status(401).end();
const event = JSON.parse(req.body);
if (event.event === "deployment.live") {
await notifySlack(`Deployed: ${event.url}`);
}
res.status(200).end();
});Per-customer workspaces from your own product. If you're building a product where a customer action should provision a real environment, that's your backend calling the SDK directly, no agent tool-calling loop involved.
# Your product's backend, not an agent: a customer submits a request,
# your own business logic decides what to build, and you provision a
# real workspace for them on demand.
from server4agent import Server4Agent
client = Server4Agent()
def provision_for_customer(customer_id: str, goal: str) -> str:
server = client.servers.create(task=f"customer-{customer_id}")
project = client.projects.create(
server.id,
name=f"{customer_id}-workspace",
visibility="public",
template="dashboard",
)
client.tasks.create(server.id, goal)
return project.urlScoping a key before handing it to another tool. Mint a key restricted to one server (or project) instead of sharing your account-wide key.
// Hand a support tool a key that can only touch one customer's server,
// not your whole account.
const supportKey = await client.keys.create("support-tool");
await client.keys.updateScope(supportKey.id, {
allowedServerIds: [server.id],
});
// supportKey.key is the plaintext — shown once, here. Hand it to the tool
// and store it on your side if you'll need to revoke it later by id.Source
Both SDKs are open source in the sdk/js and sdk/python directories of the Server4Agent repository, alongside their test suites. Every method wraps one of the endpoints on the REST API page, if a method's behavior is ever unclear, that page has the underlying request/response shape.