---
title: "Ontology Ledger API"
description: "Open subjects, append evidenced records, fold at a record time and a valid time, export STIX 2.1, and verify the seal"
canonical: https://y2.dev/docs/api/ontology-ledger/
---

# Ontology Ledger API

Open subjects, append evidenced records, fold at a record time and a valid time, export STIX 2.1, and verify the seal

The ledger API reads and writes your workspace's passive entity ledger. It requires a **workspace-bound** API key and does not accept x402 payment. For the concepts, start with [Ontology and Cyber-Market Fusion](https://y2.dev/docs/ontology).

The base URL is:

```
https://api.y2.dev/api/v2/ledger
```

## Operations

| Goal                                             | Operation                                        | Scope          |
| ------------------------------------------------ | ------------------------------------------------ | -------------- |
| List subjects, optionally anchored to one entity | `GET /subjects?entityId=ent_…`                   | `ledger:read`  |
| Open a subject, optionally anchored              | `POST /subjects`                                 | `ledger:write` |
| Fold one subject at the requested clocks         | `GET /subjects/{subjectId}?recordedAt=&validAt=` | `ledger:read`  |
| Export one subject as STIX 2.1                   | `GET /subjects/{subjectId}/stix`                 | `ledger:read`  |
| Export sealed lines                              | `GET /records?afterSeq=&limit=`                  | `ledger:read`  |
| Append a designator, observation, or claim       | `POST /records`                                  | `ledger:write` |
| Verify the seal over a window                    | `GET /verify?afterSeq=&limit=`                   | `ledger:read`  |

Writes also require an owner, admin, or member role for the key's user.

## Append a record

`POST /records` takes one record. The `kind` must match the payload key:

**Observation**

```
{
  "kind": "observation",
  "observation": {
    "method": "public-registry",
    "sourceGrade": "primary",
    "sourceUrl": "https://filings.example/northwind/annual",
    "retrievedAt": "2026-06-01T11:40:00Z",
    "excerpt": "Northwind relies on Contoso for fulfillment.",
    "collector": "filings-sync"
  }
}
```

`contentHash` is computed from the excerpt. Send it only when the excerpt is absent and `archiveUrl` holds the hashed content. Send `retrievedAt` when you fetched the page earlier. Omitted on a retrieval, it defaults to the time the line is recorded.

**Designator**

```
{
  "kind": "designator",
  "designator": { "kind": "external-id", "namespace": "sec-cik", "value": "320193" }
}
```

Values are canonicalized: this CIK is stored as `0000320193`. An existing designator with the same key is returned with `200` and `created: false`.

**Claim**

```
{
  "kind": "claim",
  "claim": {
    "predicate": "supplies",
    "from": "sbj_…supplier",
    "to": "sbj_…issuer",
    "confidence": 70,
    "verification": "located",
    "validFrom": "2025-12-31T00:00:00Z",
    "evidenceRefs": ["obv_…"],
    "note": "The issuer's own filing names the supplier."
  }
}
```

Send `supersedes` with the current head's `claimId` for every line after a claim key's first.

Send an `Idempotency-Key` header to make a retry safe: a replay returns the original record with `200`. Reusing a key with a different body returns `409 IDEMPOTENCY_CONFLICT`.

## Handle rule failures

A record that breaks a ledger rule is rejected before anything is written. `detail` lists each rule code and message.

| Status                 | When                                                                             |
| ---------------------- | -------------------------------------------------------------------------------- |
| `409 CONFLICT`         | `assertion.chain`: the line does not supersede the current head of its claim key |
| `400 VALIDATION_ERROR` | Any other rule, such as `assertion.verification` or `designator.value`           |
| `404 NOT_FOUND`        | The anchored entity or subject does not exist                                    |
| `403 FORBIDDEN`        | Personal key, missing role, or suspended seat                                    |

On `409`, fold the subject again to read the current head, then retry with `supersedes` set to it.

## Keep a copy in sync

Page `GET /records` from `afterSeq=0` and store each `line` verbatim. Resume from `meta.nextAfterSeq`. Because the log is append-only and sealed, a synced copy stays valid, and the offline checker can prove it matches what Y2 recorded. See [Export STIX and verify the seal](https://y2.dev/docs/ontology/how-to/export-and-verify).

## Read the fused view

Cyber-market fusion is an entity operation in the [Intel API](https://y2.dev/docs/api/intel): `GET /api/v2/entities/{entityId}/fusion` with `intel:explorer`. It uses the ledger's anchored subjects and supply ties to build the exposure path.

## Endpoint reference

[Ontology Ledger operations](https://y2.dev/docs/api/reference/ontology-ledger)

[Cyber-market fusion](https://y2.dev/docs/api/reference/intel/getEntityFusionV2)

[Ledger record format](https://y2.dev/docs/ontology/reference/ledger-format)

[Authentication](https://y2.dev/docs/api/authentication)
