Integration

Official SDK

A small TypeScript client for one job. Use an agent you already configured, and render its answers in a chat interface you build yourself. It cannot change anything about the agent.

Install

terminal
npm install @wicarax/sdk

Requires Node.js 18 or later, or any modern browser or bundler. The package ships as CommonJS with TypeScript declarations, has no runtime dependencies, and works with both require and ESM named imports.

Note

The package page is @wicarax/sdk on npm.

What each key can do

Capability is per method, not per client. A publishable key is a real credential. It is simply not a chat credential.

SDK capabilityPublishable keySecret key
chat.sendNoYes
agent.getAppearanceYesYes
models.listYesYes

Calling chat.send on a client built with only a publishable key throws before any network request, with code: "secret_key_required" and no status. It is a configuration mistake rather than a refusal, so isAuthError is false and isCapabilityError is true.

Heads up

The two checks are independent and both real. The SDK refuseschat.send in your own process, with no network request; the server refuses a wcx_pk_ on /v1/chat/completions with 403 access_denied. The server-side refusal is the boundary that matters, because curl, a copied fetch snippet and any OpenAI client never run the SDK's check. The SDK's version exists so you find out at your desk rather than in production.

Send a message

Chat runs on a server, with a secret key. If you are building a browser UI, put this call behind your own endpoint and let your frontend talk to that.

server.ts
import { Wicarax } from '@wicarax/sdk';

const wicarax = new Wicarax({ secretKey: process.env.WICARAX_SECRET_KEY });

const result = await wicarax.chat.send({
  message: 'What is your refund policy?',
});

console.log(result.reply);

In a browser, a publishable key still reads the agent's public appearance and the model list, which is what you need to theme a custom interface:

browser.ts
import { Wicarax } from '@wicarax/sdk';

const wicarax = new Wicarax({ publishableKey: 'wcx_pk_...' });

const { name, customization } = await wicarax.agent.getAppearance();
const { data: models } = await wicarax.models.list();

// wicarax.chat.send(...) would throw here: chat needs a secret key.
Result fieldWhat it holds
replyThe answer, ready to render
modelThe public model id that produced it
usageInput, output and total token counts for this exchange
idCompletion id, useful in your own logs
Heads up

The client refuses a secret key in a browser before any network call, and the check reads the key's prefix rather than which option carried it, so passing a wcx_sk_ value as publishableKey is still refused. A publishable key requires a browser origin, so using one from a server is refused even though the key is valid. Keep secret keys on your server.

Conversation history

Product chat is text-only. chat.send accepts a text message and text history; file and media attachments are refused by the API with 400 attachments_not_supported. The currently published SDK release still advertises an attachments option, so a new SDK release is required to remove it from the public types and examples. Do not send attachments in the meantime.

For material the agent should answer from, upload it to a Knowledge Base in the dashboard. Knowledge Base ingestion and custom avatar uploads are separate upload workflows and remain available.

The client is stateless and keeps nothing between calls. Hold the transcript in your own state and pass it back on each turn, oldest first.

history.ts
const history: ChatMessage[] = [];

const first = await wicarax.chat.send({ message: 'Do you offer annual plans?' });
history.push({ role: 'user', content: 'Do you offer annual plans?' });
history.push({ role: 'assistant', content: first.reply });

const second = await wicarax.chat.send({
  message: 'What is the refund window for those?',
  history,
});
  • Only user and assistant turns are used, and the SDK filters history to those two roles before sending, so a system turn never leaves your process. A raw API request that includes a system, developer, tool or function turn is refused with 400: instructions come from the dashboard and cannot be overridden by a request.
  • Keep failures out of the transcript. If a call throws, do not push an assistant turn, or the model will read your error message back as something it said.

An optional sessionId groups exchanges in the owner's chat log. It is limited to 64 characters by the API. The SDK does not truncate a longer value; choose a stable value within the limit or handle the validation error.

Which model answers

The SDK sends wicarax-zenith by default for existing callers. Pass model explicitly when the agent is configured for a different public model. The API rejects a known but unassigned id with model_not_assigned. Use the catalog when your interface needs to show available models; chat does not fetch it first.

model.ts
// Optional discovery for a model picker.
const { data } = await wicarax.models.list();
console.log(data.map((model) => model.id));

// Or after any answer, echoed by the API.
console.log(result.model);

Older clients send Zenith by default. If an agent is switched to another model, show the model_not_assigned error in your own chat interface and update the model passed to chat.send.

chat-error.ts
import { WicaraxError } from '@wicarax/sdk';

try {
  const answer = await wicarax.chat.send({ message, model: 'wicarax-pulse' });
  showAnswer(answer.reply);
} catch (error) {
  if (error instanceof WicaraxError && error.code === 'model_not_assigned') {
    showError(error.message);
  } else {
    throw error;
  }
}

Theming your interface

Your UI is yours, but you can read the same display values the hosted widget uses, so a custom interface stays consistent with what the agent owner configured.

appearance.ts
const appearance = await wicarax.agent.getAppearance();

appearance.name;                          // agent display name
appearance.customization.theme;           // light or dark surface
appearance.customization.primaryColor;    // widget color used by the hosted UI
appearance.customization.widgetLanguage;  // en or id for interface text
appearance.customization.welcomeMessage;  // first message to show
appearance.customization.placeholderText; // input placeholder

This call is read only and returns public display fields only. It never includes private Personalization instructions. It is most useful when whoever builds the interface is not whoever configured the agent, for example an agency shipping a frontend for a client. If you own the agent and are designing your own interface anyway, skip it and use chat.send alone.

Timeouts, cancellation and errors

Timeouts and cancellation

Requests time out after 60 seconds by default. Pass timeoutMs to change it, or 0 to disable it. Cancel an in-flight request with an AbortSignal, for example when the user edits their question or navigates away.

cancel.ts
const controller = new AbortController();
const promise = wicarax.chat.send({ message, signal: controller.signal });
controller.abort();

Errors

Every failure throws WicaraxError, which carries enough to decide what to do without parsing a message string.

errors.ts
import { WicaraxError } from '@wicarax/sdk';

try {
  await wicarax.chat.send({ message });
} catch (error) {
  if (error instanceof WicaraxError) {
    if (error.isRateLimited) {
      await wait((error.retryAfter ?? 5) * 1000);
    } else if (error.isCapabilityError) {
      // This key cannot do this. Today: chat.send with a publishable key.
      // Nothing was sent, so there is no status to inspect.
    } else if (error.isAuthError) {
      // Key, agent status or origin.
    } else if (error.isTimeout) {
      // Exceeded timeoutMs.
    }
  }
}
PropertyMeaning
statusHTTP status, when the failure came from the API. Absent for local errors, which never reached the network
typeError family, for example authentication_error
codeStable machine code, for example access_denied
paramThe request field the API blamed, when it named one, for example model or messages[1].name
retryAfterSeconds to wait, taken from the Retry-After header on 429

The full list of statuses and codes is on Errors.

What the SDK does not do

  • It does not create, edit or delete agents, and it cannot change any agent setting.
  • It does not manage keys, domains, plans or billing.
  • It does not stream, and it returns no citation or source data.
  • It ships no interface. That is the hosted widget’s job.

If you would rather not build an interface at all, use the widget. If you are working in a language the SDK does not cover, call the REST API directly.

Tip

Put a small endpoint of your own in front of the secret key. Your frontend calls your server, your server calls Wicarax, and the key never reaches a browser or a bundle.

Disclaimer

This client consumes an agent and nothing more. It cannot create or reconfigure anything, it does not stream, and it returns no citation or source data. If a future version adds capability, it will be additive rather than a change to what is documented here.