> ## Documentation Index
> Fetch the complete documentation index at: https://pinata-mintlify-5df45191.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Pinata Agents HTTP API reference

> Authenticate, manage AI agents, run commands, and talk to gateways over the Pinata Agents HTTP API with examples for every endpoint.

The Agents API is the same API the dashboard uses. Everything in the UI is exposed at `agents.pinata.cloud` - including agent management, secrets, skills, channels, snapshots, custom domains, devices, and engine runtime config.

Full OpenAPI reference: [agents.pinata.cloud/openapi](https://agents.pinata.cloud/openapi) (also linked from the Support → OpenAPI Docs item in the sidebar).

## Base URLs

There are two surfaces, on purpose:

| Surface        | Host                            | Auth          | What it's for                                              |
| -------------- | ------------------------------- | ------------- | ---------------------------------------------------------- |
| **Management** | `agents.pinata.cloud`           | Pinata JWT    | Creating agents, managing secrets, browsing templates      |
| **Per-agent**  | `{agentId}.agents.pinata.cloud` | Gateway token | Talking to a specific agent (chat, routes, files, devices) |

The same agent sub-routes (`/v0/agents/{agentId}/...`) are mounted on both. Use the management host when you have the workspace owner's JWT; use the per-agent host when you only have the gateway token.

## Authentication

Three credentials, used in different contexts:

### Pinata JWT

Standard Pinata API key (`bearerAuth` in the OpenAPI spec). Used for all management routes (`/v0/agents`, `/v0/secrets`, `/v0/skills`, `/v0/templates`, etc.).

```http theme={null}
Authorization: Bearer <PINATA_JWT>
```

Create one in your [Account → API Keys](/account-management/api-keys).

### Gateway token

Per-agent token (`gatewayToken` in the OpenAPI spec) used for the agent's own subdomain. Read it from the agent's **Danger** page or `GET /v0/agents/{agentId}/gateway-token`. Rotate it from the same page or `POST /v0/agents/{agentId}/gateway-token/rotate`.

Passing the gateway token:

```http theme={null}
Authorization: Bearer <GATEWAY_TOKEN>
```

```http theme={null}
?token=<GATEWAY_TOKEN>
```

```http theme={null}
Cookie: gw_token=<GATEWAY_TOKEN>
```

<Warning>
  The gateway token grants full access to the agent's container - console, files, routes, everything. Treat it like a server credential.
</Warning>

### Git Basic auth

Used only by the Git Smart HTTP endpoints (`/v0/agents/{agentId}/git/...`). Sent as HTTP Basic auth - username is ignored, password is the gateway token. The **Copy with Token** button on the Files tab embeds this for you.

### Platform JWT (for skills)

Inside an agent, the `@pinata/platform` skill can exchange the gateway token for a short-lived (1 hour) platform JWT. That JWT then unlocks the management-domain API (create secrets, install skills, etc.) on the agent's behalf - so an agent can self-modify without ever seeing the user's Pinata JWT.

```bash theme={null}
# From inside the agent container:
curl -X POST \
  -H "Authorization: Bearer $GATEWAY_TOKEN" \
  https://{agentId}.agents.pinata.cloud/v0/platform/token
```

## Quick Examples

All examples below use `PINATA_JWT` (from `https://app.pinata.cloud`) or `GATEWAY_TOKEN` (from the agent's Danger page).

### List your agents

```bash theme={null}
curl -H "Authorization: Bearer $PINATA_JWT" \
  https://agents.pinata.cloud/v0/agents
```

### Create an agent

```bash theme={null}
curl -X POST \
  -H "Authorization: Bearer $PINATA_JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "My Agent",
    "description": "Personal assistant",
    "emoji": "🤖",
    "engine": "openclaw",
    "skillCids": ["@pinata/api"],
    "secretIds": ["secret-id-1"]
  }' \
  https://agents.pinata.cloud/v0/agents
```

`engine` is optional and defaults to `openclaw`. Pass `hermes` for the opinionated engine — see [Concepts → Engine](/agents/concepts#engine). For chat-oriented engines, the dashboard exposes channel setup during create, and engines that support create-time channel bootstrap can accept a `channels` object on this request so Telegram, Slack, or Discord come up with the agent without a post-create gateway restart. Each channel object accepts:

| Field       | Type             |      Required      | Notes                                                                       |
| ----------- | ---------------- | :----------------: | --------------------------------------------------------------------------- |
| `botToken`  | string           | yes (all channels) | Bot token from the platform. Slack uses the `xoxb-` bot token.              |
| `appToken`  | string           |  yes (Slack only)  | Slack `xapp-` app-level token for Socket Mode.                              |
| `dmPolicy`  | string           |      optional      | `open` (anyone can DM) or `pairing` (must be approved). Defaults to `open`. |
| `allowFrom` | array of strings |      optional      | Allow-list of platform user IDs that can DM the bot.                        |

These are the same fields accepted by the per-channel `POST /v0/agents/{agentId}/channels/{channel}` endpoint and by `channels` in [`manifest.json`](/agents/manifest#channels).

To list engines enabled for the current deployment:

```bash theme={null}
curl -H "Authorization: Bearer $PINATA_JWT" \
  https://agents.pinata.cloud/v0/agents/engines
```

Returns `{ "engines": [ { "id": "openclaw", "label": "OpenClaw" }, { "id": "hermes", "label": "Hermes" } ] }`, depending on which engines are enabled for the deployment.

Returns `201` with the created agent. Returns `403` if you're at the agent limit.

### Get agent details

```bash theme={null}
curl -H "Authorization: Bearer $PINATA_JWT" \
  https://agents.pinata.cloud/v0/agents/$AGENT_ID
```

Response includes `agent`, `processStatus`, `skills`, `secrets`, `snapshots`, and `portForwarding`.

### Restart the gateway

```bash theme={null}
curl -X POST \
  -H "Authorization: Bearer $PINATA_JWT" \
  https://agents.pinata.cloud/v0/agents/$AGENT_ID/restart
```

### Run a shell command

```bash theme={null}
curl -X POST \
  -H "Authorization: Bearer $PINATA_JWT" \
  -H "Content-Type: application/json" \
  -d '{"command":"ls workspace","cwd":"/home/node/clawd"}' \
  https://agents.pinata.cloud/v0/agents/$AGENT_ID/console/exec
```

Returns `{ stdout, stderr, exitCode, command, timestamp }`.

### Read a file

```bash theme={null}
curl -H "Authorization: Bearer $PINATA_JWT" \
  "https://agents.pinata.cloud/v0/agents/$AGENT_ID/files?path=workspace/IDENTITY.md"
```

### Upload a file

```bash theme={null}
curl -X POST \
  -H "Authorization: Bearer $PINATA_JWT" \
  -H "Content-Type: application/json" \
  -d "{\"filename\":\"report.pdf\",\"contentBase64\":\"$(base64 -w0 < report.pdf)\"}" \
  https://agents.pinata.cloud/v0/agents/$AGENT_ID/files/upload
```

Returns `{ path, filename, size }`. File limit matches the read endpoint (a few MB).

### Snapshot now

```bash theme={null}
curl -X POST \
  -H "Authorization: Bearer $PINATA_JWT" \
  https://agents.pinata.cloud/v0/agents/$AGENT_ID/snapshots/sync
```

### Reset to a snapshot

```bash theme={null}
curl -X POST \
  -H "Authorization: Bearer $PINATA_JWT" \
  -H "Content-Type: application/json" \
  -d '{"snapshotCid":"QmXyz..."}' \
  https://agents.pinata.cloud/v0/agents/$AGENT_ID/snapshots/reset
```

### Read the latest logs

```bash theme={null}
curl -H "Authorization: Bearer $PINATA_JWT" \
  https://agents.pinata.cloud/v0/agents/$AGENT_ID/logs
```

Returns the last 100 lines as a single string.

### Validate manifest / config

```bash theme={null}
curl -X POST \
  -H "Authorization: Bearer $PINATA_JWT" \
  -H "Content-Type: application/json" \
  -d "{\"config\":$(jq -Rs . < manifest.json)}" \
  https://agents.pinata.cloud/v0/agents/$AGENT_ID/config/validate
```

## Files

| Endpoint                                 | Method         | Notes                                                                               |
| ---------------------------------------- | -------------- | ----------------------------------------------------------------------------------- |
| `/v0/agents/{agentId}/files?path=<path>` | `GET`          | Read any file from the container                                                    |
| `/v0/agents/{agentId}/files/upload`      | `POST`         | Upload a base64 file into `<workspace>/uploads/` (max \~few MB, `413` if too large) |
| `/v0/agents/{agentId}/snapshots`         | `GET`          | Latest 10 snapshots                                                                 |
| `/v0/agents/{agentId}/snapshots/sync`    | `GET` / `POST` | Get sync status / take a snapshot now                                               |
| `/v0/agents/{agentId}/snapshots/reset`   | `POST`         | Reset to a specific snapshot CID                                                    |

## Custom Domains

| Endpoint                                         | Method           | Notes                                              |
| ------------------------------------------------ | ---------------- | -------------------------------------------------- |
| `/v0/agents/{agentId}/domains`                   | `GET`            | List subdomains and custom domains                 |
| `/v0/agents/{agentId}/domains`                   | `POST`           | Register a subdomain or custom domain              |
| `/v0/agents/{agentId}/domains/challenge`         | `POST`           | Get the TXT verification value for a custom domain |
| `/v0/agents/{agentId}/domains/{domainId}`        | `PUT` / `DELETE` | Update port/protected or remove                    |
| `/v0/agents/{agentId}/domains/{domainId}/verify` | `POST`           | Verify ownership and provision SSL                 |

See [Routes & Domains](/agents/routes) for the full workflow.

## Devices

| Endpoint                                           | Method | Notes                             |
| -------------------------------------------------- | ------ | --------------------------------- |
| `/v0/agents/{agentId}/devices`                     | `GET`  | List pending and paired devices   |
| `/v0/agents/{agentId}/devices/{requestId}/approve` | `POST` | Approve a specific device         |
| `/v0/agents/{agentId}/devices/approve-all`         | `POST` | Bulk-approve every pending device |

## Streaming logs

The Logs tab streams over WebSocket on the agent's subdomain:

```
wss://{agentId}.agents.pinata.cloud/v0/logs?token=<GATEWAY_TOKEN>
```

Each message is a JSON object: `{ timestamp, level, source, message }`. Filter on the client by `level` (`TRACE` ... `FATAL`) and free-text on `message`.

## Error Format

Errors return JSON with a single `error` field:

```json theme={null}
{ "error": "Validation failed: skills exceeds maximum of 10" }
```

Status codes follow HTTP semantics - `400` for validation, `401` for missing auth, `403` for plan/permission issues, `404` for missing resources, `409` for conflicts (duplicate secret name, both subdomain and customDomain provided, etc.), `413` for upload size, `500` for internal failures, `503` when an upstream (Convex, Pinata storage) is unreachable.

See [Errors](/agents/errors) for the full code-by-code reference.

## Endpoint Quick Reference

Compact index of every endpoint, grouped by purpose. `JWT` = Pinata JWT, `GW` = gateway token (per-agent host). All paths under `agents.pinata.cloud`.

### Agents

| Method   | Path                                            |   Auth   | Description                                         |
| -------- | ----------------------------------------------- | :------: | --------------------------------------------------- |
| `GET`    | `/v0/agents`                                    |    JWT   | List your agents                                    |
| `POST`   | `/v0/agents`                                    |    JWT   | Create an agent                                     |
| `GET`    | `/v0/agents/{agentId}`                          | JWT / GW | Agent detail (skills, secrets, snapshots, routes)   |
| `DELETE` | `/v0/agents/{agentId}`                          |    JWT   | Delete the agent                                    |
| `POST`   | `/v0/agents/{agentId}/restart`                  | JWT / GW | Restart the gateway                                 |
| `GET`    | `/v0/agents/{agentId}/logs`                     | JWT / GW | Last 100 log lines                                  |
| `GET`    | `/v0/agents/engines`                            |    JWT   | List available engines (`openclaw`, `hermes`, etc.) |
| `GET`    | `/v0/agents/{agentId}/available-agent-versions` | JWT / GW | Versions you can upgrade to                         |
| `POST`   | `/v0/agents/{agentId}/scripts/retry`            | JWT / GW | Re-run `build` then `start`                         |
| `GET`    | `/v0/agents/{agentId}/update`                   | JWT / GW | Check for OpenClaw updates                          |
| `POST`   | `/v0/agents/{agentId}/update`                   | JWT / GW | Apply an OpenClaw update                            |

### Auth

| Method | Path                                        | Auth | Description                                  |
| ------ | ------------------------------------------- | :--: | -------------------------------------------- |
| `GET`  | `/v0/agents/{agentId}/gateway-token`        |  JWT | Get the current gateway token                |
| `POST` | `/v0/agents/{agentId}/gateway-token/rotate` |  JWT | Rotate it                                    |
| `POST` | `/v0/agents/{agentId}/platform/token`       |  GW  | Exchange gateway token for a 1h platform JWT |
| `GET`  | `/v0/agents/{agentId}/platform/whoami`      |  GW  | Agent's own identity                         |

### Secrets

| Method   | Path                                      |   Auth   | Description                         |
| -------- | ----------------------------------------- | :------: | ----------------------------------- |
| `GET`    | `/v0/secrets`                             |    JWT   | List your secrets                   |
| `POST`   | `/v0/secrets`                             |    JWT   | Create a secret                     |
| `PUT`    | `/v0/secrets/{id}`                        |    JWT   | Update value                        |
| `DELETE` | `/v0/secrets/{id}`                        |    JWT   | Delete                              |
| `POST`   | `/v0/agents/{agentId}/secrets`            | JWT / GW | Attach existing secrets to an agent |
| `DELETE` | `/v0/agents/{agentId}/secrets/{secretId}` | JWT / GW | Detach a secret                     |

### Skills

| Method   | Path                                           |   Auth   | Description                        |
| -------- | ---------------------------------------------- | :------: | ---------------------------------- |
| `GET`    | `/v0/skills`                                   |    JWT   | List your installed skills         |
| `POST`   | `/v0/skills`                                   |    JWT   | Register a new skill from a folder |
| `GET`    | `/v0/skills/{skillId}/versions`                |    JWT   | List versions                      |
| `POST`   | `/v0/skills/{skillId}/versions`                |    JWT   | Publish a new version              |
| `DELETE` | `/v0/skills/{skillCid}`                        |    JWT   | Remove from library                |
| `GET`    | `/v0/clawhub`                                  |    JWT   | Browse the community hub           |
| `GET`    | `/v0/clawhub/{slug}`                           |    JWT   | Hub skill detail                   |
| `POST`   | `/v0/clawhub/{hubSkillId}/install`             |    JWT   | Install a hub skill                |
| `GET`    | `/v0/agents/{agentId}/skills`                  | JWT / GW | Skills attached to this agent      |
| `POST`   | `/v0/agents/{agentId}/skills`                  | JWT / GW | Attach                             |
| `DELETE` | `/v0/agents/{agentId}/skills/{skillId}`        | JWT / GW | Detach                             |
| `GET`    | `/v0/agents/{agentId}/skills/updates`          | JWT / GW | Check for skill updates            |
| `POST`   | `/v0/agents/{agentId}/skills/{skillId}/update` | JWT / GW | Bump a skill on this agent         |

### Channels

| Method   | Path                                      |   Auth   | Description                                         |
| -------- | ----------------------------------------- | :------: | --------------------------------------------------- |
| `GET`    | `/v0/agents/{agentId}/channels`           | JWT / GW | Status of all channels                              |
| `POST`   | `/v0/agents/{agentId}/channels/{channel}` | JWT / GW | Configure (`telegram`/`slack`/`discord`/`whatsapp`) |
| `DELETE` | `/v0/agents/{agentId}/channels/{channel}` | JWT / GW | Remove                                              |

### Routes & domains

| Method   | Path                                             |   Auth   | Description                           |
| -------- | ------------------------------------------------ | :------: | ------------------------------------- |
| `GET`    | `/v0/agents/{agentId}/port-forwarding`           | JWT / GW | List path routes                      |
| `PUT`    | `/v0/agents/{agentId}/port-forwarding`           | JWT / GW | Replace path routes                   |
| `GET`    | `/v0/agents/{agentId}/domains`                   | JWT / GW | List domains and subdomains           |
| `POST`   | `/v0/agents/{agentId}/domains`                   | JWT / GW | Register a subdomain or custom domain |
| `POST`   | `/v0/agents/{agentId}/domains/challenge`         | JWT / GW | Get TXT challenge for a custom domain |
| `PUT`    | `/v0/agents/{agentId}/domains/{domainId}`        | JWT / GW | Update port/protected                 |
| `DELETE` | `/v0/agents/{agentId}/domains/{domainId}`        | JWT / GW | Remove                                |
| `POST`   | `/v0/agents/{agentId}/domains/{domainId}/verify` | JWT / GW | Verify ownership + provision SSL      |

### Tasks

| Method   | Path                                        |   Auth   | Description      |
| -------- | ------------------------------------------- | :------: | ---------------- |
| `GET`    | `/v0/agents/{agentId}/tasks`                | JWT / GW | List cron jobs   |
| `POST`   | `/v0/agents/{agentId}/tasks`                | JWT / GW | Create           |
| `GET`    | `/v0/agents/{agentId}/tasks/{jobId}`        | JWT / GW | Detail           |
| `PUT`    | `/v0/agents/{agentId}/tasks/{jobId}`        | JWT / GW | Update           |
| `DELETE` | `/v0/agents/{agentId}/tasks/{jobId}`        | JWT / GW | Delete           |
| `POST`   | `/v0/agents/{agentId}/tasks/{jobId}/run`    | JWT / GW | Run now          |
| `POST`   | `/v0/agents/{agentId}/tasks/{jobId}/toggle` | JWT / GW | Enable / disable |
| `GET`    | `/v0/agents/{agentId}/tasks/{jobId}/runs`   | JWT / GW | Run history      |

### Files & snapshots

| Method | Path                                     |   Auth   | Description                                  |
| ------ | ---------------------------------------- | :------: | -------------------------------------------- |
| `GET`  | `/v0/agents/{agentId}/files?path=<path>` | JWT / GW | Read a file from inside the container        |
| `POST` | `/v0/agents/{agentId}/files/upload`      | JWT / GW | Upload base64 file to `<workspace>/uploads/` |
| `GET`  | `/v0/agents/{agentId}/snapshots`         | JWT / GW | Last 10 snapshots                            |
| `GET`  | `/v0/agents/{agentId}/snapshots/sync`    | JWT / GW | Sync status                                  |
| `POST` | `/v0/agents/{agentId}/snapshots/sync`    | JWT / GW | Trigger a snapshot now                       |
| `POST` | `/v0/agents/{agentId}/snapshots/reset`   | JWT / GW | Reset to a snapshot CID                      |

### Console

| Method | Path                                |   Auth   | Description                                               |
| ------ | ----------------------------------- | :------: | --------------------------------------------------------- |
| `POST` | `/v0/agents/{agentId}/console/exec` | JWT / GW | Run a shell command, returns `{stdout, stderr, exitCode}` |

### Devices

| Method | Path                                               |   Auth   | Description           |
| ------ | -------------------------------------------------- | :------: | --------------------- |
| `GET`  | `/v0/agents/{agentId}/devices`                     | JWT / GW | List pending + paired |
| `POST` | `/v0/agents/{agentId}/devices/{requestId}/approve` | JWT / GW | Approve one           |
| `POST` | `/v0/agents/{agentId}/devices/approve-all`         | JWT / GW | Approve every pending |

### Config (engine runtime)

| Method | Path                                   |   Auth   | Description                                            |
| ------ | -------------------------------------- | :------: | ------------------------------------------------------ |
| `GET`  | `/v0/agents/{agentId}/config`          | JWT / GW | Read the engine runtime config shown in the Danger tab |
| `PUT`  | `/v0/agents/{agentId}/config`          | JWT / GW | Write runtime config (validated server-side)           |
| `POST` | `/v0/agents/{agentId}/config/validate` | JWT / GW | Validate runtime config without applying               |

<Note>
  Note `config/validate` validates runtime config, **not** `manifest.json`. OpenClaw agents use `/home/node/.openclaw/openclaw.json`; Hermes agents use `/home/hermes/data/config.yaml`. To validate a manifest, use `POST /v0/templates/validate` or run `pinata agents templates validate`.
</Note>

### Templates

| Method   | Path                            | Auth | Description                                 |
| -------- | ------------------------------- | :--: | ------------------------------------------- |
| `GET`    | `/v0/templates`                 |  JWT | List your templates                         |
| `POST`   | `/v0/templates`                 |  JWT | Submit a template from a git repo           |
| `GET`    | `/v0/templates/{slug}`          |  JWT | Get by slug                                 |
| `GET`    | `/v0/templates/id/{templateId}` |  JWT | Get by ID                                   |
| `PUT`    | `/v0/templates/{templateId}`    |  JWT | Update / resubmit                           |
| `DELETE` | `/v0/templates/{templateId}`    |  JWT | Archive                                     |
| `POST`   | `/v0/templates/validate`        |  JWT | Validate a git repo for template submission |
| `POST`   | `/v0/templates/branches`        |  JWT | List branches on a public repo              |
| `POST`   | `/v0/templates/refs`            |  JWT | List branches + tags                        |
| `GET`    | `/v0/public-templates`          | none | Public marketplace listing                  |

### Git Smart HTTP

| Method | Path                                        |            Auth            | Description              |
| ------ | ------------------------------------------- | :------------------------: | ------------------------ |
| `GET`  | `/v0/agents/{agentId}/git/info/refs`        | Git Basic (GW as password) | Ref advertisement        |
| `POST` | `/v0/agents/{agentId}/git/git-upload-pack`  | Git Basic (GW as password) | `git clone` / `git pull` |
| `POST` | `/v0/agents/{agentId}/git/git-receive-pack` | Git Basic (GW as password) | `git push`               |

## OpenAPI Spec

For everything not covered here:

```
https://agents.pinata.cloud/openapi
```

The OpenAPI spec is the authoritative source - schemas, query parameters, response codes, and per-endpoint descriptions.
