MaritimemaritimeDocumentation
Dashboard

Provisioning API

Programmatically provision agents, manage zero-knowledge secrets, and inject custom build scripts for enterprise deployments.

Base URL: https://api.maritime.sh/api/v1

Auth: All provisioning endpoints require an X-API-Key header with a maritime API key (mk_...).

Install

You need a NaCl / libsodium library to seal secrets. Everything else uses standard HTTP.

pip install PyNaCl requests

Quick Start

Provision an agent, seal secrets, and deploy — in under 30 lines.

# Set your API key
export MARITIME_API_KEY="mk_your_key_here"

# 1. Provision an agent
curl -s -X POST https://api.maritime.sh/api/v1/provision \
  -H "X-API-Key: $MARITIME_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "my-agent",
    "image": "openclaw",
    "image_name": "python:3.11-slim",
    "tier": "always_on",
    "auto_deploy": false
  }'

# Save the agent_id and public_key from the response, then:

# 2. Deploy the agent
curl -s -X POST https://api.maritime.sh/api/v1/agents/AGENT_ID/deploy \
  -H "X-API-Key: $MARITIME_API_KEY" \
  -H "Content-Type: application/json"

# 3. Check status
curl -s https://api.maritime.sh/api/v1/agents/AGENT_ID \
  -H "X-API-Key: $MARITIME_API_KEY"

How Sealed Secrets Work

Maritime uses X25519 + XSalsa20-Poly1305 (NaCl sealed boxes) for zero-knowledge secret management. Neither the API caller nor Maritime can read the secrets after submission.

You (API caller)              Maritime Platform            Container
     │                              │                          │
     │ POST /provision ────────────►│                          │
     │                              │ generate X25519 keypair  │
     │◄── { public_key } ──────────│                          │
     │                              │                          │
     │ seal(secret, public_key)     │                          │
     │ POST /secrets ──────────────►│ store sealed blob        │
     │                              │ (cannot decrypt)         │
     │                              │                          │
     │ POST /deploy ───────────────►│ deploy ─────────────────►│
     │                              │ inject sealed_secrets    │
     │                              │ inject private_key       │
     │                              │                          │
     │                              │              unseal.py decrypts
     │                              │              private_key deleted
     │                              │              secrets → env vars

Important: The private key exists only inside the container and is deleted after secrets are unsealed. You can always add more secrets — they merge with existing ones and unseal on the next deploy/restart.

API Key Management

Create and manage API keys from the dashboard. These endpoints use session authentication (cookies), not API key auth.

Create API Key

POST/api/v1/keys
ParameterTypeRequiredDescription
namestringYesHuman-readable name for this key
scopesstring[]NoScopes: provision, deploy, secrets, manage. Default: all.
expires_in_daysinteger | nullNoKey expiry in days. Null = never expires.
curl -X POST https://api.maritime.sh/api/v1/keys \
  -H "Authorization: Bearer YOUR_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "production-pipeline",
    "scopes": ["provision", "deploy", "secrets", "manage"],
    "expires_in_days": 90
  }'
Response: 201 Created
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "name": "production-pipeline",
  "key_prefix": "mk_aBcDeFgH",
  "scopes": ["provision", "deploy", "secrets", "manage"],
  "is_active": true,
  "last_used_at": null,
  "expires_at": "2026-06-13T10:30:00Z",
  "created_at": "2026-03-15T10:30:00Z",
  "raw_key": "mk_aBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789abc"
}

Store the raw_key securely. It is returned only once at creation time and cannot be retrieved again.

List API Keys

GET/api/v1/keys
curl -s https://api.maritime.sh/api/v1/keys \
  -H "Authorization: Bearer YOUR_SESSION_TOKEN"

Revoke API Key

DELETE/api/v1/keys/{key_id}
curl -X DELETE https://api.maritime.sh/api/v1/keys/KEY_ID \
  -H "Authorization: Bearer YOUR_SESSION_TOKEN"

# Returns 204 No Content on success

Provisioning

Provision Agent

