Quickstart

Send a portfolio. Get named factor exposures.

Mint a key, then POST positions. Creo returns beta, size, 12–1 momentum, low volatility and liquidity, plus risk contribution, methodology version, timestamps, coverage and quality flags. You bring prices; Creo sells compute.

Agents: read /llms.txt, /openapi.json or connect the MCP server at https://itscreo.com/mcp.

Try it without a key

The demo is keyless.

The five SYNTH.* tickers are labeled synthetic series. Score them with no key and no prices, 20 calls a day per IP.

curl -s https://itscreo.com/v1/demo/exposures

Python

Mint a key once, then reuse it.

Needs pip install httpx. The first run mints a key and prints export CREO_KEY=…; run that line so later runs reuse the key. Each IP can mint 5 keys a day. Lost one? Paste a key you have at /account.

# pip install httpx
import os
import httpx

origin = "https://itscreo.com"
key = os.environ.get("CREO_KEY")
if not key:  # mint once, then reuse: minting is limited to 5 keys per IP per day
    minted = httpx.post(f"{origin}/v1/keys", json={})
    minted.raise_for_status()
    key = minted.json()["key"]
    print(f"export CREO_KEY={key}")

r = httpx.post(
    f"{origin}/v1/portfolio/exposures",
    headers={"x-api-key": key},
    json={
        "positions": [
            {"ticker": "SYNTH.MOM", "quantity": 10},
            {"ticker": "SYNTH.DEF", "quantity": -5},
        ],
        "cash": 2000,
    },
)
r.raise_for_status()
for exposure in r.json()["exposures"]:
    print(exposure["factor_id"], exposure["value"])

TypeScript

Same contract.

Save it as creo.mjs and run node creo.mjs (Node 18 or newer).

// Save as creo.mjs and run: node creo.mjs (Node 18+; .mjs allows top-level await)
const origin = "https://itscreo.com";
let key = process.env.CREO_KEY;
if (!key) { // mint once, then reuse: minting is limited to 5 keys per IP per day
  const minted = await fetch(`${origin}/v1/keys`, {
    method: "POST",
    headers: { "content-type": "application/json" },
    body: "{}",
  });
  if (!minted.ok) throw new Error(await minted.text());
  key = (await minted.json()).key;
  console.log(`export CREO_KEY=${key}`);
}
const res = await fetch(`${origin}/v1/portfolio/exposures`, {
  method: "POST",
  headers: { "content-type": "application/json", "x-api-key": key },
  body: JSON.stringify({
    positions: [
      { ticker: "SYNTH.MOM", quantity: 10 },
      { ticker: "SYNTH.DEF", quantity: -5 },
    ],
    cash: 2000,
  }),
});
if (!res.ok) throw new Error(await res.text());
for (const e of (await res.json()).exposures) console.log(e.factor_id, e.value);

MCP

Connect your agent.

Hosted MCP server at https://itscreo.com/mcp. Send your key as the x-api-key header. Only successful scoring costs a credit; connecting, listing tools and errors are free. Clients that browse the official MCP Registry can install it as com.itscreo/creo.

Claude Code

claude mcp add --transport http creo https://itscreo.com/mcp --header "x-api-key: $CREO_KEY"

Cursor · ~/.cursor/mcp.json

{
  "mcpServers": {
    "creo": {
      "url": "https://itscreo.com/mcp",
      "headers": { "x-api-key": "creo_..." }
    }
  }
}

Codex · ~/.codex/config.toml

[mcp_servers.creo]
url = "https://itscreo.com/mcp"
http_headers = { "x-api-key" = "creo_..." }

No key yet? Connect without the header: the scoring tools work keyless on SYNTH.* tickers. mint_api_key returns a key you can pass as the api_key tool argument for the rest of that session.

Your own book

Real tickers need your prices.

Send daily closes for each position. Add volume for liquidity, market_cap for size and a benchmark series for beta. Without them those factors come back null with a reason, never zero. A real ticker without history is a 422 PRICES_REQUIRED, and it is not charged. Beta and momentum need 253 daily closes, low volatility 61 and liquidity 64 (with volume); size needs only market_cap. /llms.txt lists every factor's minimum. Numbers can be JSON numbers or strings.

{
  "positions": [
    {
      "ticker": "AAPL",
      "quantity": "100",
      "market_cap": "3400000000000",
      "history": [{ "date": "2026-11-05", "close": "227.10", "volume": "48100000" }, "..."]
    }
  ],
  "benchmark": { "history": [{ "date": "2026-11-05", "close": "6012.4" }, "..."] }
}

Crypto

Crypto gets its own sleeve.

Mark each position "asset_class": "crypto" and send every calendar day from your own exchange account or feed, with volume in coin units. Beta and momentum need 181 days, low volatility 21 and liquidity 31. Equity and crypto exposures are never added together; for clean numbers, score crypto in its own request with a BTC benchmark. A mixed book with one benchmark gets a BENCHMARK_SHARED_ACROSS_SLEEVES warning.

{
  "positions": [
    { "ticker": "BTC", "asset_class": "crypto", "quantity": 0.5,
      "history": [{ "date": "2026-11-07", "close": "76050.12", "volume": "18300" }, "..."] },
    { "ticker": "SOL", "asset_class": "crypto", "quantity": -60, "history": ["..."] }
  ],
  "benchmark": { "ticker": "BTC", "history": [{ "date": "2026-11-07", "close": "76050.12" }, "..."] },
  "cash": 20000
}

Fundamentals

Value and quality from SEC filings.

Add any *.sec factor to factors and Creo reads the issuer's 10-K filings on SEC EDGAR for book-to-price, asset growth, gross profitability and return on assets. You only send a recent close. Only filings made on or before valid_at count, and every value is traced in sec_sources with its accession number. Issuers with several share classes, such as GOOGL, need market_cap for book-to-price.

{
  "positions": [
    { "ticker": "AAPL", "quantity": 100, "history": [{ "date": "2026-11-06", "close": "268.47" }] }
  ],
  "factors": ["equity.value.book_to_price.sec", "equity.quality.return_on_assets.sec"]
}