> ## Documentation Index
> Fetch the complete documentation index at: https://developers.lighton.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Define content types and attributes

> Create, modify, and organise your company's content-type trees and their
attributes. Every action is idempotent, safe to re-run.

**Two ways to build your schema:**

1. **Adopt from starter templates**: import ready-made trees from the seed
   catalog (`GET /api/v3/content-types/templates`). Once adopted, they're
   yours to customize.
2. **Build from scratch**: create your own trees, nodes, and attributes
   entirely with `define_content_type` and `define_attribute`.

You can mix both: adopt `legal` from the seeds, then add a custom
`compliance` tree alongside it. Each tree is independent.

**Actions:**
- `adopt`: import trees from the seed catalog (starter templates)
- `define_content_type`: create or update a tree node (root or child)
- `undefine_content_type`: delete a node and its entire subtree
- `define_attribute`: add or update a metadata field on a node
- `undefine_attribute`: remove a metadata field

**Building a tree from scratch, example flow:**

1. Create a root:
   ```json
   {"action": "define_content_type", "code": "compliance", "label": "Compliance"}
   ```
2. Add children:
   ```json
   {"action": "define_content_type", "parent_path": "compliance", "code": "audit-report", "label": "Audit Report"}
   ```
3. Add attributes:
   ```json
   {"action": "define_attribute", "content_type_path": "compliance", "name": "owner", "attribute_type": "text"}
   ```
4. Classify files via `POST /api/v3/files/{id}/facets`:
   ```json
   {"action": "classify", "content_type_path": "compliance:audit-report"}
   ```

**Attributes** are metadata fields you define on each node. Types:
`text`, `number`, `date`, `boolean`, `select`, `multi-select`, `rich-text`.
`select` and `multi-select` require `choices`. Attributes inherit down the
tree: define `jurisdiction` on `legal` and it's available on all children.

**Description best practices:** The `description` field on attributes feeds
into the scope inference endpoint (`POST /api/v3/content-types/scope`),
where it helps the LLM generate accurate search filters. Use keywords that
signal the attribute's nature:
- **Person names**: include "name", "examiner", "inventor", or "author" →
  enables `*value*` wildcard syntax hints