POST/api/v1/provisionscope: provision
ParameterTypeRequiredDescription
namestringYesAgent name
descriptionstringNoAgent description
imagestringNoFramework: openclaw, crewai, langgraph, docker, custom, auto
image_namestringNoDocker image (e.g. python:3.11-slim)
repo_urlstringNoGitHub repo URL for source builds
branchstringNoGit branch (default: main)
tierstringNoTier: smart, extended, always_on
auto_deploybooleanNoDeploy immediately (default: true)
env_varsobjectNoNon-secret env vars as key-value pairs
curl -X POST https://api.maritime.sh/api/v1/provision \
  -H "X-API-Key: $MARITIME_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "customer-support-bot",
    "image": "openclaw",
    "image_name": "python:3.11-slim",
    "repo_url": "https://github.com/acme/support-agent",
    "tier": "always_on",
    "auto_deploy": true,
    "env_vars": {
      "LOG_LEVEL": "info",
      "REGION": "us-east-1"
    }
  }'
Response: 201 Created
{
  "agent_id": "7f3a1b2c-4d5e-6f7a-8b9c-0d1e2f3a4b5c",
  "name": "customer-support-bot",
  "status": "deploying",
  "public_key": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2",
  "deployment_id": "d8e9f0a1-b2c3-4d5e-6f7a-8b9c0d1e2f3a",
  "message": "Agent provisioned. Use the public_key to seal secrets with NaCl crypto_box_seal."
}

List Agents

GET/api/v1/agentsscope: provision
curl -s https://api.maritime.sh/api/v1/agents \
  -H "X-API-Key: $MARITIME_API_KEY"

Get Agent Status

GET/api/v1/agents/{agent_id}scope: provision
curl -s https://api.maritime.sh/api/v1/agents/AGENT_ID \
  -H "X-API-Key: $MARITIME_API_KEY"

Sealed Secrets

Upload Sealed Secrets

POST/api/v1/agents/{agent_id}/secretsscope: secrets

Each value must be encrypted client-side using NaCl crypto_box_seal with the agent's public_key, then base64-encoded.

ParameterTypeRequiredDescription
secretsobjectYesMap of KEY → base64-encoded sealed ciphertext
# Sealing requires a crypto library — use this Python one-liner to seal,
# then pipe to curl:

python3 -c "
from nacl.public import PublicKey, SealedBox
import base64, json

PUBLIC_KEY = 'YOUR_PUBLIC_KEY_HEX'
pk = PublicKey(bytes.fromhex(PUBLIC_KEY))
box = SealedBox(pk)

secrets = {}
for k, v in {
    'OPENAI_API_KEY': 'sk-proj-...',
    'DATABASE_URL': 'postgresql://user:pass@host/db',
    'STRIPE_SECRET': 'sk_live_...',
}.items():
    secrets[k] = base64.b64encode(box.encrypt(v.encode())).decode()

print(json.dumps({'secrets': secrets}))
" | curl -X POST https://api.maritime.sh/api/v1/agents/AGENT_ID/secrets \
    -H "X-API-Key: $MARITIME_API_KEY" \
    -H "Content-Type: application/json" \
    -d @-

Custom Build Files

Upload Custom Files

POST/api/v1/agents/{agent_id}/filesscope: deploy

Inject files into the agent container. By default, files are placed in /maritime/scripts/ and shell scripts are executed after deploy. You can customize the target directory and control whether scripts run on deploy.

ParameterTypeRequiredDescription
filesCustomFile[]YesArray of files to inject
files[].pathstringYesFilename or relative path (e.g. install-tools.sh, config/app.toml)
files[].contentstringYesFile content. Include shebang for scripts.
files[].executablebooleanNochmod +x the file (default: true)
files[].run_on_deploybooleanNoExecute .sh files after deploy (default: true). Set false to only place the file.
files[].target_dirstringNoDirectory inside the container (default: /maritime/scripts). E.g. /app/config, /data.
curl -X POST https://api.maritime.sh/api/v1/agents/AGENT_ID/files \
  -H "X-API-Key: $MARITIME_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "files": [
      {
        "path": "install-deps.sh",
        "content": "#!/bin/bash\nset -e\napt-get update -qq\napt-get install -y -qq ffmpeg imagemagick\npip install -q pandas numpy scikit-learn",
        "executable": true,
        "run_on_deploy": true,
        "target_dir": "/maritime/scripts"
      },
      {
        "path": "app.toml",
        "content": "[server]\nhost = \"0.0.0.0\"\nport = 8080",
        "executable": false,
        "run_on_deploy": false,
        "target_dir": "/app/config"
      }
    ]
  }'

Lifecycle Management

Deploy / Redeploy

POST/api/v1/agents/{agent_id}/deployscope: deploy
ParameterTypeRequiredDescription
image_namestringNoOverride Docker image
repo_urlstringNoOverride repo URL
branchstringNoOverride git branch
# Deploy with defaults (uses provisioned settings)
curl -X POST https://api.maritime.sh/api/v1/agents/AGENT_ID/deploy \
  -H "X-API-Key: $MARITIME_API_KEY"

