Skip to content
Dashboard

Update a Q&A entry

PATCH/v2/training_data/qna/{id}

Updates title, questions, answer, or source. Questions replaces the whole list; preserve the union yourself when merging. Supply expectedRevision from GET or oracle.existing / oracle.target to apply only to the version you reviewed. A stale revision returns 409 revision_conflict; a question owned by another entry returns 409 question_already_used. Content changes attempt indexing before returning; check indexStatus.

Optional onMatch checks changed questions or answer against the addressed entry and retrieved candidates. reject refuses overlap; update permits deliberate replacement but refuses unclear results; create overrides the result. PATCH never merges entries. Checks are bounded advice and do not lock the rest of the knowledge base. A missing onMatch applies the requested update without semantic judging.

Path ParametersExpand Collapse
id: string

The Q&A entry ID

Header ParametersExpand Collapse
"Featurebase-Version": optional "2026-08-19.orbit" or "2026-01-01.nova" or "2025-12-12.clover"
One of the following:
"2026-08-19.orbit"
"2026-01-01.nova"
"2025-12-12.clover"
Body ParametersJSONExpand Collapse
answer: optional string

Replacement answer

minLength1
maxLength100000
answerFormat: optional "markdown" or "html"

Format of answer. markdown (default) is stored as-is; html is converted to markdown.

One of the following:
"markdown"
"html"
expectedRevision: optional number

Apply only if the entry still has this revision. A stale revision returns 409 revision_conflict without writing. Get the revision from retrieve, oracle.existing, or oracle.target.

minimum0
maximum9007199254740991
onMatch: optional "reject" or "update" or "create"

Optional inline knowledge check for a content change. Omit it (the default) and the change is applied immediately. Pass it to check the changed questions / answer against the addressed entry and retrieved workspace candidates first: reject: respond 409 conflicts_with_existing and leave the entry untouched; update or create: apply the change and report the match in match. A PATCH never merges two entries. Ignored when neither questions nor answer changes.

One of the following:
"reject"
"update"
"create"
questions: optional array of string

Replacement question list (replaces all existing questions)

source: optional string

Free-form label for the pipeline or system this entry came from. Filter lists by it to review or sweep everything from one source.

minLength1
maxLength100
title: optional string

New label

minLength1
maxLength500
ReturnsExpand Collapse
Qna object { id, answer, createdAt, 10 more }
id: string

Q&A entry ID

answer: string

The answer the AI agent gives (markdown)

createdAt: string

ISO timestamp of creation

externalId: string

Stable identifier supplied by the source system

indexStatus: "pending" or "indexed" or "failed"

Whether the entry is searchable by the AI agent. failed entries are stored and indexing is retried hourly up to three times. Re-send the resource to retry after exhaustion.

One of the following:
"pending"
"indexed"
"failed"
object: "qna"

Object type identifier

questions: array of string

Question variants the answer applies to

revision: number

Q&A revision. Send it as expectedRevision on PATCH to reject stale changes.

source: string

Pipeline label, if one was set

title: string

Short label for the entry

updatedAt: string

ISO timestamp of the last change

match: optional object { entry, reason, verdict }

Present only when onMatch was passed and the check ran: the verdict and the closest existing item, even when the write went ahead. null otherwise (the default), including when the payload was unchanged.

entry: object { id, kind, section, 3 more }

The existing item the verdict is about, or null when nothing was close

id: string

ID of the item (Q&A entry, training file, or article)

kind: "qna" or "training_file" or "help_center_article"

What kind of knowledge item matched: a Q&A entry, a training file / crawled page, or a live help-center article.

One of the following:
"qna"
"training_file"
"help_center_article"
section: string

Heading breadcrumb of the matching section, for training files

similarity: number

Cosine similarity between your entry and the item (0–1); null for a keyword-only hit

title: string

Title of the item

url: string

Public URL of the item when it has one (articles, crawled pages)

reason: string

The judge’s one-line explanation of the verdict

verdict: "same_topic" or "contradicts" or "different" or 2 more

How the closest existing item relates to the entry. same_topic: it answers the same customer question (the entry would be a duplicate, rewording, or updated version). contradicts: same question, incompatible facts. different: a different question, even if the wording overlaps. unclear: the judge could not decide. no_match: nothing similar was found.

One of the following:
"same_topic"
"contradicts"
"different"
"unclear"
"no_match"
outcome: optional "created" or "updated" or "unchanged"

What the write did — present on create and update responses. created: a new entry. updated: an entry already carried one of the questions (or was merged into with onMatch: "update") and got new content or an indexing retry. unchanged: everything in the payload was already on that entry; nothing written, nothing re-indexed.

One of the following:
"created"
"updated"
"unchanged"

Update a Q&A entry

curl https://do.featurebase.app/v2/training_data/qna/$ID \
    -X PATCH \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer $FEATUREBASE_API_KEY" \
    -d '{
          "answer": "You can request a refund within 60 days from **Settings → Billing**.",
          "answerFormat": "markdown",
          "expectedRevision": 1,
          "onMatch": "reject",
          "questions": [
            "How do I request a refund?",
            "Can I get my money back?"
          ],
          "source": "resolved-conversations",
          "title": "Refund requests"
        }'
{
  "id": "67ec1234abcd5678ef901235",
  "answer": "You can request a refund within 30 days from **Settings → Billing**.",
  "createdAt": "2026-09-03T10:15:00.000Z",
  "externalId": "resolution-1842",
  "indexStatus": "indexed",
  "object": "qna",
  "questions": [
    "How do I request a refund?",
    "Can I get my money back?"
  ],
  "revision": 1,
  "source": "resolved-conversations",
  "title": "Refund requests",
  "updatedAt": "2026-09-03T10:15:30.000Z",
  "match": {
    "entry": {
      "id": "67ec1234abcd5678ef901236",
      "kind": "qna",
      "section": null,
      "similarity": 0.61,
      "title": "Refund requests",
      "url": null
    },
    "reason": "Both answer how to request a refund; the new entry adds the 30-day window.",
    "verdict": "same_topic"
  },
  "outcome": "created"
}
Returns Examples
{
  "id": "67ec1234abcd5678ef901235",
  "answer": "You can request a refund within 30 days from **Settings → Billing**.",
  "createdAt": "2026-09-03T10:15:00.000Z",
  "externalId": "resolution-1842",
  "indexStatus": "indexed",
  "object": "qna",
  "questions": [
    "How do I request a refund?",
    "Can I get my money back?"
  ],
  "revision": 1,
  "source": "resolved-conversations",
  "title": "Refund requests",
  "updatedAt": "2026-09-03T10:15:30.000Z",
  "match": {
    "entry": {
      "id": "67ec1234abcd5678ef901236",
      "kind": "qna",
      "section": null,
      "similarity": 0.61,
      "title": "Refund requests",
      "url": null
    },
    "reason": "Both answer how to request a refund; the new entry adds the 30-day window.",
    "verdict": "same_topic"
  },
  "outcome": "created"
}