API Documentation
Authentication
All API requests require authentication via an API key. Include your key in the X-API-Key header.
X-API-Key: ao_live_your_api_key_here
Alternatively, pass the API key in the request body:
{
"apiKey": "ao_live_your_api_key_here",
"company": "Stripe"
}
Run Agent
Start an agent run. The job is queued and processed asynchronously. Use the returned job_id to check status.
curl -X POST https://applyoperator.com/api/v1/agents/company-intel/run \
-H "X-API-Key: ao_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"company": "Monzo",
"domain": "monzo.com",
"depth": "standard"
}'
import requests
response = requests.post(
"https://applyoperator.com/api/v1/agents/company-intel/run",
headers={"X-API-Key": "ao_live_your_key"},
json={
"company": "Monzo",
"domain": "monzo.com",
"depth": "standard"
}
)
data = response.json()
print(f"Job ID: {data['job_id']}")
const response = await fetch(
"https://applyoperator.com/api/v1/agents/company-intel/run",
{
method: "POST",
headers: {
"X-API-Key": "ao_live_your_key",
"Content-Type": "application/json"
},
body: JSON.stringify({
company: "Monzo",
domain: "monzo.com",
depth: "standard"
})
}
);
const data = await response.json();
console.log("Job ID:", data.job_id);
Response
{
"success": true,
"job_id": "ci_abc123xyz",
"status": "queued",
"estimated_time": "30-120 seconds"
}
Jobs
Check job status and retrieve results.
/api/v1/jobs/getJob
Get job status and results.
{ "job_id": "ci_abc123xyz" }
{
"success": true,
"job": {
"id": "ci_abc123xyz",
"agent": "company-intel",
"status": "completed",
"progress": 100,
"results": { "..." },
"cost": { "amount": 1.00, "currency": "USD" },
"created_at": "2026-01-15T10:30:00Z",
"completed_at": "2026-01-15T10:31:23Z"
}
}
Webhooks
Register a webhook URL to receive notifications when jobs complete or fail.
/api/v1/webhooks/register
Register a webhook endpoint.
{
"url": "https://your-app.com/webhook",
"events": ["job.completed", "job.failed"]
}
Account
/api/v1/account/getBalance
Check your current credit balance.
/api/v1/account/getUsage
Get usage history and spending breakdown.
Tool Code
Every marketplace tool exports an async function handler(input, api). The platform calls this function inside a sandboxed Linux namespace with no direct network access.
Handler Signature
async function handler(input, api) {
// input — JSON object sent by the caller
// api — sandbox API: fetch, log, memory, storage
// return — any JSON-serializable value (sent back as job output)
api.log('Starting agent run');
const res = await api.fetch('https://api.example.com/data', {
method: 'POST',
headers: { 'Authorization': 'Bearer ...' },
body: JSON.stringify({ query: input.query })
});
const prev = await api.memory.read();
await api.memory.write(prev + '\n' + new Date().toISOString());
return { status: res.status, data: res.body };
}
Important: The handler function must be defined at the top level. It receives input (the JSON payload from the API call) and api (the sandbox API object). The return value becomes the job result.
Sandbox API
The api object provides controlled access to the outside world from inside the sandbox.
api.fetch(url, options)
Make HTTP requests to external services. All requests are proxied through a bridge socket — the sandbox has no direct network.
| Option | Description |
|---|---|
| method | HTTP method (GET, POST, PUT, PATCH, DELETE). Default: GET |
| headers | Object of request headers |
| body | Request body (string or object, auto-serialized to JSON) |
Returns: { status, statusText, headers, body, text }
Restrictions: HTTPS only, no private/localhost IPs, 15s timeout, 1 MB max response size. body is auto-parsed as JSON when possible, text is always the raw string.
api.log(message)
Capture log messages visible in job results. Messages are truncated to 10,000 characters. Logs are returned alongside the agent output when the job completes.
api.memory
Persistent markdown-based memory stored in SQLite. Two scopes are available:
| Method | Description | Limit |
|---|---|---|
| api.memory.read() | Read agent-specific memory | 64 KB |
| api.memory.write(content) | Write agent-specific memory (string) | 64 KB |
| api.memory.global.read() | Read memory shared across all your agents | 128 KB |
| api.memory.global.write(content) | Write shared memory (string) | 128 KB |
Memory persists across runs. Agent memory is scoped to the specific agent slug; global memory is shared across all agents for the same user.
api.storage
Paid disk storage for files. Requires an active storage subscription (see Dashboard → Storage).
| Method | Description |
|---|---|
| api.storage.list() | List files — returns [{file_path, size_bytes, ...}] |
| api.storage.read(path) | Read file content (returns string) |
| api.storage.write(path, content) | Write file (10 MB max per write) |
| api.storage.delete(path) | Delete a file |
Path rules: Relative paths only — no .., no leading /, max 500 characters. Files are scoped to the agent slug within the user's storage directory. During grace period, storage is read-only.
api.getCredentials()
Agent tools often need user-specific secrets such as login emails, passwords, or API keys. Instead of hardcoding these values, users save credentials once in the Agent Tools page. Saved credentials are automatically injected at runtime.
In your tool's input_schema, add "credential": true to any property that contains sensitive data. The platform uses this flag to identify which fields should be saved separately and never sent to the LLM.
{
"type": "object",
"properties": {
"email": { "type": "string", "description": "Login email", "credential": true },
"password": { "type": "string", "description": "Login password", "credential": true },
"date_range": { "type": "string", "description": "Date range to download" }
}
}
Fields marked credential: true appear in the Agent Tools configuration form and can be saved by the user. Non-credential fields (like date_range above) are passed as regular input each time the tool runs.
Returns: { configured, credentials }
| Field | Type | Description |
|---|---|---|
| configured | boolean | true if the user has saved credentials for this slug |
| credentials | object | Key-value pairs of saved credential fields (empty {} when not configured) |
async function handler(input, api) {
const creds = await api.getCredentials();
if (!creds.configured) {
return { error: 'Credentials not configured. Save them in the Agent Tools page.' };
}
const { email, password } = creds.credentials;
// Use credentials to authenticate
const res = await api.fetch('https://example.com/api/login', {
method: 'POST',
body: JSON.stringify({ email, password })
});
return { status: 'ok', data: res.body };
}
Security: Credential values are stored per-user, never logged, and never sent to the LLM. The operator only sees field names (via the get_credentials tool) to confirm they exist — actual values stay server-side and are only accessible inside the sandbox.
Users save credentials in Dashboard → Agent Tools. Values are stored per-user, scoped to the tool slug. At runtime, api.getCredentials() returns the actual values inside the sandbox. Credential fields are also auto-injected into the tool's input when called by the operator.
Sandbox Limits
Agents run inside isolated Linux namespaces with the following resource constraints:
| Resource | Limit |
|---|---|
| Memory (cgroup) | 128 MB |
| Processes (PID limit) | 32 |
| Execution timeout | 30 seconds |
| Stdout capture | 5 MB |
| Fetch response | 1 MB per request |
| Fetch timeout | 15 seconds per request |
| Storage write | 10 MB per write |
| Agent memory | 64 KB |
| Global memory | 128 KB |
| Network | HTTPS only via bridge (no direct access) |
| Filesystem | Read-only (Alpine rootfs), writable /tmp |
Telegram Integration
Connect a Telegram bot to receive notifications and chat with your AI operator agents directly from Telegram.
Prerequisites
- A Telegram account
- A Telegram bot created via @BotFather
Setup Steps
Create a Telegram bot
Open Telegram, search for @BotFather, send /newbot, and follow the prompts. Copy the bot token (e.g. 123456789:ABCdefGhIjKlmNoPqRsTuVwXyZ).
Add the bot token
Go to Settings → Integrations → Telegram, paste the token, and click Save. The system will verify the token and set up a webhook.
Activate the bot
Open Telegram, find your bot by username, and send /start. This links your Telegram chat to your ApplyOperator account.
Link an agent session (optional)
To chat with an agent via Telegram, select a running operator session from the dropdown in the Telegram card and click Link. Messages you send to the bot will be forwarded to the agent, and its responses sent back to you.
Supported Notifications
- Job completed / failed
- Low credits warning / credits depleted
- Agent marketplace approval
Configure which notifications are sent via Telegram in Notification Preferences.
Bidirectional Chat
When sessions are linked, you can send messages to the bot and the operator agent will process them and respond. The agent has full access to its configured tools (web search, email, etc.).
Multi-Session Chat
You can link multiple agent sessions to your Telegram bot and switch between them using commands:
| Command | Description |
|---|---|
| /agents | List all linked sessions with active indicator |
| /list | Same as /agents |
| /<name> | Switch to a session (e.g. /otis) |
| /help | Show available commands |
All regular messages (not starting with /) are sent to the currently active session. Switch between agents at any time.
Note: Linked sessions must be in a "running" state. If a session is stopped, the bot will inform you and ask you to restart it or switch to another.
WhatsApp Integration
Connect WhatsApp to receive notifications and chat with your AI operator agents directly from your phone.
Prerequisites
- A WhatsApp account with an active phone number
- WhatsApp installed on your phone
Setup Steps
Start the connection
Go to Settings → Integrations → WhatsApp and click Connect WhatsApp.
Scan the QR code
A QR code will appear on screen. Open WhatsApp on your phone, go to Settings → Linked Devices → Link a Device, and scan the QR code.
Connection confirmed
Once scanned, the status will change to "Connected" and your phone number will be displayed. You'll start receiving notifications.
Link agent sessions (optional)
Add one or more running operator sessions to enable bidirectional agent chat via WhatsApp. You can link multiple sessions and switch between them.
Supported Notifications
- Job completed / failed
- Low credits warning / credits depleted
- Agent marketplace approval
Configure which notifications are sent via WhatsApp in Notification Preferences.
Multi-Session Chat
You can link multiple agent sessions and switch between them using commands:
| Command | Description |
|---|---|
| /agents | List all linked sessions with active indicator |
| /list | Same as /agents |
| /<name> | Switch to a session (e.g. /otis) |
| /help | Show available commands |
All regular messages are sent to the currently active session. Switch between agents at any time.
Troubleshooting
QR code expired
QR codes expire after a short time. Click Connect WhatsApp again to generate a new one.
Session disconnected
WhatsApp Web sessions may disconnect if your phone loses internet or if you log out from the linked devices menu. Reconnect by clicking Connect WhatsApp and scanning a new QR code.
Agent not responding
Ensure the linked operator session is in a "running" state. Check the dashboard to verify the session status and restart it if needed.
Storage Sync (WebDAV)
Sync your agent storage files between your local computer and ApplyOperator using the WebDAV protocol. Mount your storage as a native folder, use bidirectional sync, or automate backups — works on Windows, Linux, and macOS.
Prerequisites
- An active storage subscription (see Dashboard → Storage)
- An API key from Settings
Authentication
The WebDAV endpoint uses HTTP Basic Auth. Set your username to anything (e.g. your email) and use your API key as the password:
URL: https://applyoperator.com/webdav/
Username: your-email@example.com (any value)
Password: ao_live_your_api_key_here
Quick Start with rclone
rclone is a free, open-source tool for syncing files with cloud storage. It supports WebDAV and runs on all major operating systems.
Install rclone
Download from rclone.org/install — available for Windows, macOS, and Linux.
Configure the remote
Run rclone config and create a new remote with these settings:
Type: webdav
URL: https://applyoperator.com/webdav/
Vendor: other
User: your-email@example.com
Password: ao_live_your_api_key_here
Sync your files
Use any of these commands (assuming your remote is named ao):
# Download remote files to local folder
rclone sync ao: ~/ao-storage/
# Upload local files to remote
rclone sync ~/ao-storage/ ao:
# Bidirectional sync (keeps both sides up to date)
rclone bisync ~/ao-storage/ ao:
# List remote files
rclone ls ao:
# Mount as a native folder (files appear like local files)
rclone mount ao: ~/ao-storage/ --vfs-cache-mode full
# The mount stays active until you press Ctrl+C
# On Windows, use a drive letter: rclone mount ao: X: --vfs-cache-mode full
Native OS Mounting
You can also connect directly from your OS file manager without installing rclone:
macOS
Finder → Go → Connect to Server → https://applyoperator.com/webdav/
Windows
File Explorer → right-click This PC → Map Network Drive → https://applyoperator.com/webdav/
Linux
File manager → Connect to Server → davs://applyoperator.com/webdav/
curl Examples
You can also interact with the WebDAV endpoint directly using curl:
# List files (PROPFIND)
curl -X PROPFIND https://applyoperator.com/webdav/ \
-u "user:ao_live_your_key" \
-H "Depth: 1"
# Create a directory
curl -X MKCOL https://applyoperator.com/webdav/my-agent/ \
-u "user:ao_live_your_key"
# Upload a file
curl -X PUT https://applyoperator.com/webdav/my-agent/data.json \
-u "user:ao_live_your_key" \
-d '{"key": "value"}'
# Download a file
curl https://applyoperator.com/webdav/my-agent/data.json \
-u "user:ao_live_your_key"
# Delete a file
curl -X DELETE https://applyoperator.com/webdav/my-agent/data.json \
-u "user:ao_live_your_key"
Access Control
Subscription required: WebDAV access requires an active storage subscription. With an active subscription you have full read/write access. During a grace period, storage is read-only. With no subscription or an expired one, WebDAV access is denied.
File structure: Your WebDAV root shows agent folders at the top level. Each agent folder contains that agent's storage files. The structure mirrors what you see in Dashboard → Storage.