Ontology

Defining an ontology schema

Adopt templates and manage concept types and relation types — the schema that powers graph filters.

This tutorial uses GET /api/v1/ontology/templates, POST /api/v1/ontology/templates/{id}/adopt, and the /api/v1/ontologies/{id}/… type endpoints. The full schema lives in the API reference.

After this tutorial you'll have a workspace ontology with concept types and relation types — the schema that powers graph filtering. You define (or adopt) this once, then create as many concept instances and document links as you need.

There are two ways to get a schema:

  1. Adopt a starter template — clone a ready-made ontology into a workspace, then customize
  2. Build from scratch — create concept types and relation types on an adopted ontology (or extend a vertical kit)

Option A: Adopt a starter template

Browse templates, then adopt one into a workspace. Context212 ships vertical kits inspired by common document taxonomies:

KeyLabel
legalLegal (contracts, litigation, compliance, …)
healthcareHealthcare
financeFinance
techTechnology
manufacturingManufacturing

Each kit includes concept types (with parent_key for attribute inheritance), shared organization / person entities, and domain relation types such as classified_as, party_to / signed_by, and vertical-specific edges (e.g. governs in legal).

const headers = {
  Authorization: `Bearer ${process.env.C212_API_KEY}`,
};

const templates = await fetch(
  "https://api.context212.com/api/v1/ontology/templates",
  { headers },
).then((r) => r.json());

for (const ontology of templates) {
  console.log(`${ontology.key.padEnd(16)} ${ontology.label}  (${ontology.id})`);
}

Adopt into a workspace (replace IDs with your own):

const headers = {
  Authorization: `Bearer ${process.env.C212_API_KEY}`,
};

const response = await fetch(
  `https://api.context212.com/api/v1/ontology/templates/${templateId}/adopt`,
  {
    method: "POST",
    headers: { ...headers, "Content-Type": "application/json" },
    body: JSON.stringify({ workspace_id: 12 }),
  },
);

const ontology = await response.json();
console.log(ontology);
// { id, key, label, version: 1, is_template: false, adopted_from, workspace_id: 12, status: "active", ... }

Adoption clones concept types and relation types into a new workspace-owned ontology. After that, everything is fully editable — rename, add, or remove types. Adoption is a starting point, not a lock-in.

Example from the legal kit: concept type keys are plain snake_case (nda, contract) with parent_key for inheritance — attributes are defined only on the type that owns them (an NDA inherits jurisdiction from legal via the parent chain at validation time). Use classified_as from a file to a concept of that type (or any descendant of legal).

Option B: Add concept types

List types on your adopted ontology, then create more:

const headers = {
  Authorization: `Bearer ${process.env.C212_API_KEY}`,
};

const types = await fetch(
  `https://api.context212.com/api/v1/ontologies/${ontologyId}/concept-types`,
  { headers },
).then((r) => r.json());

console.log(types.map((t) => t.key));

const created = await fetch(
  `https://api.context212.com/api/v1/ontologies/${ontologyId}/concept-types`,
  {
    method: "POST",
    headers: { ...headers, "Content-Type": "application/json" },
    body: JSON.stringify({
      key: "incident",
      label: "Incident",
      attributes: [
        {
          key: "severity",
          label: "Severity",
          data_type: "select",
          select_options: ["low", "medium", "high", "critical"],
          required: true,
        },
        {
          key: "occurred_on",
          label: "Occurred on",
          data_type: "date",
          required: false,
        },
      ],
    }),
  },
).then((r) => r.json());

console.log(created.id, created.key);

Update or delete a type by ID:

// PATCH /api/v1/ontology/concept-types/{concept_type_id}
// DELETE /api/v1/ontology/concept-types/{concept_type_id}  → 409 if live instances exist

parent_id is optional and only for attribute inheritance — concept types are not a display tree.

Add relation types

Document-sourced edges use source_concept_type_id: null. Concept-to-concept edges set both type IDs.

const headers = {
  Authorization: `Bearer ${process.env.C212_API_KEY}`,
};

const relationType = await fetch(
  `https://api.context212.com/api/v1/ontologies/${ontologyId}/relation-types`,
  {
    method: "POST",
    headers: { ...headers, "Content-Type": "application/json" },
    body: JSON.stringify({
      key: "involves",
      label: "Involves",
      inverse_label: "Involved in",
      source_concept_type_id: null, // document source
      target_concept_type_id: personTypeId,
      cardinality: "many_to_many",
    }),
  },
).then((r) => r.json());

console.log(relationType.id, relationType.key);

Cardinality:

ValueBehaviour when creating another edge from the same source
many_to_manyAllowed (default)
one_to_many / one_to_one409 if that source already has this relation type

Version the schema

When you need a clean schema bump without mutating the version documents were classified against:

const next = await fetch(
  `https://api.context212.com/api/v1/ontologies/${ontologyId}/new-version`,
  {
    method: "POST",
    headers: { Authorization: `Bearer ${process.env.C212_API_KEY}` },
  },
).then((r) => r.json());

// Previous ontology → status "archived"
// New ontology → status "active", version = previous + 1, types cloned

Existing document_ontology_version rows keep pointing at the ontology ID that was active when the document received its first relation.

Next

With a schema in place, create concepts and link documents.

On this page