Give any AI agent full access to your AlifOffice workspace — CRM contacts, deals, projects, tasks, and invoices. Connect via MCP (Claude Desktop & Claude Code), OpenAI function calling, or direct REST API.
https://www.alifoffice.com/api/v1 · All endpoints return {"ok": true, "data": ...}
Every request needs a Bearer API key and a workspace slug header.
ao auth login
/api/v1/auth/login with your email & password.curl -s -X POST https://www.alifoffice.com/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"you@example.com","password":"...","workspace":"your-slug"}'
# Response: {"ok":true,"data":{"api_key":"ao_...","active_workspace":"your-slug",...}}
Using the key
curl https://www.alifoffice.com/api/v1/auth/me \ -H "Authorization: Bearer ao_your_key_here" \ -H "X-Workspace: your-slug"
The MCP server exposes all AlifOffice commands as tools that Claude Desktop and Claude Code can call directly. Once configured, just tell Claude what you need — it handles the API calls automatically.
~/Library/Application Support/Claude/claude_desktop_config.json
(Mac) or %APPDATA%\Claude\claude_desktop_config.json (Windows).
claude_desktop_config.json
{
"mcpServers": {
"alifoffice": {
"command": "python3",
"args": ["/path/to/alifoffice_mcp.py"],
"env": {
"AO_API_KEY": "ao_your_key_here",
"AO_WORKSPACE": "your-workspace-slug",
"AO_API_URL": "https://www.alifoffice.com/api/v1"
}
}
}
}
# If you have the AlifOffice CLI installed and already ran `ao auth login`,
# the MCP server will read your key from ~/.ao/config automatically.
{
"mcpServers": {
"alifoffice": {
"command": "ao-mcp"
}
}
}
Claude Code (claude_code_config.json)
{
"mcpServers": {
"alifoffice": {
"command": "python3",
"args": ["/path/to/alifoffice_mcp.py"],
"env": {
"AO_API_KEY": "ao_your_key_here",
"AO_WORKSPACE": "your-workspace-slug"
}
}
}
}
Example prompts once connected
| "List all my overdue invoices" | → calls ao_invoice_list with status=overdue |
| "Create a high-priority task in the Website project: Fix checkout bug" | → ao_projects_task_create |
| "Move the Database migration task to In Review" | → ao_projects_task_update |
| "Show me all contacts at Acme Corp" | → ao_crm_contact_list with search=Acme |
| "What's my API quota usage?" | → ao_auth_me |
Fetch the OpenAI-compatible tool schema from /api/v1/tools and pass it directly to
chat.completions.create(). The model decides when to call each tool; you execute the call
against our REST API.
import requests, json, openai
AO_KEY = "ao_your_key_here"
AO_WS = "your-workspace-slug"
AO_URL = "https://www.alifoffice.com/api/v1"
HEADERS = {"Authorization": f"Bearer {AO_KEY}", "X-Workspace": AO_WS}
# 1. Fetch tool schema (cache this — it rarely changes)
tools = requests.get(f"{AO_URL}/tools").json()["tools"]
# 2. Chat with tool use
client = openai.OpenAI()
messages = [{"role": "user", "content": "List all active projects and their open tasks"}]
response = client.chat.completions.create(
model="gpt-4o", tools=tools, messages=messages
)
# 3. Execute tool calls
for call in (response.choices[0].message.tool_calls or []):
fn = call.function.name # e.g. "ao_projects_list"
args = json.loads(call.function.arguments)
# Map tool name → API path
path = fn.replace("ao_", "").replace("_", "/", 1).replace("_", "-")
result = requests.get(f"{AO_URL}/{path}", headers=HEADERS, params=args).json()
print(result)
import OpenAI from "openai";
const AO_KEY = "ao_your_key_here";
const AO_WS = "your-workspace-slug";
const AO_URL = "https://www.alifoffice.com/api/v1";
const AO_HEADERS = { Authorization: `Bearer ${AO_KEY}`, "X-Workspace": AO_WS };
// 1. Fetch tool schema
const { tools } = await fetch(`${AO_URL}/tools`).then(r => r.json());
// 2. Chat with tools
const client = new OpenAI();
const response = await client.chat.completions.create({
model: "gpt-4o",
tools,
messages: [{ role: "user", content: "Show me unpaid invoices" }],
});
// 3. Execute tool calls
for (const call of response.choices[0].message.tool_calls ?? []) {
const args = JSON.parse(call.function.arguments);
const url = `${AO_URL}/invoice/invoices?` + new URLSearchParams(args);
const data = await fetch(url, { headers: AO_HEADERS }).then(r => r.json());
console.log(data);
}
# Fetch the full OpenAI-compatible tool schema curl https://www.alifoffice.com/api/v1/tools | jq '.tools[].function.name' # Output: # "ao_auth_me" # "ao_crm_contact_list" # "ao_crm_contact_create" # "ao_crm_deal_list" # "ao_projects_list" # "ao_projects_task_list" # ... 19 tools total
Use the ?format=anthropic query param to get tools in Anthropic's format.
Works with all Claude models that support tool use.
import requests, json, anthropic
AO_KEY = "ao_your_key_here"
AO_WS = "your-workspace-slug"
AO_URL = "https://www.alifoffice.com/api/v1"
HEADERS = {"Authorization": f"Bearer {AO_KEY}", "X-Workspace": AO_WS}
# 1. Fetch Anthropic-format tool schema
tools = requests.get(f"{AO_URL}/tools?format=anthropic").json()["tools"]
# 2. Create message with tools
client = anthropic.Anthropic()
message = client.messages.create(
model="claude-opus-4-6",
max_tokens=1024,
tools=tools,
messages=[{"role": "user", "content": "Create a CRM contact: Jane Smith, jane@acme.com, Acme Corp"}]
)
# 3. Handle tool use blocks
for block in message.content:
if block.type == "tool_use":
print(f"Calling: {block.name}")
print(f"With: {json.dumps(block.input, indent=2)}")
# Execute against AlifOffice API
result = requests.post(
f"{AO_URL}/crm/contacts",
headers={**HEADERS, "Content-Type": "application/json"},
json=block.input
).json()
print(f"Result: {result['data']['id']}")
import Anthropic from "@anthropic-ai/sdk";
const AO_KEY = "ao_your_key_here";
const AO_WS = "your-workspace-slug";
const AO_URL = "https://www.alifoffice.com/api/v1";
// 1. Fetch Anthropic-format tools
const { tools } = await fetch(`${AO_URL}/tools?format=anthropic`).then(r => r.json());
// 2. Create message
const client = new Anthropic();
const message = await client.messages.create({
model: "claude-opus-4-6",
max_tokens: 1024,
tools,
messages: [{ role: "user", content: "List all my active projects" }],
});
// 3. Execute tool calls
for (const block of message.content) {
if (block.type === "tool_use") {
const resp = await fetch(`${AO_URL}/projects?` + new URLSearchParams(block.input), {
headers: { Authorization: `Bearer ${AO_KEY}`, "X-Workspace": AO_WS }
}).then(r => r.json());
console.log(resp.data);
}
}
Plain HTTP + JSON. Works with LangChain tools, n8n, Make, Zapier, or any custom integration.
export AO_KEY="ao_your_key_here"
export AO_WS="your-workspace-slug"
export AO="https://www.alifoffice.com/api/v1"
# List projects
curl "$AO/projects" \
-H "Authorization: Bearer $AO_KEY" \
-H "X-Workspace: $AO_WS"
# Create a task
curl -X POST "$AO/projects/{project_id}/tasks" \
-H "Authorization: Bearer $AO_KEY" \
-H "X-Workspace: $AO_WS" \
-H "Content-Type: application/json" \
-d '{"title":"Fix login bug","priority":"high","status":"todo"}'
# List CRM contacts
curl "$AO/crm/contacts?search=acme&limit=20" \
-H "Authorization: Bearer $AO_KEY" \
-H "X-Workspace: $AO_WS"
import requests
class AoClient:
def __init__(self, api_key, workspace, base="https://www.alifoffice.com/api/v1"):
self.base = base
self.headers = {
"Authorization": f"Bearer {api_key}",
"X-Workspace": workspace,
"Content-Type": "application/json",
}
def get(self, path, **params):
return requests.get(f"{self.base}/{path}", headers=self.headers, params=params).json()
def post(self, path, **body):
return requests.post(f"{self.base}/{path}", headers=self.headers, json=body).json()
def patch(self, path, **body):
return requests.patch(f"{self.base}/{path}", headers=self.headers, json=body).json()
ao = AoClient("ao_your_key_here", "your-workspace-slug")
# Examples
projects = ao.get("projects", status="active")
new_task = ao.post("projects/{id}/tasks", title="Fix bug", priority="high")
contacts = ao.get("crm/contacts", search="acme corp", limit=10)
deal = ao.post("crm/deals", title="Enterprise deal", amount=50000, stage="proposal")
from langchain.tools import tool
import requests
AO_KEY = "ao_your_key_here"
AO_WS = "your-workspace-slug"
HDRS = {"Authorization": f"Bearer {AO_KEY}", "X-Workspace": AO_WS}
BASE = "https://www.alifoffice.com/api/v1"
@tool
def list_projects(status: str = None) -> dict:
"""List AlifOffice projects. Optionally filter by status."""
params = {"status": status} if status else {}
return requests.get(f"{BASE}/projects", headers=HDRS, params=params).json()
@tool
def create_task(project_id: str, title: str, priority: str = "medium") -> dict:
"""Create a task in an AlifOffice project."""
return requests.post(f"{BASE}/projects/{project_id}/tasks",
headers={**HDRS, "Content-Type": "application/json"},
json={"title": title, "priority": priority}).json()
@tool
def list_contacts(search: str = None) -> dict:
"""Search CRM contacts by name, email, or company."""
return requests.get(f"{BASE}/crm/contacts", headers=HDRS,
params={"search": search} if search else {}).json()
# Use with any LangChain agent
from langchain.agents import initialize_agent, AgentType
from langchain_openai import ChatOpenAI
agent = initialize_agent(
tools=[list_projects, create_task, list_contacts],
llm=ChatOpenAI(model="gpt-4o"),
agent=AgentType.OPENAI_FUNCTIONS,
)
agent.run("List active projects and create a task in the first one: Write unit tests")
All 19 tools available to AI agents. Full schema at /api/v1/tools.
Auth
| Tool | Endpoint | Description |
|---|---|---|
| ao_auth_me | GET /auth/me |
Current user, workspace & quota |
CRM
| Tool | Endpoint | Description |
|---|---|---|
| ao_crm_contact_list | GET /crm/contacts |
List & search contacts |
| ao_crm_contact_get | GET /crm/contacts/{id} |
Single contact |
| ao_crm_contact_create | POST /crm/contacts |
Create contact |
| ao_crm_contact_update | PATCH /crm/contacts/{id} |
Update contact |
| ao_crm_deal_list | GET /crm/deals |
List & filter deals |
| ao_crm_deal_create | POST /crm/deals |
Create deal |
| ao_crm_deal_update | PATCH /crm/deals/{id} |
Update deal |
Projects
| Tool | Endpoint | Description |
|---|---|---|
| ao_projects_list | GET /projects |
List projects |
| ao_projects_create | POST /projects |
Create project |
| ao_projects_task_list | GET /projects/{id}/tasks |
List tasks |
| ao_projects_task_create | POST /projects/{id}/tasks |
Create task |
| ao_projects_task_update | PATCH /projects/{id}/tasks/{t} |
Update task |
Invoices
| Tool | Endpoint | Description |
|---|---|---|
| ao_invoice_list | GET /invoice/invoices |
List invoices |
| ao_invoice_get | GET /invoice/invoices/{id} |
Single invoice |
| ao_invoice_create | POST /invoice/invoices |
Create invoice |
| ao_invoice_mark_paid | POST /invoice/invoices/{id}/mark-paid |
Mark as paid |
Workspace
| Tool | Endpoint | Description |
|---|---|---|
| ao_workspace_list | GET /workspace |
List workspaces |
| ao_workspace_members | GET /workspace/{slug}/members |
List members |