---
title: "Create a new agent (deploy a pod)."
method: POST
path: "/agents"
tags: ["Agents"]
---

# Create a new agent (deploy a pod).

`POST /agents`

## Request

- Base URL: `https://agentspodium.com/api`
- URL: `https://agentspodium.com/api/agents`
- Auth: HTTP bearer

Call once to provision a pod. The call is synchronous and returns once the pod exists, typically within one to two minutes — the engine inside may need a few more seconds, which GET /agents/{id}/liveness tells you. Follow with PATCH /agents/{id}/llm-key: a fresh pod has no model key and answers nothing until one is set.

## Request body

- object
  - `personaId` string, required: Any id from GET /personas.
  - `tier` 'tiny' | 'small' | 'medium' | 'large', required: Must satisfy the chosen engine's minTier.
  - `name` string: Up to 60 chars; the pod's hostnames are derived from it.
  - `channels` string[]: Default ["web"].
  - `lang` 'en' | 'ru'
  - `skills` string[]
  - `extraSoul` string: Owner instructions appended to the persona's SOUL.
  - `soul` string
  - `domain` string: Your own hostname, e.g. agent.example.com. Names under agentspodium.com are assigned automatically and refused here.
  - `tools` object
    - `enabled` string[]
    - `mcpServers` McpServerConfig[]
      - `name` string, required: Unique server name; used as the server:tool prefix in Hermes.
      - `command` string: Stdio transport: executable to spawn.
      - `args` string[]
      - `env` object
      - `url` string, uri: HTTP transport: MCP endpoint URL.
      - `headers` object
  - `engine` 'hermes' | 'openclaw' | 'n8n' | 'claude-code' | 'opencode' | 'pi': Default hermes.
  - `model` string
  - `webhookUrl` string: Public http(s) URL to POST pod events to. The signing secret comes back once as `webhookSecret` beside `agent`.
  - `app` AppConfig: Build and run configuration for engine "app": a customer repository served as frontend plus backend on one pod.
    - `repo` string, required: Public https git URL. Private repositories need repoToken on create.
    - `branch` string, required
    - `runtime` 'node' | 'python' | 'go' | 'static' | 'docker' | 'null', nullable: Omit and the pod detects it from the repository.
    - `buildCommand` string, nullable
    - `outputDir` string, nullable: Static output, relative to rootDir; null means no static half.
    - `startCommand` string, nullable: Backend process; null means a static-only app.
    - `appPort` integer, required: Port the backend listens on inside the pod.
    - `apiPrefix` string, required: Paths routed to the backend; everything else is served from outputDir.
    - `env` object: Environment variables for the app. Not for secrets.
    - `rootDir` string, nullable: Directory inside the repository where the build runs. For a monorepo whose app is not at the root. Netlify calls this "base".
    - `repoUser` string, nullable: Username paired with repoToken when the host wants one. Left out, we use what the host expects: x-access-token for GitHub, oauth2 for GitLab, the token alone for Gitea and Forgejo.

## Response `200`

Created — the pod exists and status is "running" (the engine inside may still be booting).

