---
title: "Register a multimodal evidence asset (metadata-only)"
method: POST
path: "/v1/ingest/evidence-asset"
tags: ["Evidence"]
---

# Register a multimodal evidence asset (metadata-only)

`POST /v1/ingest/evidence-asset`

## Request

- Base URL: `https://brain.inite.ai`
- URL: `https://brain.inite.ai/v1/ingest/evidence-asset`
- Auth: HTTP bearer

Registers one multimodal evidence asset header (image / audio / video / document / sensor) plus optional citation-target fragments — WITHOUT transferring bytes. The surface is metadata-only by design (the MM-6 quarantine boundary): `originUri` (a caller-owned location the brain never fetches) is required, `storageRef` is rejected (400), and no upload is accepted, so a fresh registration is always availability `external`. `byteHash` (sha256 of the original bytes) is REQUIRED — the UNIQUE asset identity (migration 0109): same-user re-registration dedupes to the existing asset (`deduped: true`, requested fragments still appended); a different principal hitting a known hash gets a bare 409 without the stored row’s metadata. Fragment locators are validated against the kind→modality matrix BEFORE any row is written — one bad locator fails the whole request. A fragment `excerpt` lands as a caller-asserted `derived_representation` of kind `text` (producerVersion `ingest-excerpt-v1`). Answers a bare 404 until `EVIDENCE_INGEST_ENABLED=1`; answers 503 while `EVIDENCE_SUBSTRATE_ENABLED` is off. Source: src/evidence/evidence-ingest.controller.ts.

Required scope: `brain:write`.

## Request body

- IngestEvidenceAssetRequest
  - `byteHash` string, required
  - `byteLength` integer, required
  - `durationMs` integer
  - `fragments` IngestEvidenceFragment[]
    - `excerpt` string
    - `label` string
    - `lang` string
    - `locator` union, required
      - object
        - `end` integer, required
        - `kind` 'charRange', required
        - `start` integer, required
      - object
        - `h` number, required
        - `kind` 'pageRegion', required
        - `page` integer, required
        - `w` number, required
        - `x` number, required
        - `y` number, required
      - object
        - `endMs` integer, required
        - `kind` 'timeRange', required
        - `startMs` integer, required
      - object
        - `endFrame` integer, required
        - `kind` 'frameRange', required
        - `startFrame` integer, required
      - object
        - `endMs` integer
        - `kind` 'track', required
        - `startMs` integer
        - `trackId` string, required
    - `piiClasses` string[]
  - `height` integer
  - `mediaType` string, required
  - `meta` object
  - `modality` 'image' | 'audio' | 'video' | 'document' | 'sensor', required
  - `occurredAt` string, required
  - `originUri` string, required
  - `pageCount` integer
  - `piiClasses` string[]
  - `recorder` string
  - `retainUntil` string
  - `scope` string[]
  - `userId` string
  - `vertical` string, required
  - `width` integer

## Response `201`

Registered (or same-user deduped) asset + created fragments.

- IngestEvidenceAssetResponse
  - `assetId` string, required
  - `availability` 'hot' | 'cold' | 'external' | 'gone', required
  - `deduped` boolean, required
  - `fragments` IngestEvidenceFragmentResult[], required
    - `fragmentId` string, required
    - `representationId` string

## Other responses

- `400`: Validation failed.
- `401`: Missing or unknown bearer key.
- `403`: The key lacks the required scope.
- `404`: No such resource in this tenant.
- `409`: State conflict — e.g. a lost/mismatched claim token, an already claimed work item, or an immutable-version republish.
- `503`: The evidence write seam is off (EVIDENCE_SUBSTRATE_ENABLED) — the route exists but every write is refused. Boot-time env-validation warns about this inconsistent flag pair.

---

[API](https://skmtc.dev/inite/apis/inite-brain-platform-api.md) · [All operations](https://skmtc.dev/inite/apis/inite-brain-platform-api/llms.txt) · [OpenAPI document](https://skmtc.dev/inite/apis/inite-brain-platform-api/revisions/c7c3eb5e304b?raw)
