> For the complete documentation index, see [llms.txt](https://docs.pal.aic.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.pal.aic.io/using-pal.net/ontology.md).

# Ontology

The Ontology client supports dynamic, metadata-driven access when customer definitions are not known at compile time. It preserves exact API names and unknown JSON values so customer-specific schemas can evolve without forcing an SDK release.

## Register the client

```csharp
services.AddPalantir(options);
services.AddPalantirOntology();
```

Resolve `IPalOntologyClient` from a scope.

## Discover object types

```csharp
var types = await ontology.ListObjectTypesAsync(
    "my-ontology",
    branch: "master",
    cancellationToken: cancellationToken);

foreach (var type in types.Items)
{
    Console.WriteLine($"{type.ApiName}: {type.PrimaryKeys.Count} primary key(s)");
    foreach (var property in type.Properties.Values)
        Console.WriteLine($"  {property.ApiName} ({property.DataType})");
}

var employeeType = await ontology.GetObjectTypeAsync(
    "my-ontology", "employee", cancellationToken: cancellationToken);
```

`PalOntologyObjectType` includes API name, display metadata, RID, status, primary keys, properties, interfaces, and links. Property data types and specialised metadata remain `JsonElement` for forward compatibility.

## Read and enumerate objects

```csharp
var employee = await ontology.GetObjectAsync(
    "my-ontology",
    "employee",
    primaryKey: "E-1001",
    selectedProperties: ["employeeId", "displayName"],
    cancellationToken: cancellationToken);

if (employee.TryGetProperty("displayName", out var displayName))
    Console.WriteLine(displayName.GetString());

await foreach (var item in ontology.EnumerateObjectsAsync(
    "my-ontology",
    "employee",
    new PalOntologyListOptions { PageSize = 100 },
    cancellationToken))
{
    Console.WriteLine(item.PrimaryKey);
}
```

`EnumerateObjectsAsync` follows continuation tokens lazily and stops if the upstream repeats a page token, preventing an infinite loop. The page API remains available when the caller needs explicit checkpointing.

## Search

`PalOntologySearchRequest` represents the published `where` and `orderBy` JSON clauses without inventing a PAL-specific query language:

```csharp
var search = new PalOntologySearchRequest
{
    Where = JsonSerializer.SerializeToElement(new
    {
        property = "status",
        @operator = "eq",
        value = "ACTIVE"
    }),
    PageSize = 50,
    Select = ["employeeId", "displayName"]
};

var matches = await ontology.SearchObjectsAsync(
    "my-ontology", "employee", search, cancellationToken);
```

Use the exact where/order structure supported by the target upstream API version. PAL.NET validates page size and selected property names but does not reinterpret the upstream expression grammar.

## Apply actions

```csharp
var action = new PalApplyActionRequest
{
    Options = new PalApplyActionOptions
    {
        Mode = "VALIDATE_AND_EXECUTE",
        ReturnEdits = "ALL"
    },
    Parameters = new Dictionary<string, JsonElement?>
    {
        ["employeeId"] = JsonSerializer.SerializeToElement("E-1001"),
        ["newStatus"] = JsonSerializer.SerializeToElement("ACTIVE")
    }
};

var result = await ontology.ApplyActionAsync(
    "my-ontology",
    "activateEmployee",
    action,
    new PalApplyActionContext { Branch = "master" },
    cancellationToken);
```

In application code, prefer a helper that creates `JsonElement` values with `JsonSerializer.SerializeToElement` to keep the example readable. Action parameter names are preserved exactly. Standard batches contain 1–20 requests and do not accept a transaction identifier.

## Generated customer clients

When an Ontology schema is stable and used heavily, generate strongly typed customer contracts and clients. The generator records the source metadata and hash; keep generated output separate from hand-authored code. Use the dynamic client when definitions change frequently or generation is not practical. `PalOntologyObjectMapper.Deserialize<T>` maps a dynamic object into a generated contract while retaining unknown fields in the generated model's extension data when supported.
