# Manage FAQs

```json metadata
{
  "schema_version": 2,
  "title": "Manage FAQs",
  "description": "Write answers, promote reviewed proposals, and publish FAQ versions for retrieval.",
  "categories": ["docs","develop","ai"],
  "tableOfContents": {"sections":[{"id":"before-you-begin","title":"Before you begin"},{"id":"write-an-answer","title":"Write an answer"},{"id":"create-a-draft-faq","title":"Create a draft FAQ"},{"id":"promote-a-reviewed-proposal","title":"Promote a reviewed proposal"},{"id":"publish-a-version","title":"Publish a version"},{"id":"update-an-answer","title":"Update an answer"},{"id":"list-entries-and-inspect-history","title":"List entries and inspect history"},{"id":"look-up-entry-state","title":"Look up entry state"},{"id":"withdraw-or-delete-an-faq","title":"Withdraw or delete an FAQ"}]}

,
  "codeExamples": [{"codetabsId":"iris_playbook_faqs-stepplaybook-faq-create","difficulty":"beginner","id":"playbook-faq-create","languages":[{"clientId":"iris-python","clientName":"Python (Iris)","id":"Python (Iris)","langId":"python","panelId":"panel_Python (Iris)_iris_playbook_faqs-stepplaybook-faq-create"},{"clientId":"iris-cli","clientName":"CLI (Iris)","id":"CLI (Iris)","langId":"bash","panelId":"panel_CLI (Iris)_iris_playbook_faqs-stepplaybook-faq-create"},{"clientId":"iris-curl","clientName":"cURL (Iris)","id":"cURL (Iris)","langId":"bash","panelId":"panel_cURL (Iris)_iris_playbook_faqs-stepplaybook-faq-create"}]},{"codetabsId":"iris_playbook_faqs-stepplaybook-faq-publish","difficulty":"beginner","id":"playbook-faq-publish","languages":[{"clientId":"iris-python","clientName":"Python (Iris)","id":"Python (Iris)","langId":"python","panelId":"panel_Python (Iris)_iris_playbook_faqs-stepplaybook-faq-publish"},{"clientId":"iris-cli","clientName":"CLI (Iris)","id":"CLI (Iris)","langId":"bash","panelId":"panel_CLI (Iris)_iris_playbook_faqs-stepplaybook-faq-publish"},{"clientId":"iris-curl","clientName":"cURL (Iris)","id":"cURL (Iris)","langId":"bash","panelId":"panel_cURL (Iris)_iris_playbook_faqs-stepplaybook-faq-publish"}]},{"codetabsId":"iris_playbook_faqs-stepplaybook-faq-publication","difficulty":"beginner","id":"playbook-faq-publication","languages":[{"clientId":"iris-python","clientName":"Python (Iris)","id":"Python (Iris)","langId":"python","panelId":"panel_Python (Iris)_iris_playbook_faqs-stepplaybook-faq-publication"},{"clientId":"iris-cli","clientName":"CLI (Iris)","id":"CLI (Iris)","langId":"bash","panelId":"panel_CLI (Iris)_iris_playbook_faqs-stepplaybook-faq-publication"},{"clientId":"iris-curl","clientName":"cURL (Iris)","id":"cURL (Iris)","langId":"bash","panelId":"panel_cURL (Iris)_iris_playbook_faqs-stepplaybook-faq-publication"}]},{"codetabsId":"iris_playbook_faqs-stepplaybook-faq-search","difficulty":"beginner","id":"playbook-faq-search","languages":[{"clientId":"iris-python","clientName":"Python (Iris)","id":"Python (Iris)","langId":"python","panelId":"panel_Python (Iris)_iris_playbook_faqs-stepplaybook-faq-search"},{"clientId":"iris-cli","clientName":"CLI (Iris)","id":"CLI (Iris)","langId":"bash","panelId":"panel_CLI (Iris)_iris_playbook_faqs-stepplaybook-faq-search"},{"clientId":"iris-curl","clientName":"cURL (Iris)","id":"cURL (Iris)","langId":"bash","panelId":"panel_cURL (Iris)_iris_playbook_faqs-stepplaybook-faq-search"}]},{"codetabsId":"iris_playbook_faqs-stepplaybook-faq-update","difficulty":"beginner","id":"playbook-faq-update","languages":[{"clientId":"iris-python","clientName":"Python (Iris)","id":"Python (Iris)","langId":"python","panelId":"panel_Python (Iris)_iris_playbook_faqs-stepplaybook-faq-update"},{"clientId":"iris-cli","clientName":"CLI (Iris)","id":"CLI (Iris)","langId":"bash","panelId":"panel_CLI (Iris)_iris_playbook_faqs-stepplaybook-faq-update"},{"clientId":"iris-curl","clientName":"cURL (Iris)","id":"cURL (Iris)","langId":"bash","panelId":"panel_cURL (Iris)_iris_playbook_faqs-stepplaybook-faq-update"}]},{"codetabsId":"iris_playbook_faqs-stepplaybook-faq-republish","difficulty":"beginner","id":"playbook-faq-republish","languages":[{"clientId":"iris-python","clientName":"Python (Iris)","id":"Python (Iris)","langId":"python","panelId":"panel_Python (Iris)_iris_playbook_faqs-stepplaybook-faq-republish"},{"clientId":"iris-cli","clientName":"CLI (Iris)","id":"CLI (Iris)","langId":"bash","panelId":"panel_CLI (Iris)_iris_playbook_faqs-stepplaybook-faq-republish"},{"clientId":"iris-curl","clientName":"cURL (Iris)","id":"cURL (Iris)","langId":"bash","panelId":"panel_cURL (Iris)_iris_playbook_faqs-stepplaybook-faq-republish"}]},{"codetabsId":"iris_playbook_faqs-stepplaybook-faq-rollback","difficulty":"beginner","id":"playbook-faq-rollback","languages":[{"clientId":"iris-python","clientName":"Python (Iris)","id":"Python (Iris)","langId":"python","panelId":"panel_Python (Iris)_iris_playbook_faqs-stepplaybook-faq-rollback"},{"clientId":"iris-cli","clientName":"CLI (Iris)","id":"CLI (Iris)","langId":"bash","panelId":"panel_CLI (Iris)_iris_playbook_faqs-stepplaybook-faq-rollback"},{"clientId":"iris-curl","clientName":"cURL (Iris)","id":"cURL (Iris)","langId":"bash","panelId":"panel_cURL (Iris)_iris_playbook_faqs-stepplaybook-faq-rollback"}]},{"codetabsId":"iris_playbook_faqs-stepplaybook-faq-list","difficulty":"beginner","id":"playbook-faq-list","languages":[{"clientId":"iris-python","clientName":"Python (Iris)","id":"Python (Iris)","langId":"python","panelId":"panel_Python (Iris)_iris_playbook_faqs-stepplaybook-faq-list"},{"clientId":"iris-cli","clientName":"CLI (Iris)","id":"CLI (Iris)","langId":"bash","panelId":"panel_CLI (Iris)_iris_playbook_faqs-stepplaybook-faq-list"},{"clientId":"iris-curl","clientName":"cURL (Iris)","id":"cURL (Iris)","langId":"bash","panelId":"panel_cURL (Iris)_iris_playbook_faqs-stepplaybook-faq-list"}]},{"codetabsId":"iris_playbook_faqs-stepplaybook-faq-stats","difficulty":"beginner","id":"playbook-faq-stats","languages":[{"clientId":"iris-python","clientName":"Python (Iris)","id":"Python (Iris)","langId":"python","panelId":"panel_Python (Iris)_iris_playbook_faqs-stepplaybook-faq-stats"},{"clientId":"iris-curl","clientName":"cURL (Iris)","id":"cURL (Iris)","langId":"bash","panelId":"panel_cURL (Iris)_iris_playbook_faqs-stepplaybook-faq-stats"}]},{"codetabsId":"iris_playbook_faqs-stepplaybook-faq-history","difficulty":"beginner","id":"playbook-faq-history","languages":[{"clientId":"iris-python","clientName":"Python (Iris)","id":"Python (Iris)","langId":"python","panelId":"panel_Python (Iris)_iris_playbook_faqs-stepplaybook-faq-history"},{"clientId":"iris-cli","clientName":"CLI (Iris)","id":"CLI (Iris)","langId":"bash","panelId":"panel_CLI (Iris)_iris_playbook_faqs-stepplaybook-faq-history"},{"clientId":"iris-curl","clientName":"cURL (Iris)","id":"cURL (Iris)","langId":"bash","panelId":"panel_cURL (Iris)_iris_playbook_faqs-stepplaybook-faq-history"}]},{"codetabsId":"iris_playbook_faqs-stepplaybook-faq-lookup","difficulty":"beginner","id":"playbook-faq-lookup","languages":[{"clientId":"iris-python","clientName":"Python (Iris)","id":"Python (Iris)","langId":"python","panelId":"panel_Python (Iris)_iris_playbook_faqs-stepplaybook-faq-lookup"},{"clientId":"iris-curl","clientName":"cURL (Iris)","id":"cURL (Iris)","langId":"bash","panelId":"panel_cURL (Iris)_iris_playbook_faqs-stepplaybook-faq-lookup"}]},{"codetabsId":"iris_playbook_faqs_withdraw-stepplaybook-faq-withdraw","difficulty":"beginner","id":"playbook-faq-withdraw","languages":[{"clientId":"iris-python","clientName":"Python (Iris)","id":"Python (Iris)","langId":"python","panelId":"panel_Python (Iris)_iris_playbook_faqs_withdraw-stepplaybook-faq-withdraw"},{"clientId":"iris-cli","clientName":"CLI (Iris)","id":"CLI (Iris)","langId":"bash","panelId":"panel_CLI (Iris)_iris_playbook_faqs_withdraw-stepplaybook-faq-withdraw"},{"clientId":"iris-curl","clientName":"cURL (Iris)","id":"cURL (Iris)","langId":"bash","panelId":"panel_cURL (Iris)_iris_playbook_faqs_withdraw-stepplaybook-faq-withdraw"}]},{"codetabsId":"iris_playbook_faqs_delete-stepplaybook-faq-delete","difficulty":"beginner","id":"playbook-faq-delete","languages":[{"clientId":"iris-python","clientName":"Python (Iris)","id":"Python (Iris)","langId":"python","panelId":"panel_Python (Iris)_iris_playbook_faqs_delete-stepplaybook-faq-delete"},{"clientId":"iris-cli","clientName":"CLI (Iris)","id":"CLI (Iris)","langId":"bash","panelId":"panel_CLI (Iris)_iris_playbook_faqs_delete-stepplaybook-faq-delete"},{"clientId":"iris-curl","clientName":"cURL (Iris)","id":"cURL (Iris)","langId":"bash","panelId":"panel_cURL (Iris)_iris_playbook_faqs_delete-stepplaybook-faq-delete"}]}]
}
```

