Developers
Build on Ace.
One key opens every app your account connects — 1,609 of them. Call them from your code, hand them to any AI chat over MCP, or ship them inside your own product.
Your keys
One key per project.
Keys belong to your Ace account and reach the apps you connect on Integrations. Keys act as your account: keep them secret and revoke one any time. A new key is shown once; Ace keeps only a fingerprint and cannot show it again.
Keys are created on your Ace developer page after you sign in.
MCP
Every app in every chat.
Ace runs a remote MCP server. Any client that speaks MCP gets six tools:
search_appsconnect_applist_connectionsfind_toolsget_toolrun_toolClaude
Settings → Connectors → Add custom connector. Name it Ace and paste your link:
https://tryacee.com/mcp/k/ace_sk_YOUR_KEYThe link carries your key. Treat it like a password.
Claude Code
In a terminal:
claude mcp add --transport http ace https://tryacee.com/mcp --header "Authorization: Bearer ace_sk_YOUR_KEY"ChatGPT
Settings → Apps & Connectors → Advanced → turn on Developer mode, then Create. Paste your link and choose No authentication (the link holds your key):
https://tryacee.com/mcp/k/ace_sk_YOUR_KEYCursor
Add to ~/.cursor/mcp.json:
{
"mcpServers": {
"ace": {
"url": "https://tryacee.com/mcp",
"headers": {
"Authorization": "Bearer ace_sk_YOUR_KEY"
}
}
}
}VS Code
Add to .vscode/mcp.json:
{
"servers": {
"ace": {
"type": "http",
"url": "https://tryacee.com/mcp",
"headers": {
"Authorization": "Bearer ace_sk_YOUR_KEY"
}
}
}
}Any client
Streamable HTTP at https://tryacee.com/mcp with Authorization: Bearer <key>, or the URL-only form https://tryacee.com/mcp/k/<key>. Server card: https://tryacee.com/.well-known/mcp/server-card.json.
curl https://tryacee.com/mcp \
-H "Authorization: Bearer ace_sk_YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'SDKs
Three lines to a connected app.
No dependencies. JavaScript runs in Node 18+, Deno, Bun, Workers and browsers. Python needs only the standard library.
JavaScript
npm install https://tryacee.com/sdk/tryacee-sdk-1.0.0.tgzimport { Ace } from "@tryacee/sdk";
const ace = new Ace({ apiKey: process.env.ACE_API_KEY });
// 1. Connect an app (send your user to the link once)
const { url } = await ace.apps.connect("slack");
// 2. Find the tool for a task, in plain words
const { tools } = await ace.tools.find("post a message in #sales on Slack");
// 3. Run it
const result = await ace.tools.run("SLACK_SEND_MESSAGE", {
channel: "#sales",
markdown_text: "Deal closed 🎉",
});Python
pip install https://tryacee.com/sdk/tryacee-1.0.0-py3-none-any.whlfrom tryacee import Ace
ace = Ace() # reads ACE_API_KEY
link = ace.apps.connect("hubspot")["url"] # send the user here once
found = ace.tools.find("create a contact in HubSpot")
result = ace.tools.run("HUBSPOT_CREATE_CONTACT", {"email": "pat@example.com"})curl
curl https://tryacee.com/api/v1/apps?search=slack \
-H "Authorization: Bearer ace_sk_YOUR_KEY"
curl -X POST https://tryacee.com/api/v1/tools/SLACK_SEND_MESSAGE/run \
-H "Authorization: Bearer ace_sk_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"arguments":{"channel":"#sales","markdown_text":"Deal closed"}}'AI agent
Hand every connected app to your own model. tools.definitions() returns OpenAI or Anthropic tool definitions; pass the model's tool call back to tools.run().
const tools = await ace.tools.definitions({ app: "gmail", format: "anthropic" });
const msg = await anthropic.messages.create({
model: "claude-opus-5-5",
max_tokens: 1024,
tools,
messages: [{ role: "user", content: "Summarize my unread mail" }],
});
for (const block of msg.content)
if (block.type === "tool_use") await ace.tools.run(block.name, block.input);REST API
The whole table.
Base URL https://tryacee.com/api/v1 · Authorization: Bearer ace_sk_… · JSON in and out · errors are {"error":{"code","message"}} · 120 requests a minute per key · full spec in the OpenAPI document.
| Method | Path | What it does |
|---|---|---|
| GET | /catalog | Public app catalog, no key |
| GET | /apps?search= | Search apps with your connection status |
| GET | /apps/{app} | One app |
| POST | /apps/{app}/connect | Sign-in link that connects the app |
| POST | /apps/{app}/request | Any endpoint of a connected app's API: {method, path, query?, body?} |
| GET | /connections | Your connected apps |
| DELETE | /connections/{id} | Disconnect |
| GET | /tools?app= | Tools in an app, with input schemas |
| POST | /tools/find | Find tools for a task in plain words |
| GET | /tools/{tool} | One tool's schema |
| POST | /tools/{tool}/run | Run it in a connected app |
| GET | /custom-connectors | Your own connectors (any company's MCP server) |
| POST | /custom-connectors | Add an MCP server {name, url, key?} or any REST API {name, spec, base?, key?, keyIn?} |
| DELETE | /custom-connectors/{id} | Remove it |
| GET | /triggers/types?app= | Events an app can send (new payment, new issue, new message…) |
| POST | /triggers | Watch one: {type, config?, webhookUrl}, or take webhooks from any service: {source: "webhook", name, webhookUrl?} |
| GET | /triggers | Your triggers |
| DELETE | /triggers/{id} | Stop watching |
| GET | /events?trigger= | The last 50 events and how each delivery went |
| GET | /runs | Your 25 latest runs |
| GET | /me | The account behind the key |
Triggers
Apps that call you.
Pick an event in any connected app, give Ace your webhook, and every time it happens Ace posts it to you, signed. Ace keeps the last 50 events per trigger and tries each delivery three times.
const { triggers } = await ace.triggers.types({ app: "stripe" });
const { trigger, signingSecret } = await ace.triggers.create({
type: triggers[0].id,
webhookUrl: "https://your-app.com/hooks/ace",
});
// In your webhook handler: verify before trusting the body.
import { createHmac, timingSafeEqual } from "node:crypto";
const ts = req.headers["x-ace-timestamp"];
const expected = "sha256=" + createHmac("sha256", signingSecret).update(ts + "." + rawBody).digest("hex");
const ok = timingSafeEqual(Buffer.from(expected), Buffer.from(req.headers["x-ace-signature"]));