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.
https://solari.sh/mcp/api/v1AUTHENTICATION
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-sdkimport { 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-sdkfrom 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.
- TS
new 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.
- TS
await solari.listTools()PYsolari.list_tools() - GET /tools — every tool this account can call, with its JSON input schema.
- TS
await solari.getTool(name)PYsolari.get_tool(name) - GET /tools/{name} — one tool's schema and description.
- TS
await 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.
- TS
await 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.
- TS
await 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_secondsERRORS
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 →