SOLARI API & SDK

One API for every workflow.

Every read-only tool the CLI and the MCP server run is one HTTP call away — or one method call, with the TypeScript and Python SDKs. Same data, same access token, plain JSON in and out.

LIVE · v1https://solari.sh/mcp/api/v1

AUTHENTICATION

One bearer token, minted by the CLI.

Sign in once with the solari CLI, then hand its access token to whatever runs your code.

solari auth token
Prints the signed-in account's access token, refreshing it first when it has run out. Good for eight hours.
SOLARI_TOKEN
The SDKs and the CLI read this variable, so CI jobs and containers need no sign-in of their own.

Send it as Authorization: Bearer <token> on every request.

ENDPOINTS

Four endpoints. The tools do the rest.

Tool names, arguments, and results are exactly what solari help all --json and the MCP server describe.

GET/tools
Every tool this account can call, with its JSON input schema.
GET/tools/{name}
One tool's schema and description.
POST/tools/{name}
Run a tool. The JSON body is its arguments; the response is its payload.
GET/me
The account behind the token.

EXAMPLE

Resolve a brand in one call.

The response is the same JSON the CLI prints with --json: found, plus items ordered best-first.

curl -sS https://solari.sh/mcp/api/v1/tools/solari_catalog_instagram_account_search \
  -H "Authorization: Bearer $(solari auth token)" \
  -H "Content-Type: application/json" \
  -d '{"query":"nike","limit":3}'

SDKS

Or skip the HTTP and use a client.

Both clients are thin, dependency-free wrappers over these endpoints. Dotted paths map to tool names: catalog.instagram.account.search is solari_catalog_instagram_account_search.

TypeScript · Node, Bun, Deno, Workers, browsers

npm install @brandazine/solari-sdk
import { Solari } from "@brandazine/solari-sdk";

const solari = new Solari({ token: process.env.SOLARI_TOKEN });
const hits = await solari.tools.catalog.instagram.account.search({ query: "nike", limit: 3 });

Python 3.9+ · standard library only

pip install solari-sdk
from solari_sdk import Solari

solari = Solari()  # reads SOLARI_TOKEN
hits = solari.tools.catalog.instagram.account.search(query="nike", limit=3)

Six calls. Same shape in both languages.

Every method maps to one endpoint above. Results are the tool's JSON payload, untouched; nothing is cached client-side.

TSnew Solari({ token?, baseUrl?, fetch?, timeoutMs?, userAgent? })
PYSolari(token=None, base_url=…, timeout=150, user_agent=None, transport=None)
Create a client. token falls back to SOLARI_TOKEN; baseUrl defaults to solari.sh. Inject fetch or transport to test without a network.
TSawait solari.listTools()
PYsolari.list_tools()
GET /tools — every tool this account can call, with its JSON input schema.
TSawait solari.getTool(name)
PYsolari.get_tool(name)
GET /tools/{name} — one tool's schema and description.
TSawait solari.call<T>(name, args)
PYsolari.call(name, arguments=None, **kwargs)
POST /tools/{name} — run a tool by its full name. TypeScript lets you type the result.
TSawait solari.tools.catalog.instagram.account.search(args)
PYsolari.tools.catalog.instagram.account.search(**kwargs)
The same call spelled as a dotted path. Generated from the tool registry, so paths, argument names, and enum values are type-checked in TypeScript and by pyright/mypy in Python.
TSawait solari.me()
PYsolari.me()
GET /me — the account behind the token.

One error type, carrying the envelope.

Non-2xx responses raise SolariError with the API's status, code, message, and tool, plus retryable for 429, 502, 503, and 504 and the Retry-After seconds when the server sent them. Network failures raise the same type with status 0.

import { Solari, SolariError } from "@brandazine/solari-sdk";

try {
  await solari.call("solari_insight_instagram_brand_overview", { username: "nike" });
} catch (error) {
  if (error instanceof SolariError && error.retryable) {
    // error.status, error.code, error.tool, error.retryAfterSeconds
  }
}
from solari_sdk import Solari, SolariError

try:
    solari.call("solari_insight_instagram_brand_overview", username="nike")
except SolariError as error:
    if error.retryable:
        ...  # error.status, error.code, error.tool, error.retry_after_seconds

ERRORS

Every failure is a JSON envelope.

Non-2xx responses carry error.code, error.message, and error.tool when a tool was involved. Rate limits and warming apps add a Retry-After header.

{
  "error": {
    "code": "invalid_arguments",
    "message": "limit: expected number, received string",
    "tool": "solari_catalog_instagram_account_search"
  }
}
400invalid_arguments
The body did not match the tool's input schema. The message names the field.
400invalid_json
The body was not a JSON object.
400tool_error
The tool refused the call — for example, a missing account reference.
401unauthorized
The token is missing, expired, or revoked. Mint a new one.
403forbidden
Your SOLARI account cannot use this tool.
404tool_not_found
No tool by that name for this account. List the tools to see what exists.
429rate_limited
Too many calls. Wait for Retry-After seconds.
502upstream_error
SOLARI could not complete the call. Retry shortly.
503app_warming_up
A Studio app is starting. Retry after Retry-After seconds.
504upstream_timeout
The call ran past the time limit. Narrow it or retry.

ALSO

The same tools over MCP.

Agents and MCP hosts connect to the MCP server with the same token. Use whichever fits the caller.

https://solari.sh/mcpConnect over MCP