Build with Yin and Yang through the Instachat API by SoulfulAI. Chat completions, Responses, web search and audio, with examples for your terminal and application.
This reference covers the public /v1 API for signed-in, account-managed integrations, including Instachat CLI. Chat and Responses use OpenAI-compatible request formats; the supported fields and differences are listed below.
https://brain.intch.cc/v1Use HTTPS for HTTP requests and WSS for realtime connections. Send JSON with Content-Type: application/json, except for audio uploads. Model IDs and JSON field names are case-sensitive in these examples.
Every request needs your account access token in the Authorization: Bearer <token> header. Sign in to your Instachat account. New accounts may need approval before inference is available; a valid token alone does not grant spending access.
The examples read INSTACHAT_ACCESS_TOKEN from your environment. Set it privately to the token supplied for your account. Keep it on your server or local machine; do not embed it in a public website, commit it, or include it in logs.
For Instachat CLI itself, use instachat login. The CLI manages its own credentials; setting this example environment variable is not a replacement for CLI sign-in. If your API token expires or is revoked, sign in again. A 401 does not return a replacement token.
The optional X-Instachat-Client request header checks that your token was issued for the app making the request. Send it when integrating one of the named clients: instachat-cli, instachat-desktop, web or desktop. Use the identity your sign-in flow was configured for, not an arbitrary app name.
For example, send X-Instachat-Client: instachat-cli with a token issued for Instachat CLI. The signed token’s client must match instachat-cli or instachat-desktop exactly; web and desktop require a token without a client scope. Unknown values and mismatches return 403 client_mismatch. Sign in through the intended app to obtain the matching token.
Omitting the header keeps existing integrations working. The header does not select a model, change the token’s scope or grant access. In live checks with a CLI-scoped token, omitting it and sending instachat-cli both succeeded; declaring web, desktop, instachat-desktop or an unknown value returned 403. Generic API examples below omit the optional header.
/v1/modelsyang is more powerful and the default for account-managed requests. yin is faster. Use these stable names; the models behind them can advance without changing your integration.
429 free_daily_limit_reached even with a valid token. Wait until the returned resets_at time (00:00 UTC), or review your plan. See error examples below; listing models does not prove inference allowance is available.curl --fail-with-body https://brain.intch.cc/v1/models \
-H "Authorization: Bearer $INSTACHAT_ACCESS_TOKEN"The JSON response has object: "list" and a data array. Each account-managed row includes:
| Field | Type | Contract |
|---|---|---|
id | string | The request model ID: yang or yin. The first catalog row is the default. |
object / created / owned_by | string / number / string | Model envelope: "model", 0, and "soulful". |
display_name / description | string | Human-readable name and task guidance. |
context_window | number | Current context capacity in tokens. |
max_output_tokens | number | null | Current declared output limit; null means no limit is declared in the catalog. |
capabilities | object | Boolean tools, images and reasoning flags. Check these before selecting a feature. |
Read limits and capabilities from this endpoint instead of hardcoding a snapshot. On plans where a Yang allowance applies, an exhausted allowance can run a request on Yin. Inspect the returned model to see which model answered.
/v1/chat/completionsSend the conversation in messages on each request. Your application owns the conversation history and any tool execution.
| Field | Type | Contract |
|---|---|---|
messages | array, required | A non-empty array of messages. Text messages have role and content. Use system, user and assistant for text conversations; tool results use role: tool and tool_call_id. |
model | string | yin or yang. Omitting it selects yang for an account-managed request. |
stream | boolean | Default false. true returns server-sent events. |
stream_options | object | Set include_usage: true to receive usage events when streaming. |
max_tokens / max_completion_tokens | integer | Output token control passed to the selected model. Choose one, within the catalog's limit. |
tools / tool_choice | array / string or object | Function definitions and selection. Tool objects use type: function with a nested function containing name, description and parameters. |
parallel_tool_calls | boolean | Passed to the selected model to control parallel function calls. |
temperature / top_p / top_k | number | Sampling controls. Valid ranges and combinations depend on the selected model. |
stop / seed | string or array / integer | Stop sequences and sampling seed, subject to model support. |
frequency_penalty / presence_penalty | number | Model-dependent repetition controls. |
response_format | object | Requested output format, subject to model support. |
reasoning / reasoning_effort / thinking | object / string / object | Model-dependent reasoning controls. Yin has a server-selected speed-oriented default when none is supplied. |
chat_template_kwargs / tool_stream | object / boolean | Advanced model-dependent controls; acceptance by the API does not guarantee support by every model. |
store | boolean | Only false is accepted. Chat completions does not provide stored-response retrieval. |
Unknown top-level fields receive 400 unsupported_parameter. Unsupported values can also be rejected by the selected model; OpenAI compatibility does not imply every OpenAI feature is available.
curl --fail-with-body https://brain.intch.cc/v1/chat/completions \
-H "Authorization: Bearer $INSTACHAT_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"model": "yin",
"messages": [
{
"role": "user",
"content": "Say hello in one sentence."
}
]
}'A successful JSON response uses object: "chat.completion", an id, created, model and choices. Read text from choices[0].message.content. Check finish_reason: stop means normal completion, length means the output limit was reached, and tool_calls means your application needs to handle function calls. Usage reports prompt_tokens, completion_tokens and total_tokens.
When the model returns message.tool_calls, validate the function name and arguments, execute the permitted function in your application, then send the assistant message and a role: "tool" result with its matching tool_call_id in your next request. The API does not execute your functions.
For a model whose catalog declares image support, message content can contain text parts (type: "text", text) and image parts (type: "image_url", image_url.url). Image acceptance and limits depend on the selected model.
Set stream: true. Chat completions returns text/event-stream: each data: line contains a JSON chunk, followed by data: [DONE] on normal completion. Read incremental text from choices[0].delta.content and accumulate tool-call argument fragments before parsing them.
curl --fail-with-body --no-buffer https://brain.intch.cc/v1/chat/completions \
-H "Authorization: Bearer $INSTACHAT_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"model": "yin",
"messages": [
{
"role": "user",
"content": "Write a haiku about coding."
}
],
"stream": true,
"stream_options": {
"include_usage": true
}
}'A usage event may have an empty choices array. Check its length before accessing a choice. Inspect every event for an error, even after HTTP 200; a broken connection is not proof of a completed answer. Cancelling the request cancels the upstream read. The service does not automatically replay a managed inference request.
/v1/responsesAn alternative to Chat Completions with typed output items and optional stored conversation chaining.
| Field | Type | Contract |
|---|---|---|
input | string or array, required | Non-empty text, or message/function_call/function_call_output items. Messages accept user, assistant, system and developer roles; developer is treated as system. |
model / instructions | string / string | yin or yang (default yang); optional instructions for this request only. |
store | boolean | Defaults to true. Stored responses are available to their creating identity for 30 days. Use false to disable this response store. |
previous_response_id | string | Continue a stored response owned by your identity. Up to the last 60 stored chat messages are carried forward; earlier instructions are not inherited. |
stream / max_output_tokens | boolean / integer | Enable semantic SSE events, or set the output token limit. |
tools / tool_choice / parallel_tool_calls | array / string or object / boolean | Function tools only. Responses function definitions use type, name, description and parameters at the top level. |
temperature / top_p / reasoning | number / number / object | Model-dependent controls. |
metadata | object | Application metadata returned with the response. |
background | boolean | true is rejected. There is no background or cancel API. |
Message content arrays accept input_text, output_text, text and input_image parts. Function calls use call_id, name and JSON-encoded arguments; results use function_call_output with the matching call_id and output.
Hosted tools such as web search, file search and MCP are rejected with 400 unsupported_tool_type. Call the web search endpoint separately from your application. Unknown top-level fields are rejected.
curl --fail-with-body https://brain.intch.cc/v1/responses \
-H "Authorization: Bearer $INSTACHAT_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"model": "yin",
"input": "Say hello in one sentence.",
"store": true
}'The response contains id, object: "response", status, model, output and usage. Text is inside message output items' content parts of type output_text; function calls are separate output items. Usage uses input_tokens, output_tokens and total_tokens. Inspect status: incomplete with incomplete_details.reason: "max_output_tokens" means the answer hit its limit.
Copy the created response's id into INSTACHAT_RESPONSE_ID. These requests use the same account token. Missing, expired, deleted or another identity's responses return 404.
/v1/responses/{id}# Set this to the id returned by the create example above.
: "${INSTACHAT_RESPONSE_ID:?Set INSTACHAT_RESPONSE_ID to your response id}"
curl --fail-with-body https://brain.intch.cc/v1/responses/"$INSTACHAT_RESPONSE_ID" \
-H "Authorization: Bearer $INSTACHAT_ACCESS_TOKEN"/v1/responses/{id}# Deletes only the response you just created.
: "${INSTACHAT_RESPONSE_ID:?Set INSTACHAT_RESPONSE_ID to your response id}"
curl --fail-with-body -X DELETE https://brain.intch.cc/v1/responses/"$INSTACHAT_RESPONSE_ID" \
-H "Authorization: Bearer $INSTACHAT_ACCESS_TOKEN"Deletion returns the response id, object: "response" and deleted: true.
curl --fail-with-body --no-buffer https://brain.intch.cc/v1/responses \
-H "Authorization: Bearer $INSTACHAT_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"model": "yin",
"input": "Write a haiku about coding.",
"store": false,
"stream": true
}'Responses streams use named events and increasing sequence_number values. Handle response.created, response.in_progress, response.output_text.delta and response.completed. Function arguments use response.function_call_arguments.delta and .done. Also handle response.incomplete, response.failed and error. This stream does not use Chat Completions' [DONE] marker.
Use the OpenAI Python or JavaScript/TypeScript SDK with the Instachat base URL and your account token. These examples disable automatic retries so one invocation does not silently repeat a paid request. They demonstrate Chat Completions compatibility, not every feature of those SDKs.
# Install: python -m pip install openai
import os
from openai import OpenAI
client = OpenAI(
base_url="https://brain.intch.cc/v1",
api_key=os.environ["INSTACHAT_ACCESS_TOKEN"],
max_retries=0,
)
response = client.chat.completions.create(
model="yin",
messages=[{"role": "user", "content": "Say hello in one sentence."}],
)
print(response.choices[0].message.content)// Install: npm install openai
// Save as hello.mjs and run: node hello.mjs
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://brain.intch.cc/v1",
apiKey: process.env.INSTACHAT_ACCESS_TOKEN,
maxRetries: 0,
});
const response = await client.chat.completions.create({
model: "yang",
messages: [{ role: "user", content: "Say hello in one sentence." }],
});
console.log(response.choices[0].message.content);import os
from openai import OpenAI
client = OpenAI(
base_url="https://brain.intch.cc/v1",
api_key=os.environ["INSTACHAT_ACCESS_TOKEN"],
max_retries=0,
)
stream = client.chat.completions.create(
model="yin",
messages=[{"role": "user", "content": "Write a haiku about coding."}],
stream=True,
stream_options={"include_usage": True},
)
for chunk in stream:
# Usage-only events can have an empty choices array.
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
if chunk.usage:
print("\nTokens:", chunk.usage.total_tokens)
print()/v1/searchRetrieve search results directly, without a model call.
| Field | Type | Contract |
|---|---|---|
query | string, required | 1 to 400 characters after trimming. |
limit | integer | 1 to 10; default 5. Filters can produce fewer results. |
allowed_domains / blocked_domains | string arrays | Up to 10 bare hostnames each, such as example.com. |
freshness | string | "auto" (default) selects a recency window for time-sensitive queries; "none" disables that selection. |
curl --fail-with-body https://brain.intch.cc/v1/search \
-H "Authorization: Bearer $INSTACHAT_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "Instachat SoulfulAI",
"limit": 3,
"freshness": "none"
}'The response contains results (each with title, url and snippet), searched_at (UTC timestamp) and provider. Search errors have error.type and error.message; they do not require an error.code.
/v1/audio/speechSend JSON with required input text (at most 2,000 characters), optional language and response_format. Use ogg (default), wav, pcm or m4a. The response is audio bytes, not JSON. WAV and PCM use mono PCM16 at 24 kHz. Request WAV explicitly for this example; an unrecognized format, including mp3, falls back to OGG.
curl --fail-with-body --output hello.wav https://brain.intch.cc/v1/audio/speech \
-H "Authorization: Bearer $INSTACHAT_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"input": "Hello from Instachat.",
"response_format": "wav"
}'/v1/audio/transcriptionsUpload a multipart file, at most 10 MiB. The response is JSON with a text field. Language is detected automatically; a supplied transcription language field is accepted but does not override detection. The following request transcribes the file made above.
# Run the speech example first to create hello.wav, or use your own audio file.
curl --fail-with-body https://brain.intch.cc/v1/audio/transcriptions \
-H "Authorization: Bearer $INSTACHAT_ACCESS_TOKEN" \
-F "file=@hello.wav"/v1/realtime/modelsList the voice model choices. The JSON response includes object: "list", default and data. Voice model choices are separate from the chat model catalog.
curl --fail-with-body https://brain.intch.cc/v1/realtime/models \
-H "Authorization: Bearer $INSTACHAT_ACCESS_TOKEN"/v1/realtimeThis is a WebSocket upgrade, not an HTTP JSON endpoint. Connect over WSS with a Bearer header. Browser WebSocket clients can authenticate using the openai-insecure-api-key.<token> subprotocol; never place a shared secret in a browser bundle.
// Install: npm install ws
// Save as connect.mjs and run: node connect.mjs
import WebSocket from "ws";
const socket = new WebSocket("wss://brain.intch.cc/v1/realtime", {
headers: { Authorization: `Bearer ${process.env.INSTACHAT_ACCESS_TOKEN}` },
});
const timeout = setTimeout(() => {
console.error("Timed out waiting for session.created");
process.exitCode = 1;
socket.terminate();
}, 15000);
socket.on("message", (data) => {
const event = JSON.parse(data.toString());
if (event.type === "session.created") {
console.log(event.type);
socket.close(); // Connection check only; no microphone or audio is sent.
} else if (event.type === "error") {
console.error(event);
process.exitCode = 1;
socket.close();
}
});
socket.on("error", (error) => {
console.error(error.message);
process.exitCode = 1;
});
socket.on("close", () => clearTimeout(timeout));The check waits for session.created and closes. It does not start a voice conversation. The voice protocol uses session.*, input_audio_buffer.*, response.output_audio.delta (base64 PCM16 at 24 kHz) and response.done. Contact hello@soulful-ai.org for production voice integration guidance.
HTTP errors are JSON. Chat and Responses errors contain error.message, error.type, error.code and optionally error.param. Codes can be null. Search uses its own type names; audio errors may omit param.
| Status | Meaning and next step |
|---|---|
| 400 | Invalid JSON, missing fields or unsupported parameters/tools. Fix the request before retrying. |
| 401 | Missing, expired, revoked or invalid token. Sign in again. Chat/model auth uses invalid_api_key; search uses unauthenticated. |
| 403 | Account approval, model policy or token/client mismatch. Chat/Responses may return account_pending_approval, model_not_allowed or client_mismatch. |
| 404 | Stored response not found or unavailable to your identity. |
| 429 | Request quota, spending limit or upstream capacity limit. Inspect the error and honor Retry-After when present. |
| 500 / 502 / 503 / 504 | Server failure, upstream failure, unavailable service or timeout. Retry with bounded backoff if appropriate; retain partial-stream state to avoid repeating tool side effects. |
The 401, free-limit 429, 403 and 404 examples were observed on Chat Completions and stored-response retrieval. The spend-ceiling example shows the stable response shape with placeholders. Use the reset timestamp and retry delay returned for your request.
{
"error": {
"message": "Missing or invalid Authorization header. Expected: Bearer <token>",
"type": "invalid_request_error",
"param": null,
"code": "invalid_api_key"
}
}HTTP 429
Retry-After: 42316
{
"error": {
"message": "You've reached today's free usage limit. It resets at 00:00 UTC; upgrade to Instachat Pro for more.",
"type": "rate_limit_error",
"code": "free_daily_limit_reached",
"param": null,
"resets_at": "2026-09-23T00:00:00.000Z"
}
}spend_ceiling_reached is the account daily-spend safety brake, including for paid or prepaid usage. It is distinct from the free daily allowance. The response has HTTP 429, a Retry-After header in seconds and the fields below. Treat message as a human-readable explanation including today’s spend and the limit; its wording can change. Use code for programmatic handling and wait until error.resets_at before retrying.
HTTP 429
Retry-After: <seconds until reset>
{
"error": {
"message": "<human-readable explanation including today’s spend and the limit>",
"type": "rate_limit_error",
"code": "spend_ceiling_reached",
"param": null,
"resets_at": "<UTC reset timestamp>"
}
}{
"error": {
"message": "This session was issued for instachat-cli, not web. Sign in again from this app.",
"type": "invalid_request_error",
"param": null,
"code": "client_mismatch"
}
}{
"error": {
"message": "Response 'resp_dummy_nonexistent' not found.",
"type": "invalid_request_error",
"param": null,
"code": "response_not_found"
}
}For free_daily_limit_reached, the live free-account response includes Retry-After in seconds until the daily reset at 00:00 UTC, alongside error.resets_at. Repeated retries before that reset will not restore allowance. The OpenAI SDK reports this HTTP status as RateLimitError. Check the error code before deciding whether a retry is useful.
An HTTP 200 stream can still fail later. Treat explicit stream error events or an unexpected disconnect as failure, not successful completion.
Chat Completions and Responses share an account request quota. Requests also pass account approval and spending checks. Limits can change during early access; a request quota is not a guarantee of remaining daily allowance or capacity.
| Surface | Configured request limit |
|---|---|
| Chat Completions and Responses, combined | 1,000 requests per hour per account |
| Search | 30 per 10 minutes and 200 per day per account |
| Audio, each endpoint | 30 per minute |
Account inference quotas and search quotas return Retry-After in seconds. It is not guaranteed for every 429, including audio and some upstream failures. For a daily-allowance error, wait until resets_at. For transient capacity errors without a retry header, use bounded exponential backoff with jitter. Do not retry approval, billing or invalid-request errors unchanged.
Token usage fields describe consumption, not a price quote. Check your account's current terms for billing and allowances.