Skip to content

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.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

No 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.

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

Surfaces that can grow#

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

AreaClient treatmentWhy
Response envelopes and resource objectsAccept additional fieldsAdditive fields should not break deserialization
Error codesHandle known codes and keep an unknown fallbackNew failure cases can add codes
Voices, models, transcribersReference by id, never by display name or list positionProviders and catalogue entries can be added
Assistant settings sub-objectsIgnore keys your client does not useNew tuning options can appear here
WhatsApp onboarding statesKeep an unknown-state fallbackThe 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#