1350 lines
51 KiB
YAML
1350 lines
51 KiB
YAML
openapi: 3.0.3
|
|
|
|
info:
|
|
title: Relata API
|
|
version: "1.0.0"
|
|
description: |
|
|
Relata's REST interface.
|
|
|
|
**Authentication.** Every endpoint requires a session cookie obtained by posting the
|
|
browser login form at `POST /login`. There is no separate API key.
|
|
|
|
**CSRF.** State-changing requests (POST, PATCH, DELETE) must carry the session's CSRF
|
|
token in the `X-CSRF-Token` header. The token is rendered into every page as a hidden
|
|
`csrf_token` field.
|
|
|
|
**Three different scores.** Responses report `query_relevance`, `semantic_similarity` and
|
|
`relationship_strength` separately. None is a probability, and they must not be compared
|
|
with one another. See docs/SEARCH_AND_SCORING.md.
|
|
|
|
servers:
|
|
- url: http://127.0.0.1:8080
|
|
description: Default local instance
|
|
|
|
tags:
|
|
- name: Items
|
|
- name: Search
|
|
- name: Relationships
|
|
- name: Entities
|
|
- name: Jobs
|
|
- name: Health
|
|
|
|
security:
|
|
- sessionCookie: []
|
|
|
|
paths:
|
|
/api/v1/items:
|
|
post:
|
|
tags: [Items]
|
|
summary: Store pasted text or a JSON document
|
|
description: |
|
|
The content type is detected from the content itself; `mime_type` is a hint only.
|
|
Identical content returns 409 with the existing item's ID unless `allow_duplicate`
|
|
is set.
|
|
parameters: [{$ref: '#/components/parameters/CSRFToken'}]
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema: {$ref: '#/components/schemas/CreateItemRequest'}
|
|
responses:
|
|
'202':
|
|
description: Accepted and queued for processing
|
|
content:
|
|
application/json:
|
|
schema: {$ref: '#/components/schemas/ItemAccepted'}
|
|
'400': {$ref: '#/components/responses/BadRequest'}
|
|
'401': {$ref: '#/components/responses/Unauthorised'}
|
|
'403': {$ref: '#/components/responses/Forbidden'}
|
|
'409': {$ref: '#/components/responses/Duplicate'}
|
|
'413': {$ref: '#/components/responses/TooLarge'}
|
|
get:
|
|
tags: [Items]
|
|
summary: List items
|
|
parameters:
|
|
- {name: source_type, in: query, schema: {type: string}, description: 'Comma-separated. An unrecognised value is rejected.'}
|
|
- {name: mime_type, in: query, schema: {type: string}}
|
|
- {name: status, in: query, schema: {type: string}}
|
|
- {name: title, in: query, schema: {type: string}, description: 'Literal substring; metacharacters are escaped.'}
|
|
- {name: content_hash, in: query, schema: {type: string}}
|
|
- {name: created_from, in: query, schema: {type: string, format: date}}
|
|
- {name: created_to, in: query, schema: {type: string, format: date}}
|
|
- {$ref: '#/components/parameters/Limit'}
|
|
- {$ref: '#/components/parameters/Offset'}
|
|
responses:
|
|
'200':
|
|
description: A page of items
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
items: {type: array, items: {$ref: '#/components/schemas/Item'}}
|
|
pagination: {$ref: '#/components/schemas/Pagination'}
|
|
'400': {$ref: '#/components/responses/BadRequest'}
|
|
'401': {$ref: '#/components/responses/Unauthorised'}
|
|
|
|
/api/v1/items/upload:
|
|
post:
|
|
tags: [Items]
|
|
summary: Upload a document
|
|
description: |
|
|
Accepts plain text, Markdown, JSON, PDF and DOCX. The type is verified from the file's
|
|
content, not its name or declared type. Archives and executables are refused.
|
|
parameters: [{$ref: '#/components/parameters/CSRFToken'}]
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
multipart/form-data:
|
|
schema:
|
|
type: object
|
|
required: [file]
|
|
properties:
|
|
file: {type: string, format: binary}
|
|
title: {type: string, maxLength: 300}
|
|
source_type: {type: string}
|
|
created_at: {type: string, format: date}
|
|
allow_duplicate: {type: string, enum: ['true', 'false']}
|
|
responses:
|
|
'202':
|
|
description: Accepted and queued for processing
|
|
content:
|
|
application/json:
|
|
schema: {$ref: '#/components/schemas/ItemAccepted'}
|
|
'400': {$ref: '#/components/responses/BadRequest'}
|
|
'401': {$ref: '#/components/responses/Unauthorised'}
|
|
'409': {$ref: '#/components/responses/Duplicate'}
|
|
'413': {$ref: '#/components/responses/TooLarge'}
|
|
'415': {$ref: '#/components/responses/UnsupportedMedia'}
|
|
|
|
/api/v1/items/{id}:
|
|
parameters: [{$ref: '#/components/parameters/ItemID'}]
|
|
get:
|
|
tags: [Items]
|
|
summary: Retrieve an item with everything derived from it
|
|
responses:
|
|
'200':
|
|
description: The item, its chunks, entities, claims, relationships and processing history
|
|
content:
|
|
application/json:
|
|
schema: {$ref: '#/components/schemas/ItemDetail'}
|
|
'400': {$ref: '#/components/responses/BadRequest'}
|
|
'401': {$ref: '#/components/responses/Unauthorised'}
|
|
'404': {$ref: '#/components/responses/NotFound'}
|
|
delete:
|
|
tags: [Items]
|
|
summary: Delete an item, or preview what deletion would remove
|
|
description: |
|
|
With `dry_run=true`, reports what would be removed and changes nothing.
|
|
|
|
Without it, the item is hidden immediately and its chunks, vectors, claims,
|
|
relationships and any entities that only it referenced are removed asynchronously.
|
|
Audit events and processing runs are retained.
|
|
parameters:
|
|
- {$ref: '#/components/parameters/CSRFToken'}
|
|
- {name: dry_run, in: query, schema: {type: boolean}}
|
|
responses:
|
|
'200':
|
|
description: The deletion plan (dry run only)
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
dry_run: {type: boolean}
|
|
plan: {$ref: '#/components/schemas/DeletionPlan'}
|
|
note: {type: string}
|
|
'202':
|
|
description: Deletion queued
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
deleted: {type: string, format: uuid}
|
|
job_id: {type: string, format: uuid}
|
|
status: {type: string}
|
|
'401': {$ref: '#/components/responses/Unauthorised'}
|
|
'403': {$ref: '#/components/responses/Forbidden'}
|
|
'404': {$ref: '#/components/responses/NotFound'}
|
|
|
|
/api/v1/items/{id}/reprocess:
|
|
parameters: [{$ref: '#/components/parameters/ItemID'}]
|
|
post:
|
|
tags: [Items]
|
|
summary: Process an item again
|
|
description: |
|
|
Opens a new processing run and restarts the pipeline. Derived records are replaced
|
|
rather than duplicated, and human review decisions on relationships are preserved.
|
|
parameters: [{$ref: '#/components/parameters/CSRFToken'}]
|
|
requestBody:
|
|
required: false
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
additionalProperties: false
|
|
properties:
|
|
reason: {type: string}
|
|
responses:
|
|
'202':
|
|
description: Queued for reprocessing
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
item_id: {type: string, format: uuid}
|
|
job_id: {type: string, format: uuid}
|
|
status: {type: string}
|
|
'401': {$ref: '#/components/responses/Unauthorised'}
|
|
'403': {$ref: '#/components/responses/Forbidden'}
|
|
'404': {$ref: '#/components/responses/NotFound'}
|
|
|
|
/api/v1/items/{id}/relationships:
|
|
parameters: [{$ref: '#/components/parameters/ItemID'}]
|
|
get:
|
|
tags: [Relationships]
|
|
summary: An item's incoming and outgoing relationships
|
|
parameters:
|
|
- {name: type, in: query, schema: {type: string}, description: Comma-separated relationship types
|
|
}
|
|
- {name: provenance, in: query, schema: {type: string}}
|
|
- {name: review_status, in: query, schema: {type: string}}
|
|
- {name: confirmed_only, in: query, schema: {type: boolean}}
|
|
- {name: min_score, in: query, schema: {type: number, minimum: 0, maximum: 1}}
|
|
- {name: direction, in: query, schema: {type: string, enum: [out, in, both]}}
|
|
responses:
|
|
'200':
|
|
description: Relationships with their evidence and explanations
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
item_id: {type: string, format: uuid}
|
|
outgoing: {type: array, items: {$ref: '#/components/schemas/RelationshipView'}}
|
|
incoming: {type: array, items: {$ref: '#/components/schemas/RelationshipView'}}
|
|
note: {type: string}
|
|
'400': {$ref: '#/components/responses/BadRequest'}
|
|
'401': {$ref: '#/components/responses/Unauthorised'}
|
|
|
|
/api/v1/search:
|
|
get:
|
|
tags: [Search]
|
|
summary: Hybrid search across stored items
|
|
description: |
|
|
Combines exact matching, MongoDB text search, vector similarity, entity matching and
|
|
relationship expansion. Every result explains why it matched.
|
|
parameters:
|
|
- {name: q, in: query, schema: {type: string, maxLength: 2000}}
|
|
- {name: source_type, in: query, schema: {type: string}}
|
|
- {name: mime_type, in: query, schema: {type: string}}
|
|
- {name: entity_id, in: query, schema: {type: string}, description: Comma-separated UUIDs}
|
|
- {name: relationship_type, in: query, schema: {type: string}}
|
|
- {name: created_from, in: query, schema: {type: string, format: date}}
|
|
- {name: created_to, in: query, schema: {type: string, format: date}}
|
|
- {name: confirmed_only, in: query, schema: {type: boolean}, description: Follow only relationships a person confirmed}
|
|
- {name: min_relationship_strength, in: query, schema: {type: number, minimum: 0, maximum: 1}}
|
|
- {name: expand, in: query, schema: {type: boolean, default: true}}
|
|
- {$ref: '#/components/parameters/Limit'}
|
|
- {$ref: '#/components/parameters/Offset'}
|
|
responses:
|
|
'200':
|
|
description: Ranked results with explanations
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
search: {$ref: '#/components/schemas/SearchResponse'}
|
|
score_guide:
|
|
type: object
|
|
description: What each score means, restated on every response
|
|
properties:
|
|
query_relevance: {type: string}
|
|
semantic_similarity: {type: string}
|
|
relationship_strength: {type: string}
|
|
'400': {$ref: '#/components/responses/BadRequest'}
|
|
'401': {$ref: '#/components/responses/Unauthorised'}
|
|
|
|
/api/v1/search/answer:
|
|
post:
|
|
tags: [Search]
|
|
summary: Answer a question using only stored material
|
|
description: |
|
|
Retrieves relevant items and generates an answer from them alone. Citations are
|
|
resolved against the passages actually supplied, so a fabricated reference cannot
|
|
point at a real item. Conflicts between sources are surfaced, never reconciled.
|
|
|
|
Requires a configured language model; returns 503 otherwise.
|
|
parameters: [{$ref: '#/components/parameters/CSRFToken'}]
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [question]
|
|
additionalProperties: false
|
|
properties:
|
|
question: {type: string, maxLength: 2000}
|
|
source_types: {type: array, items: {type: string}}
|
|
entity_ids: {type: array, items: {type: string, format: uuid}}
|
|
confirmed_only: {type: boolean}
|
|
limit: {type: integer}
|
|
responses:
|
|
'200':
|
|
description: A cited answer
|
|
content:
|
|
application/json:
|
|
schema: {$ref: '#/components/schemas/Answer'}
|
|
'400': {$ref: '#/components/responses/BadRequest'}
|
|
'401': {$ref: '#/components/responses/Unauthorised'}
|
|
'502':
|
|
description: The model returned output that failed validation. Nothing was stored.
|
|
content:
|
|
application/json:
|
|
schema: {$ref: '#/components/schemas/Error'}
|
|
'503': {$ref: '#/components/responses/FeatureDisabled'}
|
|
|
|
/api/v1/relationships:
|
|
get:
|
|
tags: [Relationships]
|
|
summary: List relationships
|
|
parameters:
|
|
- {name: type, in: query, schema: {type: string}}
|
|
- {name: provenance, in: query, schema: {type: string}}
|
|
- {name: review_status, in: query, schema: {type: string}}
|
|
- {name: confirmed_only, in: query, schema: {type: boolean}}
|
|
- {name: min_score, in: query, schema: {type: number, minimum: 0, maximum: 1}}
|
|
- {$ref: '#/components/parameters/Limit'}
|
|
- {$ref: '#/components/parameters/Offset'}
|
|
responses:
|
|
'200':
|
|
description: A page of relationships
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
relationships: {type: array, items: {$ref: '#/components/schemas/RelationshipView'}}
|
|
pagination: {$ref: '#/components/schemas/Pagination'}
|
|
'400': {$ref: '#/components/responses/BadRequest'}
|
|
'401': {$ref: '#/components/responses/Unauthorised'}
|
|
post:
|
|
tags: [Relationships]
|
|
summary: Record a relationship asserted by a person
|
|
description: |
|
|
Stored with `explicit` provenance and `confirmed` review status: a human statement is
|
|
not a proposal awaiting review. Both items must be in the caller's workspace.
|
|
parameters: [{$ref: '#/components/parameters/CSRFToken'}]
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [source_id, target_id, type]
|
|
additionalProperties: false
|
|
properties:
|
|
source_id: {type: string, format: uuid}
|
|
target_id: {type: string, format: uuid}
|
|
type: {$ref: '#/components/schemas/RelationshipType'}
|
|
note: {type: string, maxLength: 2000}
|
|
responses:
|
|
'201':
|
|
description: Created
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
relationship: {$ref: '#/components/schemas/RelationshipView'}
|
|
'400': {$ref: '#/components/responses/BadRequest'}
|
|
'401': {$ref: '#/components/responses/Unauthorised'}
|
|
'403': {$ref: '#/components/responses/Forbidden'}
|
|
'404': {$ref: '#/components/responses/NotFound'}
|
|
|
|
/api/v1/relationships/{id}:
|
|
parameters: [{$ref: '#/components/parameters/RelationshipID'}]
|
|
patch:
|
|
tags: [Relationships]
|
|
summary: Change a relationship's type
|
|
description: |
|
|
The original type and provenance are preserved on the record, and the change is
|
|
appended to the relationship's review history.
|
|
parameters: [{$ref: '#/components/parameters/CSRFToken'}]
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [type]
|
|
additionalProperties: false
|
|
properties:
|
|
type: {$ref: '#/components/schemas/RelationshipType'}
|
|
note: {type: string, maxLength: 2000}
|
|
responses:
|
|
'200':
|
|
description: Updated
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
relationship: {$ref: '#/components/schemas/RelationshipView'}
|
|
'400': {$ref: '#/components/responses/BadRequest'}
|
|
'401': {$ref: '#/components/responses/Unauthorised'}
|
|
'403': {$ref: '#/components/responses/Forbidden'}
|
|
'404': {$ref: '#/components/responses/NotFound'}
|
|
|
|
/api/v1/relationships/{id}/confirm:
|
|
parameters: [{$ref: '#/components/parameters/RelationshipID'}]
|
|
post:
|
|
tags: [Relationships]
|
|
summary: Confirm a relationship
|
|
description: |
|
|
Adds a user-confirmation signal, raising the score to 1.00 through the same arithmetic
|
|
as every other signal. The original proposal and its evidence are retained.
|
|
parameters: [{$ref: '#/components/parameters/CSRFToken'}]
|
|
requestBody:
|
|
required: false
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
additionalProperties: false
|
|
properties:
|
|
note: {type: string, maxLength: 2000}
|
|
responses:
|
|
'200':
|
|
description: Confirmed
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
relationship: {$ref: '#/components/schemas/RelationshipView'}
|
|
'401': {$ref: '#/components/responses/Unauthorised'}
|
|
'403': {$ref: '#/components/responses/Forbidden'}
|
|
'404': {$ref: '#/components/responses/NotFound'}
|
|
|
|
/api/v1/relationships/{id}/reject:
|
|
parameters: [{$ref: '#/components/parameters/RelationshipID'}]
|
|
post:
|
|
tags: [Relationships]
|
|
summary: Reject a relationship
|
|
description: |
|
|
The relationship is retained with its evidence and history; its score falls to zero
|
|
and it no longer influences search. Nothing is deleted.
|
|
parameters: [{$ref: '#/components/parameters/CSRFToken'}]
|
|
requestBody:
|
|
required: false
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
additionalProperties: false
|
|
properties:
|
|
note: {type: string, maxLength: 2000}
|
|
responses:
|
|
'200':
|
|
description: Rejected
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
relationship: {$ref: '#/components/schemas/RelationshipView'}
|
|
'401': {$ref: '#/components/responses/Unauthorised'}
|
|
'403': {$ref: '#/components/responses/Forbidden'}
|
|
'404': {$ref: '#/components/responses/NotFound'}
|
|
|
|
/api/v1/entities:
|
|
get:
|
|
tags: [Entities]
|
|
summary: List extracted entities
|
|
parameters:
|
|
- {name: q, in: query, schema: {type: string}, description: Literal substring of the canonical name}
|
|
- {name: type, in: query, schema: {type: string}}
|
|
- {name: item_id, in: query, schema: {type: string, format: uuid}}
|
|
- {name: min_mentions, in: query, schema: {type: integer}}
|
|
- {$ref: '#/components/parameters/Limit'}
|
|
- {$ref: '#/components/parameters/Offset'}
|
|
responses:
|
|
'200':
|
|
description: A page of entities
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
entities: {type: array, items: {$ref: '#/components/schemas/Entity'}}
|
|
pagination: {$ref: '#/components/schemas/Pagination'}
|
|
'400': {$ref: '#/components/responses/BadRequest'}
|
|
'401': {$ref: '#/components/responses/Unauthorised'}
|
|
|
|
/api/v1/entities/{id}:
|
|
parameters: [{$ref: '#/components/parameters/EntityID'}]
|
|
get:
|
|
tags: [Entities]
|
|
summary: An entity with its aliases and citing items
|
|
responses:
|
|
'200':
|
|
description: The entity
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
entity: {$ref: '#/components/schemas/Entity'}
|
|
aliases: {type: array, items: {$ref: '#/components/schemas/EntityAlias'}}
|
|
items: {type: array, items: {$ref: '#/components/schemas/Item'}}
|
|
note: {type: string}
|
|
'401': {$ref: '#/components/responses/Unauthorised'}
|
|
'404': {$ref: '#/components/responses/NotFound'}
|
|
|
|
/api/v1/aliases/{id}/confirm:
|
|
parameters: [{$ref: '#/components/parameters/AliasID'}]
|
|
post:
|
|
tags: [Entities]
|
|
summary: Confirm that two similar names refer to the same thing
|
|
description: |
|
|
The two entities remain **separate records**. A confirmed alias becomes evidence when
|
|
relationships are discovered, weighted below an exact name match. Relata never merges
|
|
entities automatically, and confirming does not merge them either.
|
|
parameters: [{$ref: '#/components/parameters/CSRFToken'}]
|
|
responses:
|
|
'200':
|
|
description: Confirmed
|
|
content:
|
|
application/json:
|
|
schema: {$ref: '#/components/schemas/AliasDecision'}
|
|
'401': {$ref: '#/components/responses/Unauthorised'}
|
|
'403': {$ref: '#/components/responses/Forbidden'}
|
|
'404': {$ref: '#/components/responses/NotFound'}
|
|
|
|
/api/v1/aliases/{id}/reject:
|
|
parameters: [{$ref: '#/components/parameters/AliasID'}]
|
|
post:
|
|
tags: [Entities]
|
|
summary: Record that two similar names refer to different things
|
|
description: |
|
|
The proposal is retained so that it is not offered again as new, and the alias stops
|
|
contributing evidence.
|
|
parameters: [{$ref: '#/components/parameters/CSRFToken'}]
|
|
responses:
|
|
'200':
|
|
description: Rejected
|
|
content:
|
|
application/json:
|
|
schema: {$ref: '#/components/schemas/AliasDecision'}
|
|
'401': {$ref: '#/components/responses/Unauthorised'}
|
|
'403': {$ref: '#/components/responses/Forbidden'}
|
|
'404': {$ref: '#/components/responses/NotFound'}
|
|
|
|
/api/v1/jobs:
|
|
get:
|
|
tags: [Jobs]
|
|
summary: List background jobs
|
|
parameters:
|
|
- {name: status, in: query, schema: {type: string}}
|
|
- {name: type, in: query, schema: {type: string}}
|
|
- {$ref: '#/components/parameters/Limit'}
|
|
- {$ref: '#/components/parameters/Offset'}
|
|
responses:
|
|
'200':
|
|
description: A page of jobs
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
jobs: {type: array, items: {$ref: '#/components/schemas/Job'}}
|
|
pagination: {$ref: '#/components/schemas/Pagination'}
|
|
'401': {$ref: '#/components/responses/Unauthorised'}
|
|
|
|
/api/v1/jobs/{id}/retry:
|
|
parameters: [{$ref: '#/components/parameters/JobID'}]
|
|
post:
|
|
tags: [Jobs]
|
|
summary: Return a failed job to the queue
|
|
parameters: [{$ref: '#/components/parameters/CSRFToken'}]
|
|
responses:
|
|
'200':
|
|
description: Requeued
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
job: {$ref: '#/components/schemas/Job'}
|
|
'401': {$ref: '#/components/responses/Unauthorised'}
|
|
'403': {$ref: '#/components/responses/Forbidden'}
|
|
'409':
|
|
description: The job does not exist or is not in a retryable state
|
|
content:
|
|
application/json:
|
|
schema: {$ref: '#/components/schemas/Error'}
|
|
|
|
/api/v1/tokens:
|
|
get:
|
|
tags: [Tokens]
|
|
summary: List your API tokens
|
|
description: |
|
|
Returns the caller's own tokens, including revoked and expired ones so the
|
|
history stays visible. No secret is returned — only a hash was ever stored.
|
|
|
|
**Requires a signed-in session.** An API token cannot list, create or revoke
|
|
tokens: a leaked credential must not be able to mint its own replacements.
|
|
responses:
|
|
'200':
|
|
description: The caller's tokens
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
tokens:
|
|
type: array
|
|
items: {$ref: '#/components/schemas/APIToken'}
|
|
total: {type: integer}
|
|
'401': {$ref: '#/components/responses/Unauthorised'}
|
|
'403':
|
|
description: The request authenticated with an API token rather than a session
|
|
content:
|
|
application/json:
|
|
schema: {$ref: '#/components/schemas/Error'}
|
|
post:
|
|
tags: [Tokens]
|
|
summary: Issue an API token
|
|
description: |
|
|
The secret is returned **once** and cannot be retrieved again.
|
|
|
|
Granted scopes are the intersection of those requested and those the caller's
|
|
role permits, so a token never carries more authority than its creator.
|
|
parameters: [{$ref: '#/components/parameters/CSRFToken'}]
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [name, scopes]
|
|
properties:
|
|
name: {type: string, maxLength: 80}
|
|
scopes:
|
|
type: array
|
|
minItems: 1
|
|
items: {type: string, enum: [ingest, query, review]}
|
|
ttl_hours:
|
|
type: integer
|
|
description: Optional. The configured default applies when absent, capped at the configured maximum.
|
|
responses:
|
|
'201':
|
|
description: Token issued
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
token: {$ref: '#/components/schemas/APIToken'}
|
|
secret:
|
|
type: string
|
|
description: The credential. Shown once; only its hash is stored.
|
|
warning: {type: string}
|
|
'400': {$ref: '#/components/responses/InvalidRequest'}
|
|
'401': {$ref: '#/components/responses/Unauthorised'}
|
|
'403':
|
|
description: The request authenticated with an API token rather than a session
|
|
content:
|
|
application/json:
|
|
schema: {$ref: '#/components/schemas/Error'}
|
|
|
|
/api/v1/tokens/{id}:
|
|
parameters: [{$ref: '#/components/parameters/TokenID'}]
|
|
delete:
|
|
tags: [Tokens]
|
|
summary: Revoke an API token
|
|
description: |
|
|
The record is kept rather than deleted, so the token's existence and its end stay
|
|
visible. A revoked token is refused on its next use; there is no cached grant.
|
|
parameters: [{$ref: '#/components/parameters/CSRFToken'}]
|
|
responses:
|
|
'200':
|
|
description: Revoked
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
revoked: {type: boolean}
|
|
id: {type: string, format: uuid}
|
|
'401': {$ref: '#/components/responses/Unauthorised'}
|
|
'403':
|
|
description: The request authenticated with an API token rather than a session
|
|
content:
|
|
application/json:
|
|
schema: {$ref: '#/components/schemas/Error'}
|
|
'404': {$ref: '#/components/responses/NotFound'}
|
|
|
|
/health/live:
|
|
get:
|
|
tags: [Health]
|
|
summary: Liveness
|
|
description: Checks only that the process is running. Unauthenticated.
|
|
security: []
|
|
responses:
|
|
'200':
|
|
description: Alive
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
status: {type: string}
|
|
version: {type: string}
|
|
uptime_sec: {type: integer}
|
|
|
|
/health/ready:
|
|
get:
|
|
tags: [Health]
|
|
summary: Readiness
|
|
description: |
|
|
MongoDB and Qdrant are required. AI providers are reported but not required:
|
|
ingestion, keyword search and browsing work without them. Unauthenticated,
|
|
and therefore reports *that* a dependency is unreachable but never *why* —
|
|
see the server log for the cause.
|
|
security: []
|
|
responses:
|
|
'200':
|
|
description: Ready
|
|
content:
|
|
application/json:
|
|
schema: {$ref: '#/components/schemas/Readiness'}
|
|
'503':
|
|
description: A required dependency is unavailable
|
|
content:
|
|
application/json:
|
|
schema: {$ref: '#/components/schemas/Readiness'}
|
|
|
|
components:
|
|
securitySchemes:
|
|
sessionCookie:
|
|
type: apiKey
|
|
in: cookie
|
|
name: relata_session
|
|
|
|
parameters:
|
|
CSRFToken:
|
|
name: X-CSRF-Token
|
|
in: header
|
|
required: true
|
|
schema: {type: string}
|
|
description: The session's CSRF token, rendered into every page as a hidden `csrf_token` field.
|
|
ItemID:
|
|
name: id
|
|
in: path
|
|
required: true
|
|
schema: {type: string, format: uuid}
|
|
RelationshipID:
|
|
name: id
|
|
in: path
|
|
required: true
|
|
schema: {type: string, format: uuid}
|
|
EntityID:
|
|
name: id
|
|
in: path
|
|
required: true
|
|
schema: {type: string, format: uuid}
|
|
TokenID:
|
|
name: id
|
|
in: path
|
|
required: true
|
|
schema: {type: string, format: uuid}
|
|
JobID:
|
|
name: id
|
|
in: path
|
|
required: true
|
|
schema: {type: string, format: uuid}
|
|
AliasID:
|
|
name: id
|
|
in: path
|
|
required: true
|
|
schema: {type: string, format: uuid}
|
|
Limit:
|
|
name: limit
|
|
in: query
|
|
schema: {type: integer, minimum: 1, maximum: 200, default: 20}
|
|
Offset:
|
|
name: offset
|
|
in: query
|
|
schema: {type: integer, minimum: 0, default: 0}
|
|
|
|
responses:
|
|
BadRequest:
|
|
description: The request was rejected by validation
|
|
content:
|
|
application/json:
|
|
schema: {$ref: '#/components/schemas/Error'}
|
|
Unauthorised:
|
|
description: Authentication is required
|
|
content:
|
|
application/json:
|
|
schema: {$ref: '#/components/schemas/Error'}
|
|
Forbidden:
|
|
description: The caller's role does not permit this, or the CSRF check failed
|
|
content:
|
|
application/json:
|
|
schema: {$ref: '#/components/schemas/Error'}
|
|
NotFound:
|
|
description: |
|
|
No such record in the caller's workspace. A record in another workspace is
|
|
reported identically, so probing cannot confirm that an ID exists elsewhere.
|
|
content:
|
|
application/json:
|
|
schema: {$ref: '#/components/schemas/Error'}
|
|
Duplicate:
|
|
description: Identical content already exists
|
|
content:
|
|
application/json:
|
|
schema: {$ref: '#/components/schemas/Error'}
|
|
TooLarge:
|
|
description: The body exceeds the configured limit
|
|
content:
|
|
application/json:
|
|
schema: {$ref: '#/components/schemas/Error'}
|
|
UnsupportedMedia:
|
|
description: The content type is not supported
|
|
content:
|
|
application/json:
|
|
schema: {$ref: '#/components/schemas/Error'}
|
|
FeatureDisabled:
|
|
description: The feature requires a language model, which is not configured
|
|
content:
|
|
application/json:
|
|
schema: {$ref: '#/components/schemas/Error'}
|
|
|
|
schemas:
|
|
Error:
|
|
type: object
|
|
properties:
|
|
error:
|
|
type: object
|
|
properties:
|
|
code:
|
|
type: string
|
|
description: A stable, machine-readable code. Clients may branch on it.
|
|
enum:
|
|
[invalid_request, validation_failed, unauthorised, forbidden, not_found,
|
|
duplicate_content, conflict, payload_too_large, unsupported_media_type,
|
|
rate_limited, csrf_check_failed, dependency_unavailable,
|
|
model_output_invalid, feature_disabled, internal_error]
|
|
message: {type: string, description: Safe to display. Never contains internal detail.}
|
|
fields:
|
|
type: array
|
|
items:
|
|
type: object
|
|
properties:
|
|
field: {type: string}
|
|
message: {type: string}
|
|
request_id: {type: string, description: Quote this when reporting a problem.}
|
|
detail: {type: object, additionalProperties: {type: string}}
|
|
|
|
Pagination:
|
|
type: object
|
|
properties:
|
|
total: {type: integer}
|
|
limit: {type: integer}
|
|
offset: {type: integer}
|
|
has_more: {type: boolean}
|
|
|
|
SourceType:
|
|
type: string
|
|
enum: [note, document, json, email, transcript, markdown]
|
|
|
|
ProcessingStatus:
|
|
type: string
|
|
enum: [pending, parsing, chunking, embedding, analysing, relating, ready, failed,
|
|
partial, deleting, tombstoned]
|
|
|
|
RelationshipType:
|
|
type: string
|
|
enum: [similar_to, mentions, involves, supports, contradicts, updates, supersedes,
|
|
provides_context_for, possibly_explains, occurred_before, occurred_after,
|
|
derived_from, same_entity_as]
|
|
|
|
Provenance:
|
|
type: string
|
|
description: How the relationship came to exist. `model_inferred` is a proposal, not a fact.
|
|
enum: [explicit, deterministic, model_inferred, user_confirmed, user_rejected]
|
|
|
|
ReviewStatus:
|
|
type: string
|
|
enum: [pending, confirmed, rejected, edited]
|
|
|
|
EntityType:
|
|
type: string
|
|
enum: [person, organisation, location, product, event, date, subject, concept]
|
|
|
|
CreateItemRequest:
|
|
type: object
|
|
required: [content]
|
|
additionalProperties: false
|
|
description: Unknown fields are rejected.
|
|
properties:
|
|
title: {type: string, maxLength: 300}
|
|
content: {type: string}
|
|
source_type: {$ref: '#/components/schemas/SourceType'}
|
|
mime_type: {type: string, description: A hint only; the type is detected from the content.}
|
|
filename: {type: string}
|
|
metadata: {type: object, additionalProperties: {type: string}}
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
description: When the information itself dates from. Must not be in the future.
|
|
allow_duplicate:
|
|
type: boolean
|
|
description: Store even when identical content already exists.
|
|
|
|
ItemAccepted:
|
|
type: object
|
|
properties:
|
|
item: {$ref: '#/components/schemas/Item'}
|
|
job_id: {type: string, format: uuid}
|
|
status: {type: string}
|
|
|
|
Item:
|
|
type: object
|
|
properties:
|
|
id: {type: string, format: uuid}
|
|
workspace_id: {type: string, format: uuid}
|
|
title: {type: string}
|
|
source_type: {$ref: '#/components/schemas/SourceType'}
|
|
mime_type: {type: string}
|
|
original_filename: {type: string}
|
|
original_text: {type: string, description: The verbatim text supplied, never rewritten.}
|
|
extracted_text: {type: string}
|
|
size_bytes: {type: integer}
|
|
content_hash: {type: string, description: SHA-256 of the supplied bytes.}
|
|
metadata: {type: object, additionalProperties: {type: string}}
|
|
created_at: {type: string, format: date-time}
|
|
ingested_at: {type: string, format: date-time}
|
|
updated_at: {type: string, format: date-time}
|
|
status: {$ref: '#/components/schemas/ProcessingStatus'}
|
|
warnings:
|
|
type: array
|
|
items:
|
|
type: object
|
|
properties:
|
|
code: {type: string}
|
|
message: {type: string}
|
|
detail: {type: string}
|
|
error: {type: string}
|
|
parser_version: {type: string}
|
|
embedding_model: {type: string}
|
|
analysis_model: {type: string}
|
|
score_version: {type: string}
|
|
chunk_count: {type: integer}
|
|
entity_count: {type: integer}
|
|
claim_count: {type: integer}
|
|
relationship_count: {type: integer}
|
|
duplicate_of: {type: string, format: uuid}
|
|
deleted: {type: boolean}
|
|
|
|
Chunk:
|
|
type: object
|
|
properties:
|
|
id: {type: string, format: uuid, description: Also the Qdrant point ID.}
|
|
item_id: {type: string, format: uuid}
|
|
sequence: {type: integer}
|
|
text: {type: string}
|
|
content_hash: {type: string}
|
|
start_offset: {type: integer, description: Byte offset into the item's extracted text.}
|
|
end_offset: {type: integer}
|
|
page: {type: integer}
|
|
section: {type: string}
|
|
heading: {type: string}
|
|
embedding_model: {type: string}
|
|
embedded: {type: boolean}
|
|
|
|
Claim:
|
|
type: object
|
|
description: A record that a source *said* something. Not a fact.
|
|
properties:
|
|
id: {type: string, format: uuid}
|
|
item_id: {type: string, format: uuid}
|
|
chunk_id: {type: string, format: uuid}
|
|
statement: {type: string, description: A short normalised rendering.}
|
|
source_ref:
|
|
type: object
|
|
description: Always points at real text. A claim never loses this link.
|
|
properties:
|
|
item_id: {type: string, format: uuid}
|
|
chunk_id: {type: string, format: uuid}
|
|
start: {type: integer}
|
|
end: {type: integer}
|
|
quote: {type: string, description: The exact source wording.}
|
|
page: {type: integer}
|
|
attribution: {type: string}
|
|
nature: {type: string, enum: [quoted, paraphrased, inferred]}
|
|
subject: {type: string}
|
|
numbers: {type: array, items: {type: number}}
|
|
dates: {type: array, items: {type: string}}
|
|
polarity: {type: integer, enum: [-1, 1]}
|
|
method: {type: string, enum: [deterministic, model, user]}
|
|
model_version: {type: string}
|
|
confidence: {type: number}
|
|
|
|
Entity:
|
|
type: object
|
|
properties:
|
|
id: {type: string, format: uuid}
|
|
canonical_name: {type: string}
|
|
normalised_key: {type: string}
|
|
type: {$ref: '#/components/schemas/EntityType'}
|
|
aliases: {type: array, items: {type: string}}
|
|
item_ids: {type: array, items: {type: string, format: uuid}}
|
|
source_refs: {type: array, items: {type: object}}
|
|
method: {type: string, enum: [deterministic, model, user]}
|
|
evidence_score:
|
|
type: number
|
|
description: How well attested the entity is. Not a probability.
|
|
mentions: {type: integer}
|
|
model_version: {type: string}
|
|
|
|
EntityAlias:
|
|
type: object
|
|
description: A proposal that two names may refer to the same thing. Never applied automatically.
|
|
properties:
|
|
id: {type: string, format: uuid}
|
|
entity_id: {type: string, format: uuid}
|
|
alias: {type: string}
|
|
candidate_entity_id: {type: string, format: uuid}
|
|
status: {type: string, enum: [candidate, confirmed, rejected]}
|
|
similarity: {type: number}
|
|
reason: {type: string}
|
|
|
|
Signal:
|
|
type: object
|
|
description: One explicit contribution to a relationship's strength.
|
|
properties:
|
|
type:
|
|
type: string
|
|
enum: [semantic_similarity, shared_entity, alias_entity, shared_concept,
|
|
temporal_proximity, shared_metadata, claim_support, claim_contradiction,
|
|
model_classification, user_confirmation, user_rejection, content_hash_match]
|
|
value: {type: string, description: The human-readable evidence.}
|
|
strength: {type: number, minimum: 0, maximum: 1}
|
|
weight: {type: number}
|
|
detail: {type: string}
|
|
|
|
Relationship:
|
|
type: object
|
|
properties:
|
|
id: {type: string, format: uuid}
|
|
source_kind: {type: string, enum: [item, chunk, entity, claim]}
|
|
source_id: {type: string, format: uuid}
|
|
target_kind: {type: string, enum: [item, chunk, entity, claim]}
|
|
target_id: {type: string, format: uuid}
|
|
type: {$ref: '#/components/schemas/RelationshipType'}
|
|
provenance: {$ref: '#/components/schemas/Provenance'}
|
|
score:
|
|
type: number
|
|
minimum: 0
|
|
maximum: 1
|
|
description: |
|
|
A HEURISTIC relationship strength derived from the signals below, under the
|
|
named scoring version. NOT a calibrated probability.
|
|
score_version: {type: string}
|
|
evidence:
|
|
type: object
|
|
properties:
|
|
signals: {type: array, items: {$ref: '#/components/schemas/Signal'}}
|
|
source_chunk_ids: {type: array, items: {type: string}}
|
|
target_chunk_ids: {type: array, items: {type: string}}
|
|
shared_entities: {type: array, items: {type: string}}
|
|
source_excerpt: {type: string}
|
|
target_excerpt: {type: string}
|
|
model_rationale: {type: string, description: A model's words. Not a verified fact.}
|
|
model_version: {type: string}
|
|
original_type: {$ref: '#/components/schemas/RelationshipType'}
|
|
original_provenance: {$ref: '#/components/schemas/Provenance'}
|
|
review_status: {$ref: '#/components/schemas/ReviewStatus'}
|
|
review_history:
|
|
type: array
|
|
description: Append-only. A rejection never erases the original proposal.
|
|
items:
|
|
type: object
|
|
properties:
|
|
at: {type: string, format: date-time}
|
|
action: {type: string}
|
|
actor_id: {type: string}
|
|
actor_name: {type: string}
|
|
note: {type: string}
|
|
from_value: {type: string}
|
|
to_value: {type: string}
|
|
created_at: {type: string, format: date-time}
|
|
updated_at: {type: string, format: date-time}
|
|
|
|
RelationshipView:
|
|
allOf:
|
|
- {$ref: '#/components/schemas/Relationship'}
|
|
- type: object
|
|
properties:
|
|
explanation:
|
|
type: array
|
|
items: {type: string}
|
|
description: The score's arithmetic in plain English.
|
|
source_title: {type: string}
|
|
target_title: {type: string}
|
|
score_meaning: {type: string}
|
|
|
|
ItemDetail:
|
|
type: object
|
|
properties:
|
|
item: {$ref: '#/components/schemas/Item'}
|
|
chunks: {type: array, items: {$ref: '#/components/schemas/Chunk'}}
|
|
entities: {type: array, items: {$ref: '#/components/schemas/Entity'}}
|
|
claims: {type: array, items: {$ref: '#/components/schemas/Claim'}}
|
|
outgoing_relationships: {type: array, items: {$ref: '#/components/schemas/RelationshipView'}}
|
|
incoming_relationships: {type: array, items: {$ref: '#/components/schemas/RelationshipView'}}
|
|
processing_runs:
|
|
type: array
|
|
description: Retained across reprocessing, for audit.
|
|
items:
|
|
type: object
|
|
properties:
|
|
id: {type: string, format: uuid}
|
|
reason: {type: string}
|
|
started_at: {type: string, format: date-time}
|
|
ended_at: {type: string, format: date-time}
|
|
outcome: {type: string}
|
|
error: {type: string}
|
|
parser_version: {type: string}
|
|
embedding_model: {type: string}
|
|
analysis_model: {type: string}
|
|
score_version: {type: string}
|
|
stats: {type: object, additionalProperties: {type: integer}}
|
|
|
|
SearchResponse:
|
|
type: object
|
|
properties:
|
|
query: {type: string}
|
|
total: {type: integer}
|
|
limit: {type: integer}
|
|
offset: {type: integer}
|
|
took_ms: {type: integer}
|
|
notes:
|
|
type: array
|
|
items: {type: string}
|
|
description: Advisory messages, such as vector search being unavailable.
|
|
results: {type: array, items: {$ref: '#/components/schemas/SearchResult'}}
|
|
|
|
SearchResult:
|
|
type: object
|
|
properties:
|
|
item: {$ref: '#/components/schemas/Item'}
|
|
query_relevance:
|
|
type: number
|
|
description: How well this item answers THIS query, relative to the best result. Not a probability.
|
|
semantic_similarity:
|
|
type: number
|
|
description: |
|
|
Best cosine similarity of any matching section. Reported separately because
|
|
similarity is not relevance and not evidence of a factual relationship.
|
|
excerpt: {type: string}
|
|
why_matched: {type: array, items: {type: string}}
|
|
contributions:
|
|
type: array
|
|
items:
|
|
type: object
|
|
properties:
|
|
source: {type: string}
|
|
rank: {type: integer}
|
|
weight: {type: number}
|
|
score: {type: number}
|
|
detail: {type: string}
|
|
matched_chunks:
|
|
type: array
|
|
items:
|
|
type: object
|
|
properties:
|
|
chunk_id: {type: string, format: uuid}
|
|
sequence: {type: integer}
|
|
text: {type: string}
|
|
semantic_similarity: {type: number}
|
|
page: {type: integer}
|
|
section: {type: string}
|
|
matched_entities:
|
|
type: array
|
|
items:
|
|
type: object
|
|
properties:
|
|
id: {type: string, format: uuid}
|
|
name: {type: string}
|
|
type: {$ref: '#/components/schemas/EntityType'}
|
|
related_items: {type: array, items: {$ref: '#/components/schemas/RelatedItem'}}
|
|
via_relationship:
|
|
allOf: [{$ref: '#/components/schemas/RelatedItem'}]
|
|
description: Set when the item was reached by relationship expansion rather than a direct match.
|
|
rank_version: {type: string}
|
|
|
|
RelatedItem:
|
|
type: object
|
|
properties:
|
|
relationship_id: {type: string, format: uuid}
|
|
item_id: {type: string, format: uuid}
|
|
title: {type: string}
|
|
type: {$ref: '#/components/schemas/RelationshipType'}
|
|
provenance: {$ref: '#/components/schemas/Provenance'}
|
|
relationship_strength:
|
|
type: number
|
|
description: A heuristic strength, NOT query relevance and NOT a probability.
|
|
score_version: {type: string}
|
|
review_status: {$ref: '#/components/schemas/ReviewStatus'}
|
|
explanation: {type: array, items: {type: string}}
|
|
direction: {type: string, enum: [incoming, outgoing]}
|
|
|
|
Answer:
|
|
type: object
|
|
properties:
|
|
question: {type: string}
|
|
answer: {type: string, description: Generated from the sources below and nothing else.}
|
|
sufficient:
|
|
type: boolean
|
|
description: False when the stored material does not support an answer.
|
|
sources_used:
|
|
type: array
|
|
items:
|
|
type: object
|
|
properties:
|
|
ref: {type: string, description: The opaque handle shown to the model (S1, S2…).}
|
|
item_id: {type: string, format: uuid}
|
|
title: {type: string}
|
|
excerpt: {type: string}
|
|
date: {type: string}
|
|
cited: {type: boolean, description: Whether the answer actually referenced it.}
|
|
uncertainty_and_conflicts:
|
|
type: array
|
|
items: {type: string}
|
|
description: |
|
|
Disagreements between sources, insufficiency, reliance on inferred
|
|
relationships, and any prompt-injection attempt noticed. Never suppressed.
|
|
inferred_relationships_used:
|
|
type: array
|
|
items: {$ref: '#/components/schemas/RelatedItem'}
|
|
description: Links that influenced retrieval but are proposals, not facts.
|
|
model: {type: string}
|
|
retrieved_items: {type: integer}
|
|
took_ms: {type: integer}
|
|
prompt_injection_noticed: {type: boolean}
|
|
|
|
DeletionPlan:
|
|
type: object
|
|
properties:
|
|
item_id: {type: string, format: uuid}
|
|
title: {type: string}
|
|
chunks: {type: integer}
|
|
vectors: {type: integer}
|
|
claims: {type: integer}
|
|
relationships: {type: integer}
|
|
orphaned_entities:
|
|
type: array
|
|
items: {type: string}
|
|
description: Entities only this item references; they will be removed.
|
|
shared_entities_retained:
|
|
type: array
|
|
items: {type: string}
|
|
description: Entities referenced elsewhere; they will be kept.
|
|
original_file: {type: string}
|
|
queued_jobs: {type: integer}
|
|
|
|
AliasDecision:
|
|
type: object
|
|
properties:
|
|
alias_id: {type: string, format: uuid}
|
|
status: {type: string, enum: [candidate, confirmed, rejected]}
|
|
note:
|
|
type: string
|
|
description: States that the entities remain separate records.
|
|
|
|
Job:
|
|
type: object
|
|
properties:
|
|
id: {type: string, format: uuid}
|
|
type:
|
|
type: string
|
|
enum: [parse_item, chunk_item, generate_embeddings, extract_entities, extract_claims,
|
|
discover_relationships, reprocess_item, delete_item_data, reembed_workspace]
|
|
status: {type: string, enum: [pending, running, succeeded, failed, cancelled]}
|
|
item_id: {type: string, format: uuid}
|
|
priority: {type: integer}
|
|
run_after: {type: string, format: date-time}
|
|
attempts: {type: integer}
|
|
max_attempts: {type: integer}
|
|
lease_owner: {type: string}
|
|
lease_expires: {type: string, format: date-time}
|
|
last_error: {type: string}
|
|
history:
|
|
type: array
|
|
items:
|
|
type: object
|
|
properties:
|
|
number: {type: integer}
|
|
started_at: {type: string, format: date-time}
|
|
ended_at: {type: string, format: date-time}
|
|
worker: {type: string}
|
|
error: {type: string}
|
|
error_class: {type: string, enum: [transient, permanent, timeout, cancelled, invalid_model_output]}
|
|
duration_ms: {type: integer}
|
|
created_at: {type: string, format: date-time}
|
|
updated_at: {type: string, format: date-time}
|
|
completed_at: {type: string, format: date-time}
|
|
|
|
APIToken:
|
|
type: object
|
|
description: |
|
|
An API token as returned by the API. There is no field for the secret because
|
|
there is no secret to return: only its SHA-256 hash was stored.
|
|
properties:
|
|
id: {type: string, format: uuid}
|
|
name: {type: string}
|
|
prefix:
|
|
type: string
|
|
description: The leading, non-secret portion, kept so tokens can be told apart.
|
|
scopes:
|
|
type: array
|
|
items: {type: string, enum: [ingest, query, review]}
|
|
created_at: {type: string, format: date-time}
|
|
expires_at: {type: string, format: date-time}
|
|
last_used_at: {type: string, format: date-time}
|
|
revoked_at: {type: string, format: date-time}
|
|
status: {type: string, enum: [active, expired, revoked]}
|
|
|
|
Readiness:
|
|
type: object
|
|
properties:
|
|
status: {type: string, enum: [ready, 'not ready']}
|
|
version: {type: string}
|
|
note: {type: string}
|
|
checks:
|
|
type: object
|
|
additionalProperties:
|
|
type: object
|
|
properties:
|
|
status: {type: string, enum: [ok, unavailable]}
|
|
detail:
|
|
type: string
|
|
description: |
|
|
A fixed description of what an unavailable dependency means for the
|
|
service. Absent when the dependency is ok. It never carries the
|
|
underlying error: this endpoint is unauthenticated, and driver errors
|
|
embed hosts, ports and connection-string credentials. The cause is
|
|
logged server-side with the request ID.
|
|
required:
|
|
type: boolean
|
|
description: AI providers are false; MongoDB and Qdrant are true.
|