Dify annotations and annotation reply 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. Annotation text and job errors can contain confidential data. Approval must bind every mutation to the selected app, exact content, intended index configuration, and retained recovery evidence. Choose an operation | Operation suffix | Method and route | Purpose | Policy | | annotation.list | GET /v1/apps/annotations | List or search app annotations | Low-risk read; retry supported | | annotation.create | POST /v1/apps/annotations | Create one question-and-answer pair | Medium mutation; approval and key required | | annotation.update | PUT /v1/apps/annotations/{annotationid} | Replace both fields of one annotation | Medium mutation; approval and key required | | annotation.delete | DELETE /v1/apps/annotations/{annotationid} | Delete an annotation and its hit history | High mutation; approval and key required | | annotationreply.toggle | POST /v1/apps/annotation-reply/{action} | Start enable or disable work | High mutation; approval and key required | | annotationreply.status | GET /v1/apps/annotation-reply/{action}/status/{jobid} | Read provider job state | Low-risk read; retry supported | All six Tool operations are available in workflow, completion, chat, advanced-chat, agent-chat, and agent modes. They use the configured app Bearer credential and have no Dify end-user field. The capability template is: cap:dify:: Use tenant discovery to select the exact app capability. Annotation and job identifiers never select a different credential or app. List app annotations annotation.list accepts page, limit, and keyword through Action query. Page and limit default to 1 and 20. The pinned provider requires each to be at least 1 and declares no smaller route-specific maximum. { "query": { "page": 1, "limit": 20, "keyword": "refund policy" } } The response contains data, hasmore, limit, total, and page. Each record can contain id, question, answer, hitcount, and a Unix createdat timestamp. The connector permits at most 128 query keys and 256 scalar values per array. The provider performs keyword matching within the selected app. Create or replace an annotation Create and update both require a JSON body with question and answer. Update is a complete two-field replacement, not a partial patch. { "body": { "question": "When can a refund be requested?", "answer": "Submit the request within the approved service window." } } Use annotationid for update. The connector accepts a bounded path string, while the pinned provider route requires a UUID and edit permission. Create returns status 201 with the annotation record. Update returns status 200 with the replaced record. The connector wraps either response in its generic JSON result. Delete an annotation annotation.delete requires annotationid. The pinned provider checks edit permission, deletes the annotation and associated hit history, then returns an empty 204 response. { "annotationid": "0190c42f-2d5a-7000-8000-000000000301" } The connector represents the empty provider body as null inside the generic result. Deletion has no rollback contract, so preserve authorization and the approved record identity before dispatch. Enable or disable annotation reply Set action to enable or disable. The pinned provider validates the same three body fields for both actions: { "action": "enable", "body": { "scorethreshold": 0.82, "embeddingprovidername": "provider-name", "embeddingmodelname": "embedding-model-name" } } The score threshold is a floating-point similarity boundary. Provider and model names identify the embedding configuration used to index annotation questions. The disable implementation ignores those embedding values, but request validation still requires them at the pinned provider revision. Supply the known approved configuration instead of invented placeholders. A successful toggle response contains jobid and jobstatus. The initial state is normally waiting. A repeated provider request during active work can return processing with the existing job ID. The connector operation itself is synchronous because it receives this JSON acknowledgement. The provider indexing or deletion job continues in the background and has no connector cancellation capability. Track the provider job Call annotationreply.status with the exact action and UUID jobid returned by the toggle: { "action": "enable", "jobid": "0190c42f-2d5a-7000-8000-000000000302" } Known provider states are waiting, processing, completed, and error. An error response field can contain errormsg. The status lookup key is built from action and job ID. Bind both values to the selected app in the caller's evidence rather than treating the job ID as an app-scoped authorization token. At the pinned revision, completed and error status entries use a 600-second Redis retention period. Poll promptly and persist the terminal evidence needed by the caller. Do not treat a later missing job as proof of failure. Apply mutation governance The four mutations require a non-blank Action idempotency key of at most 512 bytes. AIP retains its tenant-scoped reservation for 24 hours and revalidates the input hash on collision. That reservation does not prove provider deduplication. None of the mutations publishes safe retry, transaction, reconciliation, cancellation, or compensation support. Treat questions, answers, hit counts, embedding choices, job identifiers, and error details as confidential PII-bearing data. Redact them from general logs and retain only the evidence required by policy. Recover safely | Observation | Decision | | Query, UUID, action, or body is rejected before dispatch | Correct the bounded request without claiming a provider effect | | Create or update loses its response after dispatch | Treat the outcome as uncertain; inspect the annotation list before another mutation | | Delete returns no usable response | Verify the record through a read before considering any replacement | | Toggle returns a job ID | Record the exact action and job ID, then poll status | | Toggle response is lost | Inspect provider configuration and retained evidence; do not replay automatically | | Job remains waiting or processing | Continue bounded polling; no connector cancellation is available | | Job reports error | Preserve the redacted error, repair configuration, and authorize a new Action | | Job status disappears after terminal retention | Use retained terminal evidence and current provider configuration | | Any record crosses an expected app boundary | Stop traffic and treat the event as an isolation incident | Preserve the Action ID, input digest, approval, idempotency key, app identity, annotation ID, action, job ID, and terminal provider evidence used to settle an ambiguous outcome. Related documentation • Dify capability index (README.md) • Dify connector overview (../README.md) • Dify connector configuration (../reference/configuration.md) • Authentication and credential scopes (../getting-started/authentication-and-credential-scopes.md) • Errors and retry decisions (../../../reference/errors.md)