# Deploy a specific branch
curl -X POST https://api.maritime.sh/api/v1/agents/AGENT_ID/deploy \
  -H "X-API-Key: $MARITIME_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"branch": "staging"}'

Start / Stop / Restart

POST/api/v1/agents/{agent_id}/startscope: deploy
POST/api/v1/agents/{agent_id}/stopscope: deploy
POST/api/v1/agents/{agent_id}/restartscope: deploy
# Start
curl -X POST https://api.maritime.sh/api/v1/agents/AGENT_ID/start \
  -H "X-API-Key: $MARITIME_API_KEY"

# Stop
curl -X POST https://api.maritime.sh/api/v1/agents/AGENT_ID/stop \
  -H "X-API-Key: $MARITIME_API_KEY"

# Restart
curl -X POST https://api.maritime.sh/api/v1/agents/AGENT_ID/restart \
  -H "X-API-Key: $MARITIME_API_KEY"

Teardown

DELETE/api/v1/agents/{agent_id}scope: manage

Stops the container, removes the volume, and deletes the agent record.

curl -X DELETE https://api.maritime.sh/api/v1/agents/AGENT_ID \
  -H "X-API-Key: $MARITIME_API_KEY"

# Returns 204 No Content on success

Logs & Deployments

Get Agent Logs

GET/api/v1/agents/{agent_id}/logs
ParameterTypeRequiredDescription
limitintegerNoMax entries to return (default: 100, max: 1000)
levelstringNoFilter by level: info, warning, error
curl -s "https://api.maritime.sh/api/v1/agents/AGENT_ID/logs?limit=50&level=error" \
  -H "X-API-Key: $MARITIME_API_KEY"
Response: 200 OK
[
  {
    "id": "a1b2c3d4...",
    "level": "error",
    "message": "Container exited with code 1",
    "source": "system",
    "timestamp": "2026-03-22T14:30:00Z"
  }
]

Get Deployment History

GET/api/v1/agents/{agent_id}/deployments
ParameterTypeRequiredDescription
limitintegerNoMax entries to return (default: 10, max: 50)
curl -s "https://api.maritime.sh/api/v1/agents/AGENT_ID/deployments?limit=5" \
  -H "X-API-Key: $MARITIME_API_KEY"
Response: 200 OK
[
  {
    "id": "d8e9f0a1...",
    "status": "success",
    "source": "docker",
    "branch": null,
    "build_log": "Pulling image ghcr.io/openclaw/openclaw:latest...\nContainer created: abc123...\nCustom files injected: install-deps.sh → /maritime/scripts (executed)\nDeploy complete.",
    "started_at": "2026-03-22T14:00:00Z",
    "completed_at": "2026-03-22T14:00:45Z"
  }
]

Enterprise & Wallet

Enterprise accounts enable usage-based billing with wallet credits. These endpoints use session authentication (cookies).

Create Enterprise Account

POST/api/v1/enterprise/account
ParameterTypeRequiredDescription
company_namestringYesCompany / organization name
rate_per_hour_centsintegerNoCompute rate in cents per hour (default: 1 = $0.01/hr)
initial_balance_centsintegerNoInitial wallet credit in cents (default: 0)
curl -X POST https://api.maritime.sh/api/v1/enterprise/account \
  -H "Authorization: Bearer YOUR_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "company_name": "Acme Corp",
    "rate_per_hour_cents": 1,
    "initial_balance_cents": 10000
  }'
Response: 201 Created
{
  "id": "ent_abc123...",
  "company_name": "Acme Corp",
  "balance_cents": 10000,
  "balance_dollars": 100.0,
  "rate_per_hour_cents": 1,
  "rate_per_hour_dollars": 0.01,
  "min_balance_cents": 0,
  "auto_stop_on_zero": true,
  "is_active": true,
  "created_at": "2026-03-22T10:00:00Z"
}

Get Enterprise Account

GET/api/v1/enterprise/account
curl -s https://api.maritime.sh/api/v1/enterprise/account \
  -H "Authorization: Bearer YOUR_SESSION_TOKEN"

Get Wallet Balance

GET/api/v1/wallet/balance
curl -s https://api.maritime.sh/api/v1/wallet/balance \
  -H "Authorization: Bearer YOUR_SESSION_TOKEN"
