---
title: "Answer a knowledge gap, in part or in full"
method: POST
path: "/knowledge-gaps/{gap_id}/answers"
tags: ["knowledge-gaps"]
---

# Answer a knowledge gap, in part or in full

`POST /knowledge-gaps/{gap_id}/answers`

## Request

- Base URL: `https://api.scipot.ai` (the document declares no server; this is the origin it was published from)
- URL: `https://api.scipot.ai/knowledge-gaps/{gap_id}/answers`
- Auth: none declared
- TypeScript: <https://skmtc.dev/scipot/apis/scipot-core-api/docs/knowledge-gaps/:gap_id/answers/post.ts> (a function with typed inputs; its response is checked against the schema)

Attach facts of the gap's POT that answer it, with how much of the question they cover. A `partial` answer leaves the gap in the queue with what is already known attached, for the next person to complete. A `complete` one records the answerer's claim; the state still moves only through `/transitions`, so the integrator can ask the question again before resolving. Refused with 409 on a resolved, dismissed or duplicate gap (reopen it first), and with 422 when a fact is not in the gap's POT.

## Path parameters

- `gap_id` string, uuid, required

## Request body

- GapAnswerRequest: JSON body for ``POST /knowledge-gaps/{gap_id}/answers``.
  - `actor` string, required: Who answered.
  - `contributor_id` string, uuid, nullable: The registered contributor behind the facts, if any.
  - `completeness` 'partial' | 'complete', required: `partial` keeps the gap open for someone else with this answer attached; `complete` says it answers the question (the integrator still drives the state).
  - `fact_ids` string[], required: Facts of the gap's POT that carry the answer (a contribution, a document's facts).
  - `note` string, nullable

## Response `201`

Successful Response

- KnowledgeGap: Persisted gap item — repository row shape and API response body.
  - `gap_id` string, uuid: UUIDv7 — chronologically sortable.
  - `workspace_id` string, uuid, required: Owning workspace; multi-tenant isolation key.
  - `pot_id` string, uuid, required: POT the question was asked against.
  - `query_text` string, required
  - `context` string, nullable: The asker's case (where, what they see, what they tried); null when none was given. Gaps written before 0.7.24.0 have none.
  - `requester_id` string, required
  - `domain` string, required
  - `trigger` 'low_confidence' | 'no_coverage' | 'manual'
  - `trigger_score` number, nullable
  - `state` 'open' | 'routed' | 'ingested' | 'resolved' | 'expired' | 'dismissed' | 'duplicate' | 'reopened'
  - `assigned_to` string, nullable: Opaque id of the expert/DRI the integrator routed to. Core stores, never decides, this value.
  - `resolved_cluster_id` string, uuid, nullable: Deprecated, always null: a hook for a Knowledge Cluster that was never built. Kept so stored items and clients keep validating.
  - `capsule_id` string, uuid, nullable: Deprecated, always null in production: set only by the Capsules coverage evaluation, behind `capsules_enabled` (off). Marks the ORIGIN only; the trigger vocabulary is unchanged, so existing integrator payloads keep validating.
  - `idempotency_key` string, nullable
  - `transitions` GapTransition[]: Append-only transition history (actor + timestamp per state change).
    - `from_state` 'open' | 'routed' | 'ingested' | 'resolved' | 'expired' | 'dismissed' | 'duplicate' | 'reopened', required
    - `to_state` 'open' | 'routed' | 'ingested' | 'resolved' | 'expired' | 'dismissed' | 'duplicate' | 'reopened', required
    - `actor` string, required: Who/what performed the transition (opaque integrator id).
    - `at` string, date-time
    - `note` string, nullable
    - `evidence_ref` string, nullable: Optional link to the ingestion job / contribution that drove this transition.
  - `answers` GapAnswer[]: Append-only answers contributed toward the gap, partial or complete, oldest first.
    - `answer_id` string, uuid
    - `actor` string, required: Who answered (opaque integrator id).
    - `contributor_id` string, uuid, nullable: The registered contributor behind the facts, if any.
    - `completeness` 'partial' | 'complete', required
    - `fact_ids` string[], required
    - `note` string, nullable
    - `at` string, date-time
  - `timeout_at` string, date-time, nullable: Deprecated, always null: no route sets it and the core never expires a gap; an SLA is the integrator's, which drives the gap to 'expired' itself.
  - `created_at` string, date-time
  - `updated_at` string, date-time
  - `resolved_at` string, date-time, nullable

## Other responses

- `409`: The gap is closed, or already holds the maximum of answers.
- `422`: A fact id is not a fact of the gap's POT.

## Changes

- **2026-09-27** `e6f2189e7b2f`: 1 info
  - added the optional property `context` to the response with the `201` status
- **2026-09-26** `9c8cf6ae7c8b`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/scipot/apis/scipot-core-api/changes/knowledge-gaps/:gap_id/answers/post.md)

---

[API](https://skmtc.dev/scipot/apis/scipot-core-api.md) - [All operations](https://skmtc.dev/scipot/apis/scipot-core-api/llms.txt) - [OpenAPI document](https://skmtc.dev/scipot/apis/scipot-core-api/revisions/7620af82156a?raw)