- **Codes/identifiers**: include "code", "classification", or "identifier" →
  enables exact-match hints (don't guess from topic keywords)

**Multi-classification:** A single document can be classified under multiple
content types from different trees (e.g., both `legal:contract:nda` and
`compliance:audit-report`).

Available seed roots for `adopt`: finance, healthcare, legal, manufacturing, tech

Requires admin-level access to modify the company's schema.



## OpenAPI

````yaml /api-reference/api-console.yaml post /api/v3/content-types
openapi: 3.1.0
info:
  title: LightOn API
  version: 3.13.0 (v1)
  description: >-
    LightOn gives you an API to search, parse, and ingest documents at scale.
    Build knowledge-retrieval pipelines without managing vector databases or OCR
    models.
servers:
  - url: https://api.lighton.ai
security: []
tags:
  - name: Ask
    description: >-
      Retrieval-augmented generation: search your indexed corpus and generate an
      LLM answer grounded in the retrieved passages. Supports streaming (SSE)
      and synchronous modes.
  - name: Search
    description: >-
      Hybrid vector + text retrieval over your indexed corpus. Returns ranked
      passages with provenance (file, page range, workspace). Optional reranking
      and vision mode.
  - name: Files
    description: Upload, list, fetch, and delete documents indexed in your workspaces.
  - name: Facets
    description: >-
      Organise documents with hierarchical content types and custom attributes
      per file. Start from starter templates or build your own classification
      schema from scratch.
  - name: Tags
    description: >-
      Manage flat, company-wide labels used to scope search and group content
      across workspaces.
  - name: Workspaces
    description: >-
      Create and manage workspaces — the access-controlled containers your
      documents live in.
  - name: Parse
    description: >-
      Convert documents into structured Markdown — PDFs, images, Office files,
      and HTML. Synchronous endpoint capped at 20 MB / 15 pages.
  - name: Extract
    description: >-
      Pull typed fields out of documents using a JSON Schema you provide. Sync
      mode for small documents (≤20 MB / 15 pages); async mode for larger jobs
      (≤100 MB / 1000 pages) with polling on a job ID.
  - name: API Keys
    description: >-
      Provision and revoke API keys used to authenticate against the Console
      API.
  - name: Budget
    description: >-
      Manage your organization's monthly spend budget and alert thresholds. Set
      a hard cap that blocks API requests when reached, and configure email
      notifications at custom spend percentages.
paths:
  /api/v3/content-types:
    post:
      tags:
        - Facets
      summary: Define content types and attributes
      description: >-
        Create, modify, and organise your company's content-type trees and their

        attributes. Every action is idempotent, safe to re-run.


        **Two ways to build your schema:**


        1. **Adopt from starter templates**: import ready-made trees from the
        seed
           catalog (`GET /api/v3/content-types/templates`). Once adopted, they're
           yours to customize.
        2. **Build from scratch**: create your own trees, nodes, and attributes
           entirely with `define_content_type` and `define_attribute`.

        You can mix both: adopt `legal` from the seeds, then add a custom

        `compliance` tree alongside it. Each tree is independent.


        **Actions:**

        - `adopt`: import trees from the seed catalog (starter templates)

        - `define_content_type`: create or update a tree node (root or child)

        - `undefine_content_type`: delete a node and its entire subtree

        - `define_attribute`: add or update a metadata field on a node

        - `undefine_attribute`: remove a metadata field


        **Building a tree from scratch, example flow:**


        1. Create a root:
           ```json
           {"action": "define_content_type", "code": "compliance", "label": "Compliance"}
           ```
        2. Add children:
           ```json
           {"action": "define_content_type", "parent_path": "compliance", "code": "audit-report", "label": "Audit Report"}
           ```
        3. Add attributes:
           ```json
           {"action": "define_attribute", "content_type_path": "compliance", "name": "owner", "attribute_type": "text"}
           ```
        4. Classify files via `POST /api/v3/files/{id}/facets`:
           ```json
           {"action": "classify", "content_type_path": "compliance:audit-report"}
           ```

        **Attributes** are metadata fields you define on each node. Types:

        `text`, `number`, `date`, `boolean`, `select`, `multi-select`,
        `rich-text`.

        `select` and `multi-select` require `choices`. Attributes inherit down
        the

        tree: define `jurisdiction` on `legal` and it's available on all
        children.


        **Description best practices:** The `description` field on attributes
        feeds

        into the scope inference endpoint (`POST /api/v3/content-types/scope`),

        where it helps the LLM generate accurate search filters. Use keywords
        that

        signal the attribute's nature:

        - **Person names**: include "name", "examiner", "inventor", or "author"
        →
          enables `*value*` wildcard syntax hints
        - **Codes/identifiers**: include "code", "classification", or
        "identifier" →
          enables exact-match hints (don't guess from topic keywords)

        **Multi-classification:** A single document can be classified under
        multiple

        content types from different trees (e.g., both `legal:contract:nda` and

        `compliance:audit-report`).


        Available seed roots for `adopt`: finance, healthcare, legal,
        manufacturing, tech


        Requires admin-level access to modify the company's schema.
      operationId: api_v3_content_types_create
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ContentTypeActionRequest'
            examples:
              AdoptSeedRoots:
                value:
                  action: adopt
                  content_types:
                    - legal
                    - finance
                summary: Adopt seed roots
              DefineACompany-originalRootNode:
                value:
                  action: define_content_type
                  code: compliance
                  label: Compliance
                  description: Internal compliance artefacts
                summary: Define a company-original root node
              DefineAChildNodeUnderAnExistingParent:
                value:
                  action: define_content_type
                  parent_path: compliance
                  code: audit-report
                  label: Audit Report
                summary: Define a child node under an existing parent
              UpdateAnExistingNode'sLabel:
                value:
                  action: define_content_type
                  parent_path: compliance
                  code: audit-report
                  label: Internal Audit Report
                summary: Update an existing node's label
                description: Same (parent_path, code) as an earlier call, updates in place.
              DeleteANodeAndCascadeItsSubtree:
                value:
                  action: undefine_content_type
                  content_type_path: compliance:audit-report
                summary: Delete a node and cascade its subtree
              DefineAnAttributeColumnOnANode:
                value:
                  action: define_attribute
                  content_type_path: legal:contract:nda
                  name: jurisdiction
                  attribute_type: multi-select
                  choices:
                    - FR
                    - US
                    - UK
                    - DE
                    - CH
                summary: Define an attribute column on a node
              DefineATextAttribute(personName):
                value:
                  action: define_attribute
                  content_type_path: legal:contract:nda
                  name: counterparty
                  attribute_type: text
                  description: Name of the counterparty or signing entity
                  required: true
                summary: Define a text attribute (person name)
              DefineATextAttribute(code/identifier):
                value:
                  action: define_attribute
                  content_type_path: patent
                  name: uspc_class
                  attribute_type: text
                  description: USPC classification code for the patent
                summary: Define a text attribute (code/identifier)
              DefineANumberAttribute:
                value:
                  action: define_attribute
                  content_type_path: finance:report
                  name: amount
                  attribute_type: number
                summary: Define a number attribute
              DefineADateAttribute:
                value:
                  action: define_attribute
                  content_type_path: legal:contract
                  name: effective_date
                  attribute_type: date
                summary: Define a date attribute
              DefineABooleanAttribute:
                value:
                  action: define_attribute
                  content_type_path: legal:contract:nda
                  name: is_mutual
                  attribute_type: boolean
                summary: Define a boolean attribute
              DefineASelectAttribute:
                value:
                  action: define_attribute
                  content_type_path: tech:specification
                  name: maturity
                  attribute_type: select
                  choices:
                    - Draft
                    - Approved
                    - Deprecated
                summary: Define a select attribute
              DefineARichTextAttribute:
                value:
                  action: define_attribute
                  content_type_path: legal
                  name: summary
                  attribute_type: rich-text
                  description: Long-form human-authored summary text.
                summary: Define a rich text attribute
              RemoveAnAttributeColumn:
                value:
                  action: undefine_attribute
                  content_type_path: legal:contract:nda
                  name: jurisdiction
                summary: Remove an attribute column
        required: true
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ContentTypeWrite200Response'
              examples:
                AdoptedLegalSeed:
                  value:
                    content_types:
                      - path: legal
                        code: legal
                        label: Legal
                        children:
                          - path: legal:contract
                            code: contract
                            label: Contract
                  summary: Adopted legal seed
                UpdatedCompanyNode:
                  value:
                    path: compliance:audit-report
                    code: audit-report
                    label: Internal Audit Report
                  summary: Updated company node
          description: >-
            Action completed: existing node updated or already-present attribute
            replaced
        '201':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ContentTypeWrite201Response'
              examples:
                NewCompanyNode:
                  value:
                    path: compliance
                    code: compliance
                    label: Compliance
                  summary: New company node
                NewSelectAttribute:
                  value:
                    name: maturity
                    label: Maturity
                    type: select
                    required: false
                    description: ''
                    choices:
                      - Draft
                      - Approved
                      - Deprecated
                  summary: New select attribute
          description: New node or attribute column created
        '204':
          description: Node or attribute deleted (cascade for nodes)
        '400':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/APIV3ErrorResponse'
              examples:
                AttributeTypeImmutable:
                  value:
                    id: null
                    code: 400
                    error: attribute_type_immutable
                    detail: >-
                      Cannot change the type of attribute 'jurisdiction' from
                      'text' to 'select'. Delete and recreate the attribute to
                      change its type.
                    doc_url: >-
                      https://developers.lighton.ai/errors#attribute_type_immutable
                  summary: Attribute type immutable
                AttributeNameReserved:
                  value:
                    id: null
                    code: 400
                    error: attribute_name_reserved
                    detail: '''id'' is a reserved attribute name.'
                    doc_url: >-
                      https://developers.lighton.ai/errors#attribute_name_reserved
                  summary: Attribute name reserved
                AttributeNameConflict:
                  value:
                    id: null
                    code: 400
                    error: attribute_name_conflict
                    detail: >-
                      Attribute 'jurisdiction' is already defined on 'legal' in
                      the same tree. Attribute names must be unique across the
                      entire tree.
                    doc_url: >-
                      https://developers.lighton.ai/errors#attribute_name_conflict
                  summary: Attribute name conflict
                ContentTypeDepthExceeded:
                  value:
                    id: null
                    code: 400
                    error: content_type_depth_exceeded
                    detail: >-
                      Content type depth would exceed the maximum of 4 levels
                      (got depth 4).
                    doc_url: >-
                      https://developers.lighton.ai/errors#content_type_depth_exceeded
                  summary: Content type depth exceeded
          description: Invalid request or attribute constraint violated
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/APIV3ErrorResponse'
              examples:
                Unauthorized:
                  value:
                    id: null
                    code: 401
                    error: unauthorized
                    detail: >-
                      Authentication credentials were not provided or are
                      invalid.
                    doc_url: https://developers.lighton.ai/errors#unauthorized
          description: Authentication credentials were not provided or are invalid
        '403':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/APIV3ErrorResponse'
              examples:
                Forbidden:
                  value:
                    id: null
                    code: 403
                    error: insufficient_permissions
                    detail: You do not have permission to perform this action.
                    doc_url: >-
                      https://developers.lighton.ai/errors#insufficient_permissions
          description: Insufficient permissions
        '404':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/APIV3ErrorResponse'
              examples:
                ContentTypeNotFound:
                  value:
                    id: null
                    code: 404
                    error: content_type_not_found
                    detail: >-
                      Content type 'legal:nonexistent' not found for this
                      company.
                    doc_url: >-
                      https://developers.lighton.ai/errors#content_type_not_found
                  summary: Content type not found
          description: Parent or target content type not found
        '422':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/APIV3ValidationErrorResponse'
              examples:
                ValidationError:
                  value:
                    id: null
                    code: 422
                    error: validation_error
                    detail: One or more fields failed validation.
                    doc_url: https://developers.lighton.ai/errors#validation_error
                    fields:
                      <field_name>:
                        - error: required
                          detail: This field is required.
                  summary: Validation Error
          description: Request body is valid JSON but one or more fields failed validation
      security:
        - bearerAuth: []
components:
  schemas:
    ContentTypeActionRequest:
      description: >-
        Request body for POST /api/v3/content-types.


        Action-dispatched per FAC0012. Every action is idempotent.


        Schema-side verb family:
          - ``adopt`` — bulk import from the Pydantic seed catalog.
          - ``define_content_type`` / ``undefine_content_type`` — CRUD on tree nodes.
          - ``define_attribute`` / ``undefine_attribute`` — CRUD on attribute columns.

        Fields are validated per action in ``validate_fields_for_action`` —
        top-level

        optionality mirrors the union of action shapes, so consumers only need a

        single Pydantic class (friendly to drf-spectacular), but the validator

        enforces the narrow contract per action, the same pattern used by

        ``FileFacetActionRequest``.
      properties:
        action:
          allOf:
            - $ref: '#/components/schemas/ContentTypeActionRequestActionEnum'
          title: Action
        content_types:
          default: []
          items:
            type: string
          title: Content Types
          type: array
        parent_path:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Parent Path
        code:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Code
        content_type_path:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: Colon-separated content type path.
          title: Content Type Path
        label:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: Human-readable label for the node or attribute.
          title: Label
        description:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: Optional descriptive text for the node or attribute.
          title: Description
        inherit_attributes:
          anyOf:
            - type: boolean
            - type: 'null'
          default: null
          description: >-
            Whether child content types inherit attributes from ancestors.
            Defaults to true on create.
          title: Inherit Attributes
        name:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: Attribute identifier in snake_case.
          title: Name
        attribute_type:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            Public attribute type. Supported values: text, number, date,
            boolean, select, multi-select, rich-text. Accepted aliases:
            multi_select, multiselect, rich_text, richtext.
          title: Attribute Type
        required:
          anyOf:
            - type: boolean
            - type: 'null'
          default: null
          description: Whether the attribute is required. Defaults to false.
          title: Required
        choices:
          anyOf:
            - items:
                type: string
              type: array
            - type: 'null'
          default: null
          description: >-
            Required for select and multi-select attributes. Must be omitted for
            all other types.
          title: Choices
      required:
        - action
      title: ContentTypeActionRequest
      type: object
    ContentTypeWrite200Response:
      oneOf:
        - $ref: '#/components/schemas/ContentTypesListResponse'
        - $ref: '#/components/schemas/ContentTypeNodeResponse'
        - $ref: '#/components/schemas/AttributeDefResponse'
    ContentTypeWrite201Response:
      oneOf:
        - $ref: '#/components/schemas/ContentTypeNodeResponse'
        - $ref: '#/components/schemas/AttributeDefResponse'
    APIV3ErrorResponse:
      type: object
      properties:
        id:
          type:
            - string
            - 'null'
          description: >-
            Job/resource id when one already exists (useful for async error
            diagnosis); null otherwise.
        code:
          type: integer
          description: HTTP status code
        error:
          type: string
          description: Error code used by the UI as a translation key
        detail:
          type: string
          description: Human-readable error message for developers
        doc_url:
          type: string
          description: Link to the error-code documentation page
      required:
        - code
        - detail
        - doc_url
        - error
        - id
    APIV3ValidationErrorResponse:
      type: object
      properties:
        id:
          type:
            - string
            - 'null'
          description: >-
            Job/resource id when one already exists (useful for async error
            diagnosis); null otherwise.
        code:
          type: integer
          description: HTTP status code
        error:
          type: string
          description: Error code used by the UI as a translation key
        detail:
          type: string
          description: Human-readable error message for developers
        doc_url:
          type: string
          description: Link to the error-code documentation page
        fields:
          type: object
          additionalProperties:
            type: array
            items:
              $ref: '#/components/schemas/APIV3FieldError'
          description: Field-level validation errors keyed by field name
      required:
        - code
        - detail
        - doc_url
        - error
        - id
    ContentTypeActionRequestActionEnum:
      enum:
        - adopt
        - define_content_type
        - undefine_content_type
        - define_attribute
        - undefine_attribute
      type: string
    ContentTypesListResponse:
      properties:
        content_types:
          items:
            $ref: '#/components/schemas/ContentTypeNodeResponse'
          title: Content Types
          type: array
        can_edit:
          anyOf:
            - type: boolean
            - type: 'null'
          default: null
          title: Can Edit
      required:
        - content_types
      title: ContentTypesListResponse
      type: object
    ContentTypeNodeResponse:
      properties:
        path:
          title: Path
          type: string
        code:
          title: Code
          type: string
        label:
          title: Label
          type: string
        description:
          default: ''
          title: Description
          type: string
        source:
          title: Source
          type: string
        inherit_attributes:
          default: true
          title: Inherit Attributes
          type: boolean
        attributes:
          default: []
          items:
            $ref: '#/components/schemas/AttributeDefResponse'
          title: Attributes
          type: array
        children:
          default: []
          items:
            $ref: '#/components/schemas/ContentTypeNodeResponse'
          title: Children
          type: array
      required:
        - path
        - code
        - label
        - source
      title: ContentTypeNodeResponse
      type: object
    AttributeDefResponse:
      properties:
        name:
          title: Name
          type: string
        label:
          title: Label
          type: string
        type:
          title: Type
          type: string
        required:
          title: Required
          type: boolean
        description:
          default: ''
          title: Description
          type: string
        choices:
          default: []
          items:
            type: string
          title: Choices
          type: array
      required:
        - name
        - label
        - type
        - required
      title: AttributeDefResponse
      type: object
    APIV3FieldError:
      type: object
      properties:
        error:
          type: string
          description: Error code / translation key
        detail:
          type: string
          description: Human-readable description of the field error
      required:
        - detail
        - error
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        Bearer authentication header of the form `Bearer <token>`, where
        `<token>` is your auth token.

````