Core Specificationv3.1
The Neural Protocol
How Cortex speaks to the outside world. A guide to the security, data format, and handshake mechanisms that power the plugin ecosystem.
1The Conceptual Model
Cortex plugins are stateless web servers. Think of them as "Action Libraries" that the AI consults.
When a user says "Check my order #123", the AI doesn't know how to do that. It looks at your Manifest, sees a check_order tool, and sends a request to your server.
1. User Input"Check order status"
2. Cortex EngineCalls Plugin URL
3. Your PluginReturns JSON data
2Security & Authentication
Cortex supports two security models. Choose the one that fits your use case.
The "Shared Secret" Model
Use this when you can identify the user implicitly (e.g. by their stable Cortex ID) or don't need user-specific data.
Best Use Cases
- Anonymous/Public Tools"Get price of Bitcoin", "Search Knowledge Base". No user identity needed.
- Order Status (via Input)"Check order #123". The user provides the ID in the prompt. You verify the signature.
- Sticky ProfilesStore preferences against the stable
user.id(e.g. "User prefers Spanish").
Privacy by Design: Cortex does NOT send the user's phone number or name to plugins. You receive a cryptographic hash (
user.id) unique to your plugin installation.javascript
import express from "express"; import { createHmac } from "crypto"; const app = express(); app.use(express.json()); // MIDDLEWARE: Verify the signature // This proves the request came from Cortex const verifySignature = (req, res, next) => { const authHeader = req.headers["authorization"]; if (!authHeader) return res.status(401).json({ error: "Missing auth" }); const token = authHeader.split(" ")[1]; // Remove "Bearer " const [payloadBase64, signature] = token.split("."); // 1. Re-calculate signature with your SHARED SECRET // (Env var: PLUGIN_SECRET) const expectedSig = createHmac("sha256", process.env.PLUGIN_SECRET) .update(payloadBase64) .digest("base64url"); // 2. Compare safely if (signature !== expectedSig) { return res.status(403).json({ error: "Invalid signature" }); } // 3. Decode context (contains hashed user.id) const contextJson = Buffer.from(payloadBase64, "base64url").toString(); req.cortexContext = JSON.parse(contextJson); next(); }; app.post("/webhook/orders", verifySignature, (req, res) => { // We TRUST this request came from Cortex. // The user provided their Order ID in the input. const { orderId } = req.body.input; // We can also store prefs against the anonymous user.id const { user } = req.cortexContext; console.log("Request from anonymous user:", user.id); const order = db.findOrder(orderId); res.json({ order }); });
3Context: The Source of Truth
Cortex doesn't just send the user's message. It injects a comprehensive Context Object into every request. This keeps your plugin stateless.
json
{ "serviceName": "CRM_INTEGRATION", "organizationId": "org_827393", // THE IDENTITY "user": { "id": "u_99283...", // Hashed, stable User ID "hashVersion": 1 }, // THE SECRETS "config": { "apiKey": "sk_live_...", // Decrypted! "environment": "production" }, // THE OAUTH TOKEN (If applicable) // This is what you use to authorize upstream API calls "userAccessToken": "ya29.a0Ad5..." }
Field-by-Field Breakdown
- serviceName
- The name of your plugin (e.g. 'HUB_SPOT')
- organizationId
- The ID of the company running the bot
- user.id
- A privacy-preserving HASH of the user's phone number + your service ID. Unique to your plugin.
- config
- Decrypted secrets (API Keys) that the admin configured in the Dashboard.
- userAccessToken
- If using OAuth, this is the user's specific access token (e.g. for their Gmail).