How you and your tools access the Caylex platform: through the dashboard with SSO, or programmatically with a platform access token.
Caylex has two layers of authentication. Platform authentication (covered here) controls how you and your tools access the Caylex platform itself. Server authentication controls how your end users authenticate with external MCP servers; see Server Authentication for that.You can access the platform two ways: interactively through the dashboard, or programmatically through the REST API.
Caylex uses SSO for platform access. When you sign up or log in to the Caylex dashboard, you authenticate through the platform’s identity provider. This gives you access to manage your organization’s projects, servers, navigators, and analytics.
The Caylex platform exposes a REST API for managing your workspace without clicking through the dashboard. It covers projects, skills, usage, analytics, tool security, and more. Authenticate with a platform access token and call the API from a script, a CI pipeline, or your own backend.This is the control plane for your workspace. It is separate from the runtime connection your agents use to call tools, which uses a Navigator API key instead (see Connecting your agent).
Create a new platform access token and give it a descriptive name (for example, ci-skill-sync). Optionally set an expiry date.
3
Copy the token
Copy the token value and store it in a secret manager or CI secret. The raw token is shown only once. If you lose it, revoke it and create a new one.
A platform access token has admin scope over your entire workspace. Treat it like a password: keep it server-side, never commit it to version control, and never expose it to a browser.
Send the token in the Authorization header as a Bearer token against the https://api.caylex.ai/api/v1 base URL. To verify your token works, list your projects:
A common use case is keeping a local repository of skills in sync with a Caylex project from CI. The skill sync endpoints address your project by name and each skill by its SKILL.md frontmatter name, so your tooling never has to track Caylex UUIDs.
Project names are matched exactly and are case-sensitive. URL-encode names that contain spaces. For example, Production Project becomes Production%20Project.
cURL
Python
TypeScript
BASE="https://api.caylex.ai/api/v1"PROJECT="Production%20Project"AUTH="Authorization: Bearer $CAYLEX_PLATFORM_TOKEN"# List every skill in the projectcurl "$BASE/projects/by-name/$PROJECT/skills" -H "$AUTH"# Fetch one skill, including its SKILL.md bodycurl "$BASE/projects/by-name/$PROJECT/skills/code-review" -H "$AUTH"# Add a new skill (409 if it already exists)curl -X POST "$BASE/projects/by-name/$PROJECT/skills" -H "$AUTH" \ -F "file=@./skills/code-review/SKILL.md"# Replace an existing skill (404 if it doesn't exist yet)curl -X PUT "$BASE/projects/by-name/$PROJECT/skills/code-review" -H "$AUTH" \ -F "file=@./skills/code-review/SKILL.md"# Remove a skillcurl -X DELETE "$BASE/projects/by-name/$PROJECT/skills/code-review" -H "$AUTH"
import osfrom urllib.parse import quoteimport requestsBASE_URL = "https://api.caylex.ai/api/v1"PROJECT = quote("Production Project") # URL-encode names with spacesHEADERS = {"Authorization": f"Bearer {os.environ['CAYLEX_PLATFORM_TOKEN']}"}base = f"{BASE_URL}/projects/by-name/{PROJECT}/skills"# List every skill in the projectskills = requests.get(base, headers=HEADERS).json()# Fetch one skill, including its SKILL.md bodyskill = requests.get(f"{base}/code-review", headers=HEADERS).json()# Add a new skill (409 if it already exists)with open("./skills/code-review/SKILL.md", "rb") as f: requests.post(base, headers=HEADERS, files={"file": f})# Replace an existing skill (404 if it doesn't exist yet)with open("./skills/code-review/SKILL.md", "rb") as f: requests.put(f"{base}/code-review", headers=HEADERS, files={"file": f})# Remove a skillrequests.delete(f"{base}/code-review", headers=HEADERS)
import { readFile } from "node:fs/promises";const BASE_URL = "https://api.caylex.ai/api/v1";const PROJECT = encodeURIComponent("Production Project"); // URL-encode names with spacesconst headers = { Authorization: `Bearer ${process.env.CAYLEX_PLATFORM_TOKEN}` };const base = `${BASE_URL}/projects/by-name/${PROJECT}/skills`;async function main() { // List every skill in the project const skills = await (await fetch(base, { headers })).json(); // Fetch one skill, including its SKILL.md body const skill = await (await fetch(`${base}/code-review`, { headers })).json(); // Add a new skill (409 if it already exists) const md = await readFile("./skills/code-review/SKILL.md"); const addForm = new FormData(); addForm.append("file", new File([md], "SKILL.md")); await fetch(base, { method: "POST", headers, body: addForm }); // Replace an existing skill (404 if it doesn't exist yet) const putForm = new FormData(); putForm.append("file", new File([md], "SKILL.md")); await fetch(`${base}/code-review`, { method: "PUT", headers, body: putForm }); // Remove a skill await fetch(`${base}/code-review`, { method: "DELETE", headers });}main();
For a skill bundled with extra files (scripts, references), upload a ZIP of the skill directory in place of the SKILL.md. The file part accepts either.
Use POST to add a new skill and PUT to replace one. POST returns 409 if the skill already exists, and PUT returns 404 if it doesn’t, so CI can distinguish a first-time upload from an update instead of silently overwriting.
Keep tokens server-side. Call the Platform API from your backend or CI only, never from a browser or mobile client.
Use a secret manager. Store tokens in your CI provider’s secrets or a secret manager, not in code or .env files committed to git.
Set an expiry. Give tokens an expiry date where possible, and create separate tokens for separate systems so you can revoke one without disrupting others.
Rotate and revoke. Rotate tokens periodically, and revoke any token immediately from the Administration page if it may be compromised.