## Code examples

These examples connect to Iris services using SDKs or HTTP requests with curl. Follow one language throughout each walkthrough.


Publish a FAQ to give agents an approved answer to a recurring question. Write it directly or promote a reviewed proposal.

## Before you begin

Use an existing playbook and an API key with `write` permission to create and maintain entries. Publishing and withdrawing require `publish`. See [access permissions](https://redis.io/docs/latest/develop/ai/context-engine/agent-playbooks/concepts#playbooks).

Start with the quickstart's [client setup](https://redis.io/docs/latest/develop/ai/context-engine/agent-playbooks/quickstart#connect-to-the-playbook), then append this page's snippets in order. Run each write once.

The CLI uses flat FAQ JSON files and `faqs push` to reconcile content by entry key. A changed file appends a version; an unchanged file does not. Publication remains a separate command.

## Write an answer

Write a question in the language a user would use. Include conditions that distinguish it from similar questions, such as the product or region. Make the answer self-contained: the agent receives it without the source conversation or document.

The sample FAQ explains where to find refund status. Use a [skill](https://redis.io/docs/latest/develop/ai/context-engine/agent-playbooks/manage-skills) when the agent must interpret the customer's reported stage, choose a template, and draft a reply.

SDK and HTTP requests nest content fields; CLI FAQ files use flat fields:

| Request field | CLI file field | Use it for |
|:--------------|:---------------|:-----------|
| `content.payload.faq.question` | `question` | The recurring question. |
| `content.payload.faq.answer` | `answer` | The approved answer. |
| `content.intents` | `intents` | Optional task phrases returned with discovery previews. |
| `content.attributes` | `attributes` | Exact-match filters, such as audience, locale, or product. |
| `content.metadata` | `metadata` | Application context, such as a source-document reference. |

Semantic matching uses the question, not the answer or intents. Use attributes to filter the audience. Metadata does not control publication.

For example, prefer “How do I check the status of an existing refund?” to “Refund help.” Keep “How do I request a refund?” separate: it needs a different answer.

## Create a draft FAQ

Submit the complete content with `create_faq`. The sample assigns `refund-status` as its entry key. Keys are immutable and unique within a playbook; choose another key if that one is already in use. Save the returned entry identifier and version number.

The new FAQ is unpublished. Review it before publishing; search and discovery do not return it yet.

**Available in:** Python (Iris), cURL (Iris), CLI (Iris)

##### Python (Iris)

```python
faq_content = {
    "intents": ["Check a refund", "Find an existing refund"],
    "attributes": {"locale": "en-US", "topic": "refund"},
    "payload": {
        "faq": {
            "question": "How do I check the status of a refund?",
            "answer": (
                "Open the order in your order history and select Refund status. "
                "If no refund is listed, contact support with your order number."
            ),
        }
    },
}

draft = playbook.client.create_faq(content=faq_content, entry_key="refund-status")
faq_id = draft.entry.entry_id
version = draft.version.version
print(faq_id, version, draft.entry.publication)
```

##### cURL (Iris)

```bash
cat > faq.json <<'JSON'
{
  "entryKey": "refund-status",
  "content": {
    "intents": ["Check a refund", "Find an existing refund"],
    "attributes": {"locale": "en-US", "topic": "refund"},
    "payload": {"faq": {
      "question": "How do I check the status of a refund?",
      "answer": "Open the order in your order history and select Refund status. If no refund is listed, contact support with your order number."
    }}
  }
}
JSON
curl --fail-with-body --silent --show-error \
  -X POST "$PLAYBOOK_API/faqs" \
  -H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" \
  -H 'Content-Type: application/json' --data-binary @faq.json > draft.json
FAQ_ID=$(jq -er '.entry.entryId' draft.json)
VERSION=$(jq -er '.version.version' draft.json)
jq '{entryId: .entry.entryId, version: .version.version, publication: .entry.publication}' draft.json
```

##### CLI (Iris)

```bash
cat > faq.json <<'JSON'
{
  "entryKey": "refund-status",
  "question": "How do I check the status of a refund?",
  "answer": "Open the order in your order history and select Refund status. If no refund is listed, contact support with your order number.",
  "intents": ["Check a refund", "Find an existing refund"],
  "attributes": {"locale": "en-US", "topic": "refund"}
}
JSON
iris agent-playbooks faqs validate faq.json
iris --json agent-playbooks faqs push faq.json > faq-draft.json
FAQ_ID=$(jq -er '.results[0].entryId' faq-draft.json)
VERSION=$(jq -er '.results[0].version' faq-draft.json)
jq . faq-draft.json
```



## Promote a reviewed proposal

If an answer comes from the proposal inbox, [review the candidate and its evidence](https://redis.io/docs/latest/develop/ai/context-engine/agent-playbooks/proposals#review-and-edit-a-candidate) first. Accept the proposal with the revision you reviewed.

Acceptance returns an entry and version for one unpublished FAQ. Save those values and continue with publication. Promotion does not make the answer available to agents, and it does not update an existing FAQ.

## Publish a version

1. Retrieve the exact version you intend to publish.
2. Review its answer, intents, and audience attributes.
3. Publish that version with `publish_faq`.
4. Test retrieval with a reader key and a representative question.

Test a paraphrase such as “Where can I see my refund?” and a nearby question the answer does not cover, such as “How do I request a refund?” Check the returned entry and audience, then use the [retrieval guide](https://redis.io/docs/latest/develop/ai/context-engine/agent-playbooks/retrieval) to tune matching.

**Available in:** Python (Iris), cURL (Iris), CLI (Iris)

##### Python (Iris)

```python
stored = playbook.client.get_faq_version(faq_id=faq_id, version=version)
print(stored.content)
```

##### cURL (Iris)

```bash
curl --fail-with-body --silent --show-error \
  "$PLAYBOOK_API/faqs/$FAQ_ID/versions/$VERSION" \
  -H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" | jq .content
```

##### CLI (Iris)

```bash
iris --json agent-playbooks faqs show "$FAQ_ID" --version "$VERSION" | jq .content
```



Publish the version you reviewed.

**Available in:** Python (Iris), cURL (Iris), CLI (Iris)

##### Python (Iris)

```python
playbook.client.publish_faq(faq_id=faq_id, version=version)
```

##### cURL (Iris)

```bash
curl --fail-with-body --silent --show-error \
  -X PUT "$PLAYBOOK_API/faqs/$FAQ_ID/publication" \
  -H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" \
  -H 'Content-Type: application/json' \
  --data "$(jq -n --argjson version "$VERSION" '{version: $version}')" | jq .publication
```

##### CLI (Iris)

```bash
iris agent-playbooks faqs publish "$FAQ_ID" --version "$VERSION"
```



**Available in:** Python (Iris), cURL (Iris), CLI (Iris)

##### Python (Iris)

```python
results = playbook.client.search_faqs(
    query="Where can I see how my refund is progressing?",
    filter_={"eq": {"name": "locale", "value": "en-US"}},
    limit=5,
)
for match in results.items:
    if match.faq is not None:
        print(match.entry_id, match.version, match.score, match.faq.answer)
```

##### cURL (Iris)

```bash
curl --fail-with-body --silent --show-error \
  -X POST "$PLAYBOOK_API/faqs/search" \
  -H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" \
  -H 'Content-Type: application/json' \
  --data '{"query":"Where can I see how my refund is progressing?","filter":{"eq":{"name":"locale","value":"en-US"}},"limit":5}' \
  | jq '.items[] | {entryId, version, score, answer: .faq.answer}'
```

##### CLI (Iris)

```bash
cat > search.json <<'JSON'
{
  "query": "Where can I see how my refund is progressing?",
  "filter": {"eq": {"name": "locale", "value": "en-US"}},
  "limit": 5
}
JSON
iris --json agent-playbooks faqs search --input search.json | jq .items
```



## Update an answer

Append a complete replacement version to the same entry with `append_faq_version`. Include the intents, attributes, and metadata you want that version to contain.

Coordinate publishers for the same entry. Concurrent publication changes are last-write-wins. Publishing an already published version is a no-op.

**Available in:** Python (Iris), cURL (Iris), CLI (Iris)

##### Python (Iris)

```python
from copy import deepcopy

updated_content = deepcopy(faq_content)
updated_content["payload"]["faq"]["answer"] += (
    " Support can check the current stage but cannot guarantee a bank posting date."
)
updated = playbook.client.append_faq_version(faq_id=faq_id, content=updated_content)
print("Review this version:", updated.version.version, updated.version.content)
```

##### cURL (Iris)

```bash
jq 'del(.entryKey) | .content.payload.faq.answer += " Support can check the current stage but cannot guarantee a bank posting date."' \
  faq.json > faq-update.json
curl --fail-with-body --silent --show-error \
  -X POST "$PLAYBOOK_API/faqs/$FAQ_ID/versions" \
  -H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" \
  -H 'Content-Type: application/json' --data-binary @faq-update.json > updated.json
jq .version updated.json
```

##### CLI (Iris)

```bash
jq '.answer += " Support can check the current stage but cannot guarantee a bank posting date."' \
  faq.json > faq-update.json
iris --json agent-playbooks faqs push faq-update.json > faq-updated.json
UPDATED_VERSION=$(jq -er '.results[0].version' faq-updated.json)
iris --json agent-playbooks faqs show "$FAQ_ID" --version "$UPDATED_VERSION" | jq .content
```



The identifier stays the same, and search still serves the first publication. Review and publish the new version, then search again.

**Available in:** Python (Iris), cURL (Iris), CLI (Iris)

##### Python (Iris)

```python
playbook.client.publish_faq(faq_id=faq_id, version=updated.version.version)
```

##### cURL (Iris)

```bash
curl --fail-with-body --silent --show-error \
  -X PUT "$PLAYBOOK_API/faqs/$FAQ_ID/publication" \
  -H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" \
  -H 'Content-Type: application/json' \
  --data "$(jq '{version: .version.version}' updated.json)" | jq .publication
```

##### CLI (Iris)

```bash
iris agent-playbooks faqs publish "$FAQ_ID" --version "$UPDATED_VERSION"
```



Republish the first version to roll back.

**Available in:** Python (Iris), cURL (Iris), CLI (Iris)

##### Python (Iris)

```python
playbook.client.publish_faq(faq_id=faq_id, version=version)
```

##### cURL (Iris)

```bash
curl --fail-with-body --silent --show-error \
  -X PUT "$PLAYBOOK_API/faqs/$FAQ_ID/publication" \
  -H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" \
  -H 'Content-Type: application/json' \
  --data "$(jq -n --argjson version "$VERSION" '{version: $version}')" | jq .publication
```

##### CLI (Iris)

```bash
iris agent-playbooks faqs publish "$FAQ_ID" --version "$VERSION"
```



## List entries and inspect history

Use `list_faqs` to list entries, including unpublished ones, and `get_faq` to read a summary. Both require `read`. Summaries show the latest version number and any publication, without draft content.

Follow the pagination cursor until it is absent, even after an empty page. Keep filters and sort settings unchanged. Responses return `items` and `nextCursor` and don't include a total count. Lists can change while you page through them.

CLI lists and version history follow all cursors automatically and return an array. Use `--page` for one page with `nextCursor`, and `--cursor` to continue it. The CLI's version output currently omits `contentDigest`; use an SDK or cURL example when you need that field.

**Available in:** Python (Iris), cURL (Iris), CLI (Iris)

##### Python (Iris)

```python
cursor = None
while True:
    page = playbook.client.list_faqs(sort_by="updatedAt", sort_order="DESC", limit=50, cursor=cursor)
    for entry in page.items:
        print(entry.entry_id, entry.latest_version, entry.publication)
    cursor = page.next_cursor
    if cursor is None:
        break
```

##### cURL (Iris)

```bash
CURSOR=''
while true; do
  PAGE_ARGS=(--data-urlencode sortBy=updatedAt --data-urlencode sortOrder=DESC --data-urlencode limit=50)
  if [[ -n "$CURSOR" ]]; then PAGE_ARGS+=(--data-urlencode "cursor=$CURSOR"); fi
  curl --fail-with-body --silent --show-error --get "$PLAYBOOK_API/faqs" \
    -H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" "${PAGE_ARGS[@]}" > faq-page.json
  jq '.items[] | {entryId, latestVersion, publication}' faq-page.json
  CURSOR=$(jq -r '.nextCursor // empty' faq-page.json)
  [[ -n "$CURSOR" ]] || break
done
```

##### CLI (Iris)

```bash
iris --json agent-playbooks faqs list --sort-by updatedAt --sort-order desc --page-size 50 | jq .
```



For inventory counts, call `get_playbook_stats` with a reader key. Each count has an `available` flag: unavailable is different from zero. Counts are observations, not a fixed snapshot of the lists.

**Available in:** Python (Iris), cURL (Iris)

##### Python (Iris)

```python
stats = playbook.client.get_playbook_stats()
print("Observed at:", stats.observed_at)
for label, count in (("FAQs", stats.faqs.total), ("Skills", stats.skills.total)):
    print(label, count.value if count.available else "unavailable")
```

##### cURL (Iris)

```bash
curl --fail-with-body --silent --show-error \
  "$PLAYBOOK_API/stats" \
  -H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" \
  | jq '{observedAt, faqs: (if .faqs.total.available then .faqs.total.value else "unavailable" end), skills: (if .skills.total.available then .skills.total.value else "unavailable" end)}'
```



To select only published or unpublished entries, set `published` to `true` or `false`. Omit it to include both.

Listing full version history requires `write` or `publish`. Versions arrive newest first. This example uses the FAQ created in this guide:

**Available in:** Python (Iris), cURL (Iris), CLI (Iris)

##### Python (Iris)

```python
cursor = None
while True:
    page = playbook.client.list_faq_versions(faq_id=faq_id, limit=50, cursor=cursor)
    for item in page.items:
        print(item.version, item.content_digest, item.content)
    cursor = page.next_cursor
    if cursor is None:
        break
```

##### cURL (Iris)

```bash
CURSOR=''
while true; do
  PAGE_ARGS=(--data-urlencode limit=50)
  if [[ -n "$CURSOR" ]]; then PAGE_ARGS+=(--data-urlencode "cursor=$CURSOR"); fi
  curl --fail-with-body --silent --show-error --get "$PLAYBOOK_API/faqs/$FAQ_ID/versions" \
    -H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" "${PAGE_ARGS[@]}" > faq-versions.json
  jq '.items[] | {version, contentDigest, content}' faq-versions.json
  CURSOR=$(jq -r '.nextCursor // empty' faq-versions.json)
  [[ -n "$CURSOR" ]] || break
done
```

##### CLI (Iris)

```bash
iris --json agent-playbooks faqs versions "$FAQ_ID" --page-size 50 | jq .
```



## Look up entry state

Use `lookup_entries` with `write` or `publish` permission to inspect known FAQs or skills. Supply 1–100 references, each containing either an entry identifier or an entry key. Results preserve request order and report missing entries explicitly. The batch is not a fixed snapshot.

The published CLI has no batch lookup command. Use one of the SDK or cURL tabs for this operation.

Each found entry includes `latest`, optional `publication`, and `versionCount`. The response also reports the playbook's `maxVersions` limit. The two version summaries include `contentDigest`: a server-generated hash of normalized authored content. Compare their digests to check whether the latest and published content match. It is not a hash of the uploaded ZIP or the raw request, and it is not an idempotency key.

**Available in:** Python (Iris), cURL (Iris)

##### Python (Iris)

```python
from redis_agent_playbook.models import Found

lookup = playbook.client.lookup_entries(
    references=[
        {"entry_id": faq_id},
        {"entry_key": "refund-status"},
    ]
)
print("Version limit:", lookup.max_versions)
for result in lookup.items:
    if isinstance(result, Found):
        state = result.found.entry
        print(state.entry_id, state.version_count, state.latest, state.publication)
    else:
        print("Missing:", result.missing.reference)
```

##### cURL (Iris)

```bash
jq -n --arg id "$FAQ_ID" '{references: [{entryId: $id}, {entryKey: "refund-status"}]}' \
  | curl --fail-with-body --silent --show-error \
    -X POST "$PLAYBOOK_API/entries/lookup" \
    -H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" \
    -H 'Content-Type: application/json' --data-binary @- \
  | jq '{maxVersions, items}'
```



The example finds the same FAQ by identifier and by key. Either identifies the entry across versions, not a particular publication. Before retrying an uncertain write, inspect its state and relevant version. Appending identical content can still create another version.

## Withdraw or delete an FAQ

Use `withdraw_faq` to stop serving the answer while retaining the entry and its versions. Use `delete_faq` to remove the entry and its history permanently.

Set `PLAYBOOK_FAQ_ID` to the printed entry identifier before running a withdrawal or deletion example with the same connection values.

**Available in:** Python (Iris), cURL (Iris), CLI (Iris)

##### Python (Iris)

```python
playbook.client.withdraw_faq(faq_id=faq_id)
```

##### cURL (Iris)

```bash
curl --fail-with-body --silent --show-error \
  -X DELETE "$PLAYBOOK_API/faqs/$FAQ_ID/publication" \
  -H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" | jq .
```

##### CLI (Iris)

```bash
iris agent-playbooks faqs withdraw "$PLAYBOOK_FAQ_ID"
```



When you no longer need the sample history, delete the entry.

**Available in:** Python (Iris), cURL (Iris), CLI (Iris)

##### Python (Iris)

```python
playbook.client.delete_faq(faq_id=faq_id)
```

##### cURL (Iris)

```bash
curl --fail-with-body --silent --show-error \
  -X DELETE "$PLAYBOOK_API/faqs/$FAQ_ID" \
  -H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY"
```

##### CLI (Iris)

```bash
iris agent-playbooks faqs delete "$PLAYBOOK_FAQ_ID" --yes
```



