Client, CLI and MCP
One package for code, terminals and agents.
@sitecall/cli holds the typed REST client, webhook verification, and two programs: the sitecall CLI and the sitecall-mcp server. Node 20.3 or later, and any modern browser for the client.
The typed client
Every method maps to one operation of the reference, and its argument and result types come from the same contract SiteCall's routes validate with.
server.ts
import { createSiteCallClient, SiteCallApiError } from "@sitecall/cli";
const sitecall = createSiteCallClient({
apiKey: process.env.SITECALL_API_KEY,
externalWorkspaceId: "acme-42", // or workspaceId: SiteCall's id
});
const live = await sitecall.calls.list({ state: "live" });
await sitecall.calls.transfer(live.data[0].id, { target: { queueId }, warm: true });
try {
await sitecall.calls.dial({ to: "+15125550123", from: { phoneNumberId }, agent: { externalUserId: "user-7" } });
} catch (error) {
if (error instanceof SiteCallApiError && error.code === "caller_id_forbidden") {
// error.status, error.message, error.callId, error.idempotencyKey
}
}What it does for you
- Idempotency. Each mutation gets a new UUID
Idempotency-Keyunless you pass{ idempotencyKey }; its own retries reuse it. Pass your own key to make a retry after a crash the same operation. - Safe retries. A lost answer, a 503, a 429 or a 409
idempotency_in_progressis retried twice by default (maxRetries), honoringRetry-Afterup to 8 seconds (a longer one waits 8 seconds). An operation a person must decide (a number command, a verification text, a purchase) is never retried. - Contract checks. Bodies and queries are checked before sending (
invalid_request, nothing sent) and answers are parsed with the contract, defaults applied. Turn both off withvalidate: false. - Errors. Every refusal, whatever its shape, is a
SiteCallApiErrorwithstatus,code,message,retryable, and for a plan, a dial or a messageissues,callIdormessageId. - Pages.
sitecall.paginate("calls.list", query)yields every item across pages;sitecall.events.pages()walks the event log. - Any operation by id.
sitecall.request("calls.get", { params: { id } }).
As one user: the token hook
In a browser or a phone, pass getToken instead of a key. It runs before every request; refresh: true means SiteCall refused the last token (expired or revoked), so fetch a new one. The client retries that request once with it, under the same Idempotency-Key.
browser.ts
import { createSiteCallClient } from "@sitecall/cli";
const asUser = createSiteCallClient({
workspaceId,
getToken: async ({ refresh }) => (refresh || !cached ? (cached = await fetchToken()) : cached),
});
await asUser.emergencyLocations.resolve({ deviceId });On a server acting as one user, createSessionTokenProvider mints tokens with your key and caches each until a minute before it expires:
import { createSessionTokenProvider, createSiteCallClient } from "@sitecall/cli";
const asDana = createSiteCallClient({
externalWorkspaceId: "acme-42",
getToken: createSessionTokenProvider({
mint: (body) => sitecall.sessions.create(body),
session: { externalWorkspaceId: "acme-42", externalUserId: "user-7", scopes: ["calls:*"] },
}),
});Webhooks
verifyWebhook checks a delivery's signature and timestamp and reads its event. See Webhooks.
The CLI
The CLI provisions with your own SiteCall login (an owner or admin of the company): it never needs a carrier, database or application key.
terminal
npx sitecall login # a code to your phone or email
npx sitecall tools # every tool and its JSON input schema
echo '{"workspaceId":"…"}' | npx sitecall activation_get # JSON on stdin
npx sitecall numbers_quote quote.json # or a JSON file
npx sitecall logoutProvision in order: choose or create the company, confirm its facts, search and quote a number, buy it with the quote's exact confirmation, then submit texting registration. The CLI refuses a purchase without a quote it saved, and never buys a replacement number after a timeout. Sessions are stored privately under ~/.config/sitecall/.
The MCP server
Sign in with the CLI first, then point your MCP host at the server. It speaks stdio with the same provisioning tools and schemas; tokens and codes never appear in tool output.
mcp config
{
"mcpServers": {
"sitecall": { "command": "npx", "args": ["-y", "-p", "@sitecall/cli", "sitecall-mcp"] }
}
}The host must get the person's approval for the exact company, number and monthly price before it calls numbers_buy.