Get started
Versioning & stability
What counts as a breaking change, what you can rely on, and how to write a client that survives the API evolving.
Every response carries a version in its metadata:
{
"metadata": {
"timestamp": "2026-07-30T12:00:00.000Z",
"version": "1.0",
"path": "/assistants"
}
}Endpoints are served at the root path with no version prefix. The one exception is the organization-level audit endpoints, which sit under /v1:
POST /v1/retention/audits
POST /v1/churn/auditsNo published deprecation window
The public API does not currently guarantee a deprecation period or define version negotiation. metadata.version is informational; no documented client behavior is tied to it. Build against the current OpenAPI specification and monitor What's new for public contract changes.
Write a client that tolerates change#
Regardless of policy, these four habits make an integration durable. They cost nothing today and save a rewrite later.
Ignore unknown fields. Responses are open: new keys can appear on any object. Deserialize permissively; do not fail on a field you have not seen.
Branch on error.code, never on error.message. Codes are the stable contract. Messages are written for humans and may be reworded at any time.
Do not depend on key order or array order unless an endpoint explicitly documents an ordering. Task groups are ordered because order is the feature; assistant lists are not.
Treat IDs as opaque. They are UUIDs today. Parsing them, sorting by them, or inferring creation time from them will break.
interface Envelope<T> {
success: boolean;
data?: T;
error?: { code: string; message: string; details?: unknown };
}
// Narrow to what you use; ignore everything else the API sends.
interface AssistantSummary {
id: string;
name: string;
}
async function listAssistants(): Promise<AssistantSummary[]> {
const res = await fetch("https://core-api.heysadie.ai/assistants", {
headers: { Authorization: `ApiKey ${process.env.ONCORE_API_KEY}` },
});
const body = (await res.json()) as Envelope<{ assistants: AssistantSummary[] }>;
if (!body.success) {
// Branch on the code; the message is not a contract.
switch (body.error?.code) {
case "UNAUTHORIZED":
throw new Error("Check ONCORE_API_KEY");
default:
throw new Error(body.error?.code ?? "UNKNOWN");
}
}
return body.data?.assistants ?? [];
}Surfaces that can grow#
Some parts of the platform move faster than others. Plan accordingly:
| Area | Client treatment | Why |
|---|---|---|
| Response envelopes and resource objects | Accept additional fields | Additive fields should not break deserialization |
| Error codes | Handle known codes and keep an unknown fallback | New failure cases can add codes |
| Voices, models, transcribers | Reference by id, never by display name or list position | Providers and catalogue entries can be added |
Assistant settings sub-objects | Ignore keys your client does not use | New tuning options can appear here |
| WhatsApp onboarding states | Keep an unknown-state fallback | The workflow depends partly on Meta's platform |
Voice names are not unique
The same voice can appear once per underlying model, so two rows can share a display name. Always store and send voiceId.
Staying current#
- The interactive API explorer is generated from the running API, so it is always current. Treat it as the source of truth if this reference ever disagrees.
- What's new records newly documented capabilities and public contract changes.
/llms.txt: a machine-readable index of these docs, for agents and AI tooling.
Next steps#
- API conventions: pagination, identifiers, idempotency.
- Rate limits: retry and backoff.