> ## Documentation index
> Fetch the complete index at: https://maritime.sh/llms.txt
> Setup procedure for AI agents (install, sign in, deploy, verify): https://maritime.sh/agents.md
> This page as HTML: https://maritime.sh/docs/sdk

# SDK Reference

Complete reference for both Maritime SDKs. New here? Start with the
[Build on Maritime](https://maritime.sh/docs/build) guide. Methods are shown with their TypeScript names; Python
uses the same names in snake_case (`setEnv` is `set_env`) with keyword arguments.

| Language | Package | Install |
| --- | --- | --- |
| TypeScript / JS | `maritime-sdk` | `npm install maritime-sdk` |
| Python | `maritime` | `pip install maritime` |

Both are zero-dependency. Source: [github.com/maritime-sh/maritime-sdk](https://github.com/maritime-sh/maritime-sdk).

## Client

The API key defaults to `MARITIME_API_KEY`; the base URL to `MARITIME_API_URL` or `api.maritime.sh`.

### TypeScript

```typescript
import { Maritime } from 'maritime-sdk'

const maritime = new Maritime({
  apiKey: 'mk_...',                     // or MARITIME_API_KEY
  baseUrl: 'https://api.maritime.sh',   // or MARITIME_API_URL
  timeout: 60_000,                      // per-request ms
  maxRetries: 2,                        // network + 5xx/429
})
```

### Python

```python
from maritime import Maritime

client = Maritime(
    api_key="mk_...",                   # or MARITIME_API_KEY
    base_url="https://api.maritime.sh", # or MARITIME_API_URL
    timeout=60.0,                       # per-request seconds
    max_retries=2,                      # network + 5xx/429
)
```

A failed request is retried up to `maxRetries` times (default 2), waiting 0.5 s, then 1 s, doubling up to 8 s, or
the server's `Retry-After` up to 20 s. `GET` and `DELETE`, the lifecycle calls (start, stop, sleep, restart,
reloadEnv) and `chat`, which sends an `Idempotency-Key`, retry on `429`, `500`, `502`, `503`, `504`,
timeouts and network errors. Other writes retry only on `429` and `503`, and when the connection was refused or DNS
failed, so nothing was sent; a timeout or another `5xx` may already have applied the write, so it is thrown.

## Agents

Access via `maritime.agents` (TS) / `client.agents` (Python).

| Method | Does |
| --- | --- |
| `create(params)` | Create an agent and start its deploy. Prefer template: a bare framework yields a broken image. |
| `provision({externalId, …})` | Idempotent get-or-create by externalId. The recommended per-customer entry point. |
| `get(id)` | Fetch one agent. |
| `list({externalId?, name?})` | List agents, optionally filtered. |
| `chat(id, message, {conversationId?})` | Send a message, wait for the reply. Auto-wakes a sleeping agent. |
| `start / stop / sleep / restart(id)` | Lifecycle transitions. |
| `setEnv(id, key, value, {secret})` | Upsert an env var (secrets encrypted at rest). |
| `listEnv(id) / deleteEnv(id, key)` | Read / remove env vars. |
| `reloadEnv(id)` | Push env changes into the running container. |
| `resize(id, {memMb?, diskGb?, alwaysOn?})` | Change RAM or disk (applies on the next restart) or turn always-on on or off (applies at once). null clears a value back to the base allocation. |
| `setVisibility(id, visibility)` | 'private' (share-link holders only) or 'public' (anyone with the agent URL; a visit wakes it). public needs a verified account. |
| `webhookToken(id)` | The agent's invoke token and URL; POST to the URL wakes the agent with a payload. |
| `rotateWebhookToken(id)` | Replace the invoke token. The old one stops working at once. |
| `network(id) / updateNetwork(id, update) / testNetwork(id, destination)` | Read or change internet policy, exit and private access; try one TCP connection to host:port from inside the agent. |
| `exec(id, command, {timeout?})` | Run a one-shot shell command (a string, or argv tokens as an array) and wait for it. timeout is seconds, default 60. Wakes a sleeping agent. |
| `logs(id, {limit?, level?})` | Recent log entries. |
| `delete(id)` | Tear down the agent (container + volume + network). |

Files, skills and share links of an agent hang off `maritime.agents`:

| Method | Does |
| --- | --- |
| `files.list(id, path?) / download(id, path)` | Browse the agent's files; download returns bytes. |
| `files.upload(id, {content, filename, destDir?}) / write(id, path, content)` | Upload bytes or write a text file. |
| `files.mkdir(id, path) / move(id, from, to) / delete(id, path)` | Create a folder, move or delete a path. |
| `skills.list(id) / search(id, q, {limit?})` | The agent's skills (eligible, blocked, unsupported), or search ClawHub. |
| `skills.install(id, {slug?, git?, version?, force?, env?})` | Install from ClawHub (slug) or a git repo (git). |
| `skills.upload(id, {archive, name?, env?})` | Install a custom skill from a zip or a bare SKILL.md. |
| `skills.setEnv(id, env) / setAllowlist(id, allowlist)` | Give a skill the env values it waits on; replace the allowlist (null for no limit). |
| `skills.remove(id, name) / export(id, name)` | Remove a skill, or download it as a .tar.gz. |
| `shareLinks.create(id, {ttlSeconds?, endUserExternalId?})` | A link that opens a private agent URL. Default one hour; null lasts until revoked. |
| `shareLinks.list(id) / revoke(id, linkId) / revokeForEndUser(id, externalId)` | List links, revoke one, or revoke every link bound to an end user. |

**create / provision parameters**

| Param | Type | Notes |
| --- | --- | --- |
| `name` | `string` | Unique per account. Required. |
| `template` | `string` | openclaw · zeroclaw · hermes · claude_code · dsh · … (see [frameworks](https://maritime.sh/docs/frameworks)) |
| `externalId` | `string` | Your own id for this agent. Filterable; idempotency key for `provision`. |
| `instructions` | `string` | Plain-English persona / system prompt. |
| `env` | `{key,value,secret}[]` | Seed env vars. Secrets encrypted at rest. |
| `idleTtlSeconds` | `number` | Idle seconds before auto-sleep. |

### TypeScript

```typescript
// Idempotent per-customer provisioning (recommended)
const agent = await maritime.agents.provision({
  externalId: `customer_${userId}`,
  name: `assistant-${userId}`,
  template: 'openclaw',
})

const { response } = await maritime.agents.chat(agent.id, 'Hello')
await maritime.agents.setEnv(agent.id, 'STRIPE_KEY', 'sk_live_...', { secret: true })
const { root } = await maritime.agents.files.list(agent.id)   // browse / upload / download
await maritime.agents.exec(agent.id, ['ls', '-la', root])     // one-shot shell command
await maritime.agents.sleep(agent.id)
await maritime.agents.delete(agent.id)
```

### Python

```python
# Idempotent per-customer provisioning (recommended)
agent = client.agents.provision(
    external_id=f"customer_{user_id}",
    name=f"assistant-{user_id}",
    template="openclaw",
)

reply = client.agents.chat(agent["id"], "Hello")["response"]
client.agents.set_env(agent["id"], "STRIPE_KEY", "sk_live_...", secret=True)
root = client.agents.files.list(agent["id"])["root"]        # browse / upload / download
client.agents.exec(agent["id"], ["ls", "-la", root])        # one-shot shell command
client.agents.sleep(agent["id"])
client.agents.delete(agent["id"])
```

Exec waits by default. See [command execution](https://maritime.sh/docs/sdk/agents#exec) for detached Python submission, REST retrieval and cancellation, and timeout defaults.

## Sandboxes

Linux machines you create, run commands in, pause, snapshot and end from code. They need a key with the
`sandboxes` scope (or `manage`). Access via `maritime.sandboxes`, `maritime.ephemeral`, `maritime.snapshots`,
`maritime.secrets`, `maritime.usage` and `maritime.sandboxWebhooks` (Python: `client.sandbox_webhooks` and so on).
Sandbox calls throw `MaritimeSandboxError` with a machine-readable `code` and `hint`. See
[Sandboxes](https://maritime.sh/docs/ephemeral-sandboxes) and
[sandbox events](https://maritime.sh/docs/sdk/webhooks#sandbox-events).

| Method | Does |
| --- | --- |
| `sandboxes.create({name?, from?, size?, screen?, network?, endUser?, env?, idleTimeoutSeconds?, onIdle?, timeLimitSeconds?, keepAwake?, …})` | Create a sandbox and return a Sandbox object. from is a stock template or a saved snapshot. |
| `sandboxes.get(idOrName) / connect(id) / list({…})` | Fetch one sandbox, attach to an existing one, or page through yours. |
| `sandbox.run(cmd, {background?, …})` | Run a command and wait, or start it in the background and get a CommandHandle. |
| `sandbox.files.read / write / list / remove / watch` | Work with the sandbox's files. |
| `sandbox.url(port) / pause() / kill() / save(name) / update(params)` | Open a port, pause, end, save a snapshot, or change settings. |
| `sandbox.terminal() / runCode(code)` | An interactive terminal, or run a code snippet. |
| `ephemeral.createEphemeral / listEphemeral / extendEphemeral / killEphemeral` | Sandboxes with a fixed lifetime that end, disk included, when it runs out. |
| `snapshots.list / get / delete` | Saved snapshots and the stock templates. |
| `secrets.set({name, value}) / list / delete(name)` | Account secrets injected into every new sandbox except forEndUser ones. |
| `usage.list({from, to, sandbox?, endUser?})` | Sandbox usage records, one per running interval. |
| `sandboxWebhooks.create({url, events}) / list / delete / deliveries` | Endpoints that receive signed sandbox events. See sandbox events. |

## End users

Your own users, keyed by the id you already hold. Access via `maritime.endUsers` (TS) / `client.end_users`
(Python). See the [end users guide](https://maritime.sh/docs/sdk/end-users).

| Method | Does |
| --- | --- |
| `upsert(externalId, {displayName?, metadata?, tags?})` | Create the end user, or update the fields given. |
| `get(externalId)` | One end user with its agents. |
| `list({status?, tag?, externalIdPrefix?, q?, projectId?, agentId?, sort?, lastActiveBefore?, lastActiveAfter?, cursor?, limit?})` | One page of end users, newest first. Follow nextCursor for more. |
| `activity(externalId, {limit?})` | Recent messages with replies, wakes, sleeps and agent creates, newest first. |
| `createAgent(externalId, params?) / agents(externalId)` | Create the end user's agent exactly once; list their agents. |
| `setPolicy / getPolicy / clearPolicy(externalId)` | Caps and sizing for every agent the end user owns. |
| `mintToken(externalId, {agentId?, scopes?, ttlSeconds?}) / revokeTokens(externalId)` | Short-lived eu_ token for their own client; revoke every live token. |
| `suspend / resume / delete(externalId)` | Pause, restore, or remove the end user with their agents. |

## Projects

The HTTP front door: route each of your users' messages to their own agent. Access via `maritime.projects`.

| Method | Does |
| --- | --- |
| `get(projectId)` | Fetch a project. Every agent has a projectId. |
| `update(projectId, {name?, newChatPolicy?, maxInstances?, warmPoolSize?})` | Routing for new end users: 'single', 'assign', 'spawn' (one agent per end user) or 'claim'. |
| `message(projectId, {externalUserId, message, wait?, claimCode?, displayName?})` | Send an end user's message to their agent (bind, wake, deliver). Waits up to wait seconds (default 30) for the reply. |
| `getMessage(projectId, messageId)` | Poll a queued message for its reply. |
| `users(projectId) / getUser(projectId, externalUserId)` | Every bound end user, or one with its agent status. |
| `unbindUser(projectId, externalUserId)` | Unbind an end user. Their agent rejoins the warm pool. |

## Swarms

Run one command on many sandboxes and collect the results. Access via `maritime.swarms` (TS) /
`client.swarms` (Python). See [Swarms](https://maritime.sh/docs/swarms).

| Method | Does |
| --- | --- |
| `start({command, count? | inputs?, name?, template? | image?, size?, timeoutSeconds?, concurrency?, resultPath?}, {idempotencyKey?})` | Start a swarm: one command on many sandboxes. Needs the provision scope. A repeated idempotencyKey returns the first run. |
| `list({limit?})` | Your runs, newest first. |
| `get(swarmId)` | One run with every sandbox: status, sandboxId (sbx-...), exit code, output tails and result. |
| `cancel(swarmId)` | Stop a run; its sandboxes are stopped and ended. |
| `results(swarmId)` | Every sandbox's outcome, in input order. |
| `wait(swarmId, {intervalMs?, timeoutMs?})` | Poll until the run completes or is cancelled. Python takes interval and timeout in seconds. |

## Keys

Mint scoped API keys programmatically. Minting requires the caller's key to carry the `manage` scope. Scopes are
`provision`, `deploy`, `secrets`, `manage`, `computers` and `sandboxes`. The default is the first four; `manage`
grants every scope, so a default key also reaches [Computers](https://maritime.sh/docs/computers) and
[Sandboxes](https://maritime.sh/docs/ephemeral-sandboxes). A key that should reach only Computers asks for
`['computers']`, and one for only Sandboxes asks for `['sandboxes']`. A key created with `projectId` works only on that project's front door and usage routes and is
refused everywhere else.

| Method | Does |
| --- | --- |
| `create({name, scopes?, expiresInDays?, projectId?})` | Mint an account key (mk_). The raw key is returned once. |
| `create({sandbox, ttlSeconds?})` | Mint a per-sandbox key (msk_) that reaches only that sandbox. Default lifetime one day. The secret is returned once. |
| `list() / list({sandbox})` | List your account keys, or one sandbox's keys (raw values never returned again). |
| `revoke(id)` | Revoke a key. |

### TypeScript

```typescript
const worker = await maritime.keys.create({ name: 'chat-worker', scopes: ['deploy'] })
// worker.rawKey is shown once. Store it now.
const tenant = await maritime.keys.create({ name: 'tenant-a', projectId: agent.projectId })
```

### Python

```python
worker = client.keys.create("chat-worker", scopes=["deploy"])
# worker["raw_key"] is shown once. Store it now.
tenant = client.keys.create("tenant-a", project_id=agent["projectId"])
```

## Webhooks

Receive signed events instead of polling. The [webhooks guide](https://maritime.sh/docs/sdk/webhooks#events) lists
every event and covers retries and verification.

| Method | Does |
| --- | --- |
| `create({url, events?})` | Subscribe a URL. Returns the signing secret once. |
| `list()` | List subscriptions, with isActive for each. |
| `deliveries(id, {status?, limit?})` | The delivery log, newest first. status is 'pending', 'delivered', 'failed' or 'dead'. |
| `replay(deliveryId)` | Send one delivery again now and return the result. |
| `test(id)` | Deliver a synthetic ping. |
| `delete(id)` | Remove a subscription. |

Verify a delivery with `verifyWebhookSignature({secret, body, signature})` (TS, returns a Promise of boolean) or
`verify_webhook_signature(secret, body, signature)` (Python), both exported at the package top level. Pass the raw
body and the `X-Maritime-Signature` header.

## Billing, account and network

| Method | Does |
| --- | --- |
| `billing.usage({from?, to?, projectId?, externalUserId?})` | Per-agent hosting and AI cost over a range (at most 92 days), with externalUserId on each row. |
| `billing.usageDaily({from?, to?})` | The same costs by day. |
| `account.limits()` | Your plan, machine counts against their caps, and per-agent size ceilings. Any key works. |
| `network.presets.list() / create({name, allow?, deny?}) / delete(presetId)` | Saved internet allow and deny lists to apply to agents. |

## Feedback

Tell Maritime when a doc is wrong, an example does not run, or a call fails in a way you cannot explain. Built for
coding agents. See the [feedback guide](https://maritime.sh/docs/sdk/feedback).

| Method | Does |
| --- | --- |
| `send({message, kind?, subject?, agentId?, requestId?, statusCode?, tool?, context?})` | Send one report. Returns the stored row (202). |
| `list()` | The account's last 50 reports, newest first. |

### TypeScript

```typescript
await maritime.feedback.send({
  kind: 'sdk',
  subject: 'agents.chat',
  message: 'chat returned 500 on a fresh agent; docs say sleeping agents auto-wake.',
  requestId: err.requestId,
  statusCode: err.status,
  tool: 'claude-code/2.1.0',
})
```

### Python

```python
client.feedback.send(
    "chat returned 500 on a fresh agent; docs say sleeping agents auto-wake.",
    kind="sdk",
    subject="agents.chat",
    request_id=err.request_id,
    status_code=err.status,
    tool="codex",
)
```

## Errors

Every failure is a subclass of `MaritimeError`. API errors expose `.status` and `.detail`.

| Class | When |
| --- | --- |
| `MaritimeAuthError` | 401 / 403: bad or under-scoped key |
| `MaritimePaymentRequiredError` | 402: plan limit reached, or an add-on needs a paid plan |
| `MaritimeNotFoundError` | 404: no such agent (or not yours) |
| `MaritimeConflictError` | 409: name already taken |
| `MaritimeRateLimitError` | 429: rate limited |
| `MaritimeSandboxError` | a sandbox call failed; carries code, hint and retryAfterSeconds |
| `MaritimeAPIError` | any other non-2xx |
| `MaritimeConnectionError` | never reached Maritime (network / timeout) |

```python
from maritime import MaritimeAPIError

try:
    client.agents.get("nope")
except MaritimeAPIError as err:
    print(err.status, err.detail, err.request_id)
```

## More resources

- [Computers](https://maritime.sh/docs/computers): `maritime.computers`, desktops your own model drives
- [Networks](https://maritime.sh/docs/networks): internet policy, exits and private access
- [Limits](https://maritime.sh/docs/limits): plan caps, size ceilings and error codes
- [Web apps](https://maritime.sh/docs/web-apps): public agent URLs, visibility and share links

### See also

The [Build on Maritime](https://maritime.sh/docs/build) guide (visual walkthrough), the raw
[REST API](https://maritime.sh/docs/api), and the [CLI](https://maritime.sh/docs/cli).
