Ontology

Applying concepts and relations

Create concept instances and link documents into the ontology graph.

This tutorial uses POST /api/v1/ontology/concepts, POST /api/v1/ontology/relations, and GET /api/v1/files/{file_id}/ontology. The full schema lives in the API reference.

Your ontology schema exists. Now you'll create concept instances and relations that connect documents (and concepts) into a queryable graph.

Applying ontology data is a two-step act:

  1. Create concepts: standalone instances (Organization, Person, …) with validated attributes
  2. Create relations: edges from a file (or concept) to a target concept

Step 1: Upload a document

Before linking, you need a file. If you already have one, skip this step and use your existing file_id.

Replace workspace_id with your own. List workspaces via GET /api/v1/workspaces.

import { readFileSync } from "node:fs";

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

const form = new FormData();
form.append("file", new Blob([readFileSync("acme_nda_2025.pdf")]), "acme_nda_2025.pdf");
form.append("workspace_id", String(workspaceId));
form.append("title", "NDA with Acme Corp");

const file = await fetch("https://api.context212.com/api/v1/files", {
  method: "POST",
  headers,
  body: form,
}).then((r) => r.json());

console.log(file.id); // e.g. 42

Step 2: Create a concept

Concepts live in a workspace and must use a concept type from an ontology adopted in that same workspace.

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

const concept = await fetch("https://api.context212.com/api/v1/ontology/concepts", {
  method: "POST",
  headers: { ...headers, "Content-Type": "application/json" },
  body: JSON.stringify({
    workspace_id: 12,
    concept_type_id: organizationTypeId,
    label: "Acme Corp",
    attributes: { region: "EU" },
  }),
}).then((r) => r.json());

console.log(concept);
// { id, workspace_id, concept_type_id, label, attributes: { region: "EU" }, ... }

Attributes are validated against the concept type: required fields, data_type, and select_options. Invalid payloads return 422.

List and filter concepts

const params = new URLSearchParams({
  workspace_id: "12",
  concept_type_id: organizationTypeId,
  query: "Acme",
});
params.append("attribute", "region:EU|US");

const listed = await fetch(
  `https://api.context212.com/api/v1/ontology/concepts?${params}`,
  { headers: { Authorization: `Bearer ${process.env.C212_API_KEY}` } },
).then((r) => r.json());

console.log(listed.count, listed.results);

Attribute filter syntax: repeated attribute params are AND; | inside one value is OR; comparisons (>, >=, <, <=), prefixes (Casa*), and contains (*report*) are supported.

Create a relation from the file to the concept. Use a relation type whose source_concept_type_id is null (document source).

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

const relation = await fetch("https://api.context212.com/api/v1/ontology/relations", {
  method: "POST",
  headers: { ...headers, "Content-Type": "application/json" },
  body: JSON.stringify({
    relation_type_id: referencesTypeId,
    source_document_id: 42,
    target_concept_id: concept.id,
  }),
}).then((r) => r.json());

console.log(relation.id);

Rules enforced on create:

  • Exactly one of source_document_id / source_concept_id
  • Source and target types must match the relation type
  • File workspace must match the ontology workspace
  • Cardinality one_to_one / one_to_many rejects a second edge from the same source (409)

The first relation from a document under a given ontology inserts an immutable document_ontology_version row (audit trail for which schema version classified the file).

Step 4: Inspect the graph on a file

const graph = await fetch(
  "https://api.context212.com/api/v1/files/42/ontology?depth=2",
  { headers: { Authorization: `Bearer ${process.env.C212_API_KEY}` } },
).then((r) => r.json());

console.log(JSON.stringify(graph, null, 2));

Example response:

{
  "document_id": 42,
  "relations": [
    {
      "relation_type": { "key": "references", "label": "References" },
      "target_concept": {
        "id": "…",
        "label": "Acme Corp",
        "concept_type": { "key": "organization", "label": "Organization" },
        "attributes": { "region": "EU" }
      },
      "depth": 1
    }
  ]
}

depth is capped at 3. For edges starting from a concept, use GET /api/v1/ontology/concepts/{id}/relations?depth=1.

Update and delete

// PATCH /api/v1/ontology/concepts/{id}  — label and/or attributes
// DELETE /api/v1/ontology/concepts/{id} — 409 if relations still point at it
// DELETE /api/v1/ontology/relations/{id}

Next

With documents linked into the graph, filter Search and Ask with relations.

On this page