Integration

REST API

Plain HTTP using the OpenAI Chat Completions shape. Server integrations use Chat Completions and read-only model and appearance endpoints. Hosted-widget session endpoints are managed by the widget.

Base URL and authentication

base url
https://api.wicarax.app

This is the intended production API origin. For local development, use your configured local API origin, commonly http://localhost:4000.

Every request carries the agent key as a bearer token. The key identifies the agent, so no request ever names one.

request header
Authorization: Bearer wcx_sk_YOUR_SECRET_KEY
KeyWhere it may be usedOrigin requirement
wcx_sk_Servers, scripts, automationsNone. Never expose it in a browser
wcx_pk_Browsers, for public reads and widget bootstrap. It cannot call chat completionsRequired. The request must come from an origin you allowed, so a publishable key will not work from a terminal

Core integration endpoints

MethodPathPurpose
POST/v1/chat/completionsAsk a question and receive the answer. See Chat Completions
GET/v1/modelsRead the public model id. See Models
GET/v1/agent/configRead the agent display name and cosmetic settings, for theming your own interface. Read only
GET/v1/widget.jsThe hosted widget loader. No authentication, since the embedding page supplies the key
Note

The hosted widget also uses session and message endpoints internally. The table is the core integration surface, not an exhaustive count of public routes. Agents, material, keys and plans are managed in the dashboard.

Your first request

terminal
curl https://api.wicarax.app/v1/chat/completions \
  -H "Authorization: Bearer $WICARAX_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "wicarax-zenith",
    "messages": [
      { "role": "user", "content": "What is your refund policy?" }
    ]
  }'

The response is a complete JSON body:

200 OK
{
  "id": "chatcmpl-...",
  "object": "chat.completion",
  "created": 1769500000,
  "model": "wicarax-zenith",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "Example answer based on your sources."
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 1254,
    "completion_tokens": 20,
    "total_tokens": 1274
  }
}

Using an OpenAI client

The request and response shapes follow the OpenAI chat completions format, so libraries and tools that already speak it need two changes: the base URL and the key. What they must not do is send parameters this API has not implemented: those are refused, not ignored, so a client configured with its usual defaults will get a 400 until they are removed.

openai-node
import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: process.env.WICARAX_SECRET_KEY,
  baseURL: 'https://api.wicarax.app/v1',
});

const completion = await client.chat.completions.create({
  model: 'wicarax-zenith',
  messages: [{ role: 'user', content: 'What is your refund policy?' }],
});
  • The model field is required and must be exactly wicarax-zenith. Anything else, including omitting it, is refused with 400 model_not_found. It does not select a model, because there is only one; it is a contract check that stops a client believing it chose something.
  • Default parameters are the common first failure. An OpenAI client or framework that sends temperature, max_tokens, stop or tools by default will be refused with 400 unsupported_parameter, and param will name the offending field.
  • Streaming is not supported. Sending stream: true is refused with 400 and the code streaming_not_supported, rather than being silently ignored, so a client cannot believe it opted in and then mis-parse the body.
  • system messages are refused, not dropped. They return 400 unsupported_parameter, because silently discarding a system prompt lets a caller believe they steered the assistant. Behaviour comes from the dashboard, not from the request.

Limits to design around

LimitValueWhat happens when exceeded
Request body sizeAbout 100 KB413 before the request is processed
Requests per minute across the accountSet by the plan, applied per account and shared by every agent you own429 with a Retry-After header
Requests per monthSet by the plan, applied to the accountThe call still succeeds, and the answer is a short unavailability message with zero usage
Failed credential attemptsBudgeted per network429 after repeated refusals, with Retry-After
Heads up

The monthly quota does not produce an error. A caller sees a normal 200 with a polite unavailability message, so if your integration starts returning that for everything, check the account rather than your code.

Exact numbers per plan are on Rate Limits, and every status and code is on Errors.

Errors

Failures use the OpenAI error envelope:

403 Forbidden
{
  "error": {
    "message": "Access denied for this request.",
    "type": "authentication_error",
    "param": null,
    "code": "access_denied"
  }
}

All four fields are always present. param names the request field at fault on a 400, and is null when no single field is to blame.

A malformed key, an unknown key, an inactive agent and a disallowed origin all answer with the same 403 access_denied. That is deliberate, so a scraped key cannot be confirmed by the response. Check the credential type, key state, agent state, and allowed origin before retrying.

Tip

Keep the key in an environment variable and pass it as a bearer token per request. Never place a secret key in a query string, where it ends up in server logs and browser history.

Disclaimer

There is no endpoint that writes configuration, and there is not going to be one in this surface. An API key can consume an agent, never reconfigure it, which is why a leaked key cannot be used to change your setup even though it can spend your allowance.