{
  "schemaVersion": "1.0",
  "title": "Dify annotations and annotation reply",
  "description": "Use this family to list and maintain question-and-answer annotations for one Dify app. It also enables or disables annotation reply and exposes the provider background job that changes its search index.",
  "canonical": "https://getaip.org/docs/connectors/dify/capabilities/annotations",
  "route": "/docs/connectors/dify/capabilities/annotations",
  "source": "docs/connectors/dify/capabilities/annotations.md",
  "protocol": "Agent Interoperability Protocol",
  "protocolVersion": "1.0",
  "section": "Connectors",
  "documentType": "Connector",
  "language": "en",
  "downloads": {
    "md": "/docs/download/connectors/dify/capabilities/annotations.md",
    "txt": "/docs/download/connectors/dify/capabilities/annotations.txt",
    "json": "/docs/download/connectors/dify/capabilities/annotations.json",
    "pdf": "/docs/download/connectors/dify/capabilities/annotations.pdf"
  },
  "content": {
    "format": "text/markdown",
    "markdown": "---\ntitle: Dify annotations and annotation reply\ndescription: >-\n  Maintain app annotations and track annotation-reply indexing through the\n  frozen Dify connector\nkind: capability-reference\naudience: application-developer\nappliesTo: \"1.x\"\nwritingStandard: \"aip-docs/1.0\"\nlastReviewedRevision: \"97be86e9efedf07ecf1783b03800f683f107fb04\"\nconnector: dify\n---\n\n# Dify annotations and annotation reply\n\nUse this family to list and maintain question-and-answer annotations for one\nDify app. It also enables or disables annotation reply and exposes the\nprovider background job that changes its search index.\n\nAnnotation text and job errors can contain confidential data. Approval must\nbind every mutation to the selected app, exact content, intended index\nconfiguration, and retained recovery evidence.\n\n## Choose an operation\n\n| Operation suffix | Method and route | Purpose | Policy |\n|---|---|---|---|\n| `annotation.list` | `GET /v1/apps/annotations` | List or search app annotations | Low-risk read; retry supported |\n| `annotation.create` | `POST /v1/apps/annotations` | Create one question-and-answer pair | Medium mutation; approval and key required |\n| `annotation.update` | `PUT /v1/apps/annotations/{annotation_id}` | Replace both fields of one annotation | Medium mutation; approval and key required |\n| `annotation.delete` | `DELETE /v1/apps/annotations/{annotation_id}` | Delete an annotation and its hit history | High mutation; approval and key required |\n| `annotation_reply.toggle` | `POST /v1/apps/annotation-reply/{action}` | Start enable or disable work | High mutation; approval and key required |\n| `annotation_reply.status` | `GET /v1/apps/annotation-reply/{action}/status/{job_id}` | Read provider job state | Low-risk read; retry supported |\n\nAll six Tool operations are available in `workflow`, `completion`, `chat`,\n`advanced-chat`, `agent-chat`, and `agent` modes. They use the configured app\nBearer credential and have no Dify end-user field.\n\nThe capability template is:\n\n```text\ncap:dify:<app_id>:<operation>\n```\n\nUse tenant discovery to select the exact app capability. Annotation and job\nidentifiers never select a different credential or app.\n\n## List app annotations\n\n`annotation.list` accepts `page`, `limit`, and `keyword` through Action\n`query`. Page and limit default to 1 and 20. The pinned provider requires each\nto be at least 1 and declares no smaller route-specific maximum.\n\n```json\n{\n  \"query\": {\n    \"page\": 1,\n    \"limit\": 20,\n    \"keyword\": \"refund policy\"\n  }\n}\n```\n\nThe response contains `data`, `has_more`, `limit`, `total`, and `page`. Each\nrecord can contain `id`, `question`, `answer`, `hit_count`, and a Unix\n`created_at` timestamp.\n\nThe connector permits at most 128 query keys and 256 scalar values per array.\nThe provider performs keyword matching within the selected app.\n\n## Create or replace an annotation\n\nCreate and update both require a JSON `body` with `question` and `answer`.\nUpdate is a complete two-field replacement, not a partial patch.\n\n```json\n{\n  \"body\": {\n    \"question\": \"When can a refund be requested?\",\n    \"answer\": \"Submit the request within the approved service window.\"\n  }\n}\n```\n\nUse `annotation_id` for update. The connector accepts a bounded path string,\nwhile the pinned provider route requires a UUID and edit permission.\n\nCreate returns status 201 with the annotation record. Update returns status\n200 with the replaced record. The connector wraps either response in its\ngeneric JSON result.\n\n## Delete an annotation\n\n`annotation.delete` requires `annotation_id`. The pinned provider checks edit\npermission, deletes the annotation and associated hit history, then returns an\nempty 204 response.\n\n```json\n{\n  \"annotation_id\": \"0190c42f-2d5a-7000-8000-000000000301\"\n}\n```\n\nThe connector represents the empty provider body as `null` inside the generic\nresult. Deletion has no rollback contract, so preserve authorization and the\napproved record identity before dispatch.\n\n## Enable or disable annotation reply\n\nSet `action` to `enable` or `disable`. The pinned provider validates the same\nthree body fields for both actions:\n\n```json\n{\n  \"action\": \"enable\",\n  \"body\": {\n    \"score_threshold\": 0.82,\n    \"embedding_provider_name\": \"provider-name\",\n    \"embedding_model_name\": \"embedding-model-name\"\n  }\n}\n```\n\nThe score threshold is a floating-point similarity boundary. Provider and\nmodel names identify the embedding configuration used to index annotation\nquestions.\n\nThe disable implementation ignores those embedding values, but request\nvalidation still requires them at the pinned provider revision. Supply the\nknown approved configuration instead of invented placeholders.\n\nA successful toggle response contains `job_id` and `job_status`. The initial\nstate is normally `waiting`. A repeated provider request during active work\ncan return `processing` with the existing job ID.\n\nThe connector operation itself is synchronous because it receives this JSON\nacknowledgement. The provider indexing or deletion job continues in the\nbackground and has no connector cancellation capability.\n\n## Track the provider job\n\nCall `annotation_reply.status` with the exact `action` and UUID `job_id`\nreturned by the toggle:\n\n```json\n{\n  \"action\": \"enable\",\n  \"job_id\": \"0190c42f-2d5a-7000-8000-000000000302\"\n}\n```\n\nKnown provider states are `waiting`, `processing`, `completed`, and `error`.\nAn error response field can contain `error_msg`.\n\nThe status lookup key is built from action and job ID. Bind both values to the\nselected app in the caller's evidence rather than treating the job ID as an\napp-scoped authorization token.\n\nAt the pinned revision, completed and error status entries use a 600-second\nRedis retention period. Poll promptly and persist the terminal evidence\nneeded by the caller. Do not treat a later missing job as proof of failure.\n\n## Apply mutation governance\n\nThe four mutations require a non-blank Action idempotency key of at most 512\nbytes. AIP retains its tenant-scoped reservation for 24 hours and revalidates\nthe input hash on collision.\n\nThat reservation does not prove provider deduplication. None of the mutations\npublishes safe retry, transaction, reconciliation, cancellation, or\ncompensation support.\n\nTreat questions, answers, hit counts, embedding choices, job identifiers, and\nerror details as confidential PII-bearing data. Redact them from general logs\nand retain only the evidence required by policy.\n\n## Recover safely\n\n| Observation | Decision |\n|---|---|\n| Query, UUID, action, or body is rejected before dispatch | Correct the bounded request without claiming a provider effect |\n| Create or update loses its response after dispatch | Treat the outcome as uncertain; inspect the annotation list before another mutation |\n| Delete returns no usable response | Verify the record through a read before considering any replacement |\n| Toggle returns a job ID | Record the exact action and job ID, then poll status |\n| Toggle response is lost | Inspect provider configuration and retained evidence; do not replay automatically |\n| Job remains waiting or processing | Continue bounded polling; no connector cancellation is available |\n| Job reports error | Preserve the redacted error, repair configuration, and authorize a new Action |\n| Job status disappears after terminal retention | Use retained terminal evidence and current provider configuration |\n| Any record crosses an expected app boundary | Stop traffic and treat the event as an isolation incident |\n\nPreserve the Action ID, input digest, approval, idempotency key, app identity,\nannotation ID, action, job ID, and terminal provider evidence used to settle an\nambiguous outcome.\n\n## Related documentation\n\n- [Dify capability index](README.md)\n- [Dify connector overview](../README.md)\n- [Dify connector configuration](../reference/configuration.md)\n- [Authentication and credential scopes](../getting-started/authentication-and-credential-scopes.md)\n- [Errors and retry decisions](../../../reference/errors.md)\n",
    "text": "Dify annotations and annotation reply\n\nUse this family to list and maintain question-and-answer annotations for one\nDify app. It also enables or disables annotation reply and exposes the\nprovider background job that changes its search index.\n\nAnnotation text and job errors can contain confidential data. Approval must\nbind every mutation to the selected app, exact content, intended index\nconfiguration, and retained recovery evidence.\n\nChoose an operation\n\n| Operation suffix | Method and route | Purpose | Policy |\n\n| annotation.list | GET /v1/apps/annotations | List or search app annotations | Low-risk read; retry supported |\n| annotation.create | POST /v1/apps/annotations | Create one question-and-answer pair | Medium mutation; approval and key required |\n| annotation.update | PUT /v1/apps/annotations/{annotationid} | Replace both fields of one annotation | Medium mutation; approval and key required |\n| annotation.delete | DELETE /v1/apps/annotations/{annotationid} | Delete an annotation and its hit history | High mutation; approval and key required |\n| annotationreply.toggle | POST /v1/apps/annotation-reply/{action} | Start enable or disable work | High mutation; approval and key required |\n| annotationreply.status | GET /v1/apps/annotation-reply/{action}/status/{jobid} | Read provider job state | Low-risk read; retry supported |\n\nAll six Tool operations are available in workflow, completion, chat,\nadvanced-chat, agent-chat, and agent modes. They use the configured app\nBearer credential and have no Dify end-user field.\n\nThe capability template is:\n\ncap:dify::\n\nUse tenant discovery to select the exact app capability. Annotation and job\nidentifiers never select a different credential or app.\n\nList app annotations\n\nannotation.list accepts page, limit, and keyword through Action\nquery. Page and limit default to 1 and 20. The pinned provider requires each\nto be at least 1 and declares no smaller route-specific maximum.\n\n{\n  \"query\": {\n    \"page\": 1,\n    \"limit\": 20,\n    \"keyword\": \"refund policy\"\n  }\n}\n\nThe response contains data, hasmore, limit, total, and page. Each\nrecord can contain id, question, answer, hitcount, and a Unix\ncreatedat timestamp.\n\nThe connector permits at most 128 query keys and 256 scalar values per array.\nThe provider performs keyword matching within the selected app.\n\nCreate or replace an annotation\n\nCreate and update both require a JSON body with question and answer.\nUpdate is a complete two-field replacement, not a partial patch.\n\n{\n  \"body\": {\n    \"question\": \"When can a refund be requested?\",\n    \"answer\": \"Submit the request within the approved service window.\"\n  }\n}\n\nUse annotationid for update. The connector accepts a bounded path string,\nwhile the pinned provider route requires a UUID and edit permission.\n\nCreate returns status 201 with the annotation record. Update returns status\n200 with the replaced record. The connector wraps either response in its\ngeneric JSON result.\n\nDelete an annotation\n\nannotation.delete requires annotationid. The pinned provider checks edit\npermission, deletes the annotation and associated hit history, then returns an\nempty 204 response.\n\n{\n  \"annotationid\": \"0190c42f-2d5a-7000-8000-000000000301\"\n}\n\nThe connector represents the empty provider body as null inside the generic\nresult. Deletion has no rollback contract, so preserve authorization and the\napproved record identity before dispatch.\n\nEnable or disable annotation reply\n\nSet action to enable or disable. The pinned provider validates the same\nthree body fields for both actions:\n\n{\n  \"action\": \"enable\",\n  \"body\": {\n    \"scorethreshold\": 0.82,\n    \"embeddingprovidername\": \"provider-name\",\n    \"embeddingmodelname\": \"embedding-model-name\"\n  }\n}\n\nThe score threshold is a floating-point similarity boundary. Provider and\nmodel names identify the embedding configuration used to index annotation\nquestions.\n\nThe disable implementation ignores those embedding values, but request\nvalidation still requires them at the pinned provider revision. Supply the\nknown approved configuration instead of invented placeholders.\n\nA successful toggle response contains jobid and jobstatus. The initial\nstate is normally waiting. A repeated provider request during active work\ncan return processing with the existing job ID.\n\nThe connector operation itself is synchronous because it receives this JSON\nacknowledgement. The provider indexing or deletion job continues in the\nbackground and has no connector cancellation capability.\n\nTrack the provider job\n\nCall annotationreply.status with the exact action and UUID jobid\nreturned by the toggle:\n\n{\n  \"action\": \"enable\",\n  \"jobid\": \"0190c42f-2d5a-7000-8000-000000000302\"\n}\n\nKnown provider states are waiting, processing, completed, and error.\nAn error response field can contain errormsg.\n\nThe status lookup key is built from action and job ID. Bind both values to the\nselected app in the caller's evidence rather than treating the job ID as an\napp-scoped authorization token.\n\nAt the pinned revision, completed and error status entries use a 600-second\nRedis retention period. Poll promptly and persist the terminal evidence\nneeded by the caller. Do not treat a later missing job as proof of failure.\n\nApply mutation governance\n\nThe four mutations require a non-blank Action idempotency key of at most 512\nbytes. AIP retains its tenant-scoped reservation for 24 hours and revalidates\nthe input hash on collision.\n\nThat reservation does not prove provider deduplication. None of the mutations\npublishes safe retry, transaction, reconciliation, cancellation, or\ncompensation support.\n\nTreat questions, answers, hit counts, embedding choices, job identifiers, and\nerror details as confidential PII-bearing data. Redact them from general logs\nand retain only the evidence required by policy.\n\nRecover safely\n\n| Observation | Decision |\n\n| Query, UUID, action, or body is rejected before dispatch | Correct the bounded request without claiming a provider effect |\n| Create or update loses its response after dispatch | Treat the outcome as uncertain; inspect the annotation list before another mutation |\n| Delete returns no usable response | Verify the record through a read before considering any replacement |\n| Toggle returns a job ID | Record the exact action and job ID, then poll status |\n| Toggle response is lost | Inspect provider configuration and retained evidence; do not replay automatically |\n| Job remains waiting or processing | Continue bounded polling; no connector cancellation is available |\n| Job reports error | Preserve the redacted error, repair configuration, and authorize a new Action |\n| Job status disappears after terminal retention | Use retained terminal evidence and current provider configuration |\n| Any record crosses an expected app boundary | Stop traffic and treat the event as an isolation incident |\n\nPreserve the Action ID, input digest, approval, idempotency key, app identity,\nannotation ID, action, job ID, and terminal provider evidence used to settle an\nambiguous outcome.\n\nRelated documentation\n• Dify capability index (README.md)\n• Dify connector overview (../README.md)\n• Dify connector configuration (../reference/configuration.md)\n• Authentication and credential scopes (../getting-started/authentication-and-credential-scopes.md)\n• Errors and retry decisions (../../../reference/errors.md)\n"
  },
  "integrity": {
    "algorithm": "sha256",
    "sourceDigest": "38c085dce6abacd768245696d399d1557371745f9444e6ee4480806a5305792a"
  }
}