Response: 200 OK
{
  "balance_cents": 8500,
  "balance_dollars": 85.0,
  "rate_per_hour_cents": 1,
  "rate_per_hour_dollars": 0.01,
  "period_compute_minutes": 1500.0,
  "period_spend_cents": 1500,
  "period_spend_dollars": 15.0,
  "period_credits_cents": 10000,
  "period_credits_dollars": 100.0,
  "active_agents": 3,
  "company_name": "Acme Corp"
}

Top Up Wallet

POST/api/v1/wallet/topup
ParameterTypeRequiredDescription
amount_centsintegerYesAmount to add in cents (e.g. 10000 = $100). Must be > 0.
curl -X POST https://api.maritime.sh/api/v1/wallet/topup \
  -H "Authorization: Bearer YOUR_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"amount_cents": 10000}'

Transaction History

GET/api/v1/wallet/transactions
ParameterTypeRequiredDescription
limitintegerNoMax entries (default: 50)
offsetintegerNoPagination offset (default: 0)
curl -s "https://api.maritime.sh/api/v1/wallet/transactions?limit=10" \
  -H "Authorization: Bearer YOUR_SESSION_TOKEN"

API Key Scopes

ScopeGrants Access To
provisionProvision new agents, list agents, get agent status
deployDeploy, start, stop, restart agents; upload custom files
secretsUpload sealed secrets
manageAll of the above, plus teardown/delete agents

Error Responses

StatusMeaning
401Missing, invalid, revoked, or expired API key
403API key lacks the required scope for this endpoint
402Insufficient wallet balance for deploy (enterprise accounts)
404Agent not found, or agent belongs to a different user
409Deploy already in progress for this agent

Full End-to-End Example

Complete scripts you can copy, fill in your key, and run.

"""
maritime_provision.py — Provision, seal secrets, add build scripts, deploy.
pip install PyNaCl requests
"""
import base64
import requests
from nacl.public import PublicKey, SealedBox

API_KEY = "mk_your_key_here"
BASE = "https://api.maritime.sh/api/v1"
H = {"X-API-Key": API_KEY, "Content-Type": "application/json"}

# ── 1. Provision ──
r = requests.post(f"{BASE}/provision", headers=H, json={
    "name": "fraud-detector",
    "image": "openclaw",
    "image_name": "python:3.11-slim",
    "repo_url": "https://github.com/acme/fraud-detector",
    "tier": "always_on",
    "auto_deploy": False,
    "env_vars": {"LOG_LEVEL": "info", "REGION": "us-east-1"},
}).json()
agent_id = r["agent_id"]
public_key = r["public_key"]
print(f"1. Provisioned: {agent_id}")

# ── 2. Seal & upload secrets ──
pk = PublicKey(bytes.fromhex(public_key))
box = SealedBox(pk)
secrets = {}
for k, v in {
    "OPENAI_API_KEY": "sk-proj-...",
    "DATABASE_URL": "postgresql://user:pass@host:5432/db",
    "WEBHOOK_SIGNING_SECRET": "whsec_...",
}.items():
    secrets[k] = base64.b64encode(box.encrypt(v.encode())).decode()

r = requests.post(f"{BASE}/agents/{agent_id}/secrets", headers=H, json={"secrets": secrets}).json()
print(f"2. Secrets: {r['message']}")

# ── 3. Custom build files ──
r = requests.post(f"{BASE}/agents/{agent_id}/files", headers=H, json={
    "files": [{
        "path": "install-deps.sh",
        "content": "#!/bin/bash\nset -e\napt-get update -qq\napt-get install -y -qq ffmpeg\npip install -q torch",
        "executable": True,
        "run_on_deploy": True,
    }],
}).json()
print(f"3. Files: {r['message']}")

# ── 4. Deploy ──
r = requests.post(f"{BASE}/agents/{agent_id}/deploy", headers=H).json()
print(f"4. Deploy: {r['message']} (deployment_id: {r['deployment_id']})")

# ── 5. Poll status ──
import time
for _ in range(30):
    status = requests.get(f"{BASE}/agents/{agent_id}", headers=H).json()["status"]
    print(f"   Status: {status}")
    if status in ("active", "error"):
        break
    time.sleep(5)

Client Libraries

For sealing secrets you need a NaCl / libsodium library:

Python: pip install PyNaCl

Node.js: npm install libsodium-wrappers

Go: go get golang.org/x/crypto/nacl/box

Rust: cargo add crypto_box

Ruby: gem install rbnacl