Skip to content

Getting 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.version
{
  "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:

text
POST /v1/retention/audits
POST /v1/churn/audits

TODO — verify before release

The change policy below describes the contract this documentation is written against. It has not yet been ratified by the API team — confirm the deprecation window, the announcement channel, and whether metadata.version will ever be incremented before this page ships.

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.

A tolerant client
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 ?? [];
}

What is expected to change#

Some parts of the platform move faster than others. Plan accordingly:

AreaStabilityWhy
Response envelope, error codesStableThe contract every endpoint shares
Resource IDs and core fieldsStableBreaking these breaks stored references
Voices, models, transcribersExpected to growNew providers and voices are added regularly — reference by id, never by display name
Assistant settings sub-objectsExpected to growNew tuning options land here first
WhatsApp onboarding statesExpected to changeDriven by Meta's platform, not solely by OnCore

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.
  • /llms.txt — a machine-readable index of these docs, for agents and AI tooling.

Next#