- object
  - `agent` Agent, required: One pod. Serialized with the engine encryption key and the plaintext-adjacent LLM key ciphertext stripped; every other stored field is returned as is.
    - `id` string, required
    - `userId` string, required
    - `personaId` string, required
    - `name` string, required
    - `tier` 'tiny' | 'small' | 'medium' | 'large', required
    - `channels` string[], required
    - `createdAt` string, date-time, required: The free trial is counted from here.
    - `status` 'provisioning' | 'running' | 'stopped' | 'failed' | 'deleted', required
    - `dseq` string, nullable, required: Akash deployment sequence (the pod's namespace), set after a successful deploy.
    - `endpointUrl` string, uri, nullable, required: The engine's own public URL/dashboard.
    - `llmKeyHash` string, nullable, required: sha256 of the configured LLM key; set once a key is installed.
    - `dashUsername` string, nullable, required: Login for the engine's own dashboard, when the engine has one.
    - `dashPassword` string, nullable, required
    - `quotaStatus` 'ok' | 'warn' | 'grace' | 'paused', required
    - `quota` AgentQuota, required: Latest RAM/disk snapshot for a pod, refreshed about once a minute from the cluster.
      - `memoryUsedBytes` integer, nullable, required
      - `memoryLimitBytes` integer, nullable, required
      - `memoryPct` number, nullable, required: memoryUsedBytes / memoryLimitBytes, or null when either side is unknown.
      - `diskUsedBytes` integer, nullable, required
      - `diskTotalBytes` integer, nullable, required
      - `diskPct` number, nullable, required
      - `status` 'ok' | 'warn' | 'grace' | 'paused', required: paused means the pod was auto-stopped for exceeding its plan.
      - `updatedAt` string, date-time, required
    - `lang` 'en' | 'ru', required: Propagated into the persona's SOUL.
    - `domain` string, nullable, required: The customer's own hostname if set, otherwise null (the pod still answers at <a2aSlug>.agentspodium.com).
    - `tools` AgentTools, required: Enabled Hermes toolsets and user-defined MCP servers.
      - `enabled` string[], required: Toolset ids from GET /tools; empty means the safe minimal set.
      - `mcpServers` McpServerConfig[], required
        - `name` string, required: Unique server name; used as the server:tool prefix in Hermes.
        - `command` string: Stdio transport: executable to spawn.
        - `args` string[]
        - `env` object
        - `url` string, uri: HTTP transport: MCP endpoint URL.
        - `headers` object
    - `llmProvider` 'openai' | 'anthropic' | 'openrouter' | 'google' | 'gemini' | 'groq' | 'mistral' | 'deepseek' | 'xai' | 'nous' | 'null', nullable, required
    - `lastBackupAt` string, date-time, nullable, required
    - `model` string, nullable, required: Model catalog id, e.g. anthropic:claude-sonnet-4-5.
    - `engine` 'hermes' | 'openclaw' | 'n8n' | 'claude-code' | 'opencode' | 'pi', required
    - `timezone` string, nullable, required: IANA zone, e.g. Europe/Berlin. Null means the pod's UTC default.
    - `a2aToken` string, nullable, required: Bearer peers must send to this agent's A2A endpoint. Null when the a2a toolset is off.
    - `a2aUrl` string, uri, nullable, required
    - `extraSoul` string, nullable, required: The owner's own additions appended to the persona's SOUL.
    - `a2aPeers` A2aPeerPublic[], nullable, required
      - `name` string, required
      - `url` string, uri, required
    - `a2aSlug` string, nullable, required: Stable label every one of this agent's hostnames is built from.
    - `trialNoticeDay` integer, nullable, required: Which trial reminder has already gone out: 3, 2, 1, or 0 for paused.
    - `telegramTokenEnc` string, nullable, required: "set" when a Telegram bot token is stored for this agent, otherwise null. The token itself never leaves the server.
    - `a2aListed` boolean, required: Whether the owner opted into the public A2A catalog (GET /a2a-catalog).
    - `webhookUrl` string, nullable: Receiver for pod events, or null. Set with PUT /agents/{id}/webhook or `webhookUrl` on create.
    - `webhookLastStatus` string, nullable: Outcome of the latest delivery: the HTTP status (`200`) or `error: …`.
    - `webhookLastAt` string, date-time, nullable
    - `webhookLastEvent` string, nullable: Type of the latest delivered event.
    - `app` AppConfig: Build and run configuration for engine "app": a customer repository served as frontend plus backend on one pod.
      - `repo` string, required: Public https git URL. Private repositories need repoToken on create.
      - `branch` string, required
      - `runtime` 'node' | 'python' | 'go' | 'static' | 'docker' | 'null', nullable: Omit and the pod detects it from the repository.
      - `buildCommand` string, nullable
      - `outputDir` string, nullable: Static output, relative to rootDir; null means no static half.
      - `startCommand` string, nullable: Backend process; null means a static-only app.
      - `appPort` integer, required: Port the backend listens on inside the pod.
      - `apiPrefix` string, required: Paths routed to the backend; everything else is served from outputDir.
      - `env` object: Environment variables for the app. Not for secrets.
      - `rootDir` string, nullable: Directory inside the repository where the build runs. For a monorepo whose app is not at the root. Netlify calls this "base".
      - `repoUser` string, nullable: Username paired with repoToken when the host wants one. Left out, we use what the host expects: x-access-token for GitHub, oauth2 for GitLab, the token alone for Gitea and Forgejo.
    - `appRepoTokenEnc` 'set' | 'null', nullable: "set" when a private-repository token is stored; the token itself never leaves the server.
  - `webhookSecret` string: Only when `webhookUrl` was given: the HMAC secret for verifying deliveries. Shown once.

## Other responses

- `400`: Bad request — the body failed validation.
- `401`: Missing, invalid, expired, or revoked credential.

---

[API](https://skmtc.dev/defispace/apis/agentspodium-account-api-agent-facing-subset.md) · [All operations](https://skmtc.dev/defispace/apis/agentspodium-account-api-agent-facing-subset/llms.txt) · [OpenAPI document](https://skmtc.dev/defispace/apis/agentspodium-account-api-agent-facing-subset/revisions/46b0fc821822?raw)
