{
  "asyncapi": "3.0.0",
  "info": {
    "title": "VeriProof review events",
    "version": "1.0.0",
    "description": "Signed, thin events that tell your systems when review work exists or changes. Delivery is at least once with no ordering guarantee: de-duplicate by id and order by caseVersion, then eventSequence. Answer 2xx within 10 seconds after storing the event. Every request is signed under the Standard Webhooks profile. An answer to an event never records a review decision."
  },
  "defaultContentType": "application/json",
  "channels": {
    "subscriberEndpoint": {
      "address": null,
      "title": "Your subscription endpoint",
      "description": "The HTTPS URL you registered. VeriProof sends each event as an HTTP POST.",
      "messages": {
        "ReviewCaseCreated": {
          "$ref": "#/components/messages/ReviewCaseCreated"
        },
        "ReviewCaseAssignmentChanged": {
          "$ref": "#/components/messages/ReviewCaseAssignmentChanged"
        },
        "ReviewCaseFollowUpRequired": {
          "$ref": "#/components/messages/ReviewCaseFollowUpRequired"
        },
        "ReviewCaseDecided": {
          "$ref": "#/components/messages/ReviewCaseDecided"
        },
        "ReviewCaseCancelled": {
          "$ref": "#/components/messages/ReviewCaseCancelled"
        },
        "ReviewCaseExpired": {
          "$ref": "#/components/messages/ReviewCaseExpired"
        },
        "ReviewCaseOverdue": {
          "$ref": "#/components/messages/ReviewCaseOverdue"
        },
        "ReviewContinuationAcknowledged": {
          "$ref": "#/components/messages/ReviewContinuationAcknowledged"
        },
        "ReviewContinuationDeliveryFailed": {
          "$ref": "#/components/messages/ReviewContinuationDeliveryFailed"
        },
        "SubscriptionVerificationRequested": {
          "$ref": "#/components/messages/SubscriptionVerificationRequested"
        },
        "SubscriptionDisabled": {
          "$ref": "#/components/messages/SubscriptionDisabled"
        },
        "SubscriptionSigningKeyRotating": {
          "$ref": "#/components/messages/SubscriptionSigningKeyRotating"
        },
        "SubscriptionEventsMissed": {
          "$ref": "#/components/messages/SubscriptionEventsMissed"
        }
      }
    }
  },
  "operations": {
    "sendReviewEvent": {
      "action": "send",
      "summary": "VeriProof sends the review events your subscription selected.",
      "channel": {
        "$ref": "#/channels/subscriberEndpoint"
      },
      "messages": [
        {
          "$ref": "#/channels/subscriberEndpoint/messages/ReviewCaseCreated"
        },
        {
          "$ref": "#/channels/subscriberEndpoint/messages/ReviewCaseAssignmentChanged"
        },
        {
          "$ref": "#/channels/subscriberEndpoint/messages/ReviewCaseFollowUpRequired"
        },
        {
          "$ref": "#/channels/subscriberEndpoint/messages/ReviewCaseDecided"
        },
        {
          "$ref": "#/channels/subscriberEndpoint/messages/ReviewCaseCancelled"
        },
        {
          "$ref": "#/channels/subscriberEndpoint/messages/ReviewCaseExpired"
        },
        {
          "$ref": "#/channels/subscriberEndpoint/messages/ReviewCaseOverdue"
        },
        {
          "$ref": "#/channels/subscriberEndpoint/messages/ReviewContinuationAcknowledged"
        },
        {
          "$ref": "#/channels/subscriberEndpoint/messages/ReviewContinuationDeliveryFailed"
        }
      ]
    },
    "sendSubscriptionEvent": {
      "action": "send",
      "summary": "VeriProof sends events about the subscription itself. Every subscription gets these.",
      "channel": {
        "$ref": "#/channels/subscriberEndpoint"
      },
      "messages": [
        {
          "$ref": "#/channels/subscriberEndpoint/messages/SubscriptionVerificationRequested"
        },
        {
          "$ref": "#/channels/subscriberEndpoint/messages/SubscriptionDisabled"
        },
        {
          "$ref": "#/channels/subscriberEndpoint/messages/SubscriptionSigningKeyRotating"
        },
        {
          "$ref": "#/channels/subscriberEndpoint/messages/SubscriptionEventsMissed"
        }
      ]
    }
  },
  "components": {
    "messages": {
      "ReviewCaseCreated": {
        "name": "review.case.created",
        "title": "review.case.created",
        "summary": "A review case was created and is waiting for a reviewer.",
        "contentType": "application/json",
        "headers": {
          "$ref": "#/components/schemas/StandardWebhookHeaders"
        },
        "payload": {
          "allOf": [
            {
              "$ref": "#/components/schemas/ReviewEvent"
            },
            {
              "type": "object",
              "properties": {
                "type": {
                  "const": "review.case.created"
                }
              }
            }
          ]
        },
        "bindings": {
          "http": {
            "method": "POST",
            "bindingVersion": "0.3.0"
          }
        }
      },
      "ReviewCaseAssignmentChanged": {
        "name": "review.case.assignment_changed",
        "title": "review.case.assignment_changed",
        "summary": "A reviewer claimed the case, or it moved to a different reviewer.",
        "contentType": "application/json",
        "headers": {
          "$ref": "#/components/schemas/StandardWebhookHeaders"
        },
        "payload": {
          "allOf": [
            {
              "$ref": "#/components/schemas/ReviewEvent"
            },
            {
              "type": "object",
              "properties": {
                "type": {
                  "const": "review.case.assignment_changed"
                }
              }
            }
          ]
        },
        "bindings": {
          "http": {
            "method": "POST",
            "bindingVersion": "0.3.0"
          }
        }
      },
      "ReviewCaseFollowUpRequired": {
        "name": "review.case.follow_up_required",
        "title": "review.case.follow_up_required",
        "summary": "The reviewer asked the application a question; the case stays open.",
        "contentType": "application/json",
        "headers": {
          "$ref": "#/components/schemas/StandardWebhookHeaders"
        },
        "payload": {
          "allOf": [
            {
              "$ref": "#/components/schemas/ReviewEvent"
            },
            {
              "type": "object",
              "properties": {
                "type": {
                  "const": "review.case.follow_up_required"
                }
              }
            }
          ]
        },
        "bindings": {
          "http": {
            "method": "POST",
            "bindingVersion": "0.3.0"
          }
        }
      },
      "ReviewCaseDecided": {
        "name": "review.case.decided",
        "title": "review.case.decided",
        "summary": "The reviewer recorded a final decision.",
        "contentType": "application/json",
        "headers": {
          "$ref": "#/components/schemas/StandardWebhookHeaders"
        },
        "payload": {
          "allOf": [
            {
              "$ref": "#/components/schemas/ReviewEvent"
            },
            {
              "type": "object",
              "properties": {
                "type": {
                  "const": "review.case.decided"
                }
              }
            }
          ]
        },
        "bindings": {
          "http": {
            "method": "POST",
            "bindingVersion": "0.3.0"
          }
        }
      },
      "ReviewCaseCancelled": {
        "name": "review.case.cancelled",
        "title": "review.case.cancelled",
        "summary": "The case was cancelled before a decision.",
        "contentType": "application/json",
        "headers": {
          "$ref": "#/components/schemas/StandardWebhookHeaders"
        },
        "payload": {
          "allOf": [
            {
              "$ref": "#/components/schemas/ReviewEvent"
            },
            {
              "type": "object",
              "properties": {
                "type": {
                  "const": "review.case.cancelled"
                }
              }
            }
          ]
        },
        "bindings": {
          "http": {
            "method": "POST",
            "bindingVersion": "0.3.0"
          }
        }
      },
      "ReviewCaseExpired": {
        "name": "review.case.expired",
        "title": "review.case.expired",
        "summary": "The case expired without a decision. Expiry never approves the action.",
        "contentType": "application/json",
        "headers": {
          "$ref": "#/components/schemas/StandardWebhookHeaders"
        },
        "payload": {
          "allOf": [
            {
              "$ref": "#/components/schemas/ReviewEvent"
            },
            {
              "type": "object",
              "properties": {
                "type": {
                  "const": "review.case.expired"
                }
              }
            }
          ]
        },
        "bindings": {
          "http": {
            "method": "POST",
            "bindingVersion": "0.3.0"
          }
        }
      },
      "ReviewCaseOverdue": {
        "name": "review.case.overdue",
        "title": "review.case.overdue",
        "summary": "The case passed its due time without a decision.",
        "contentType": "application/json",
        "headers": {
          "$ref": "#/components/schemas/StandardWebhookHeaders"
        },
        "payload": {
          "allOf": [
            {
              "$ref": "#/components/schemas/ReviewEvent"
            },
            {
              "type": "object",
              "properties": {
                "type": {
                  "const": "review.case.overdue"
                }
              }
            }
          ]
        },
        "bindings": {
          "http": {
            "method": "POST",
            "bindingVersion": "0.3.0"
          }
        }
      },
      "ReviewContinuationAcknowledged": {
        "name": "review.continuation.acknowledged",
        "title": "review.continuation.acknowledged",
        "summary": "The application reported what it did with the outcome.",
        "contentType": "application/json",
        "headers": {
          "$ref": "#/components/schemas/StandardWebhookHeaders"
        },
        "payload": {
          "allOf": [
            {
              "$ref": "#/components/schemas/ReviewEvent"
            },
            {
              "type": "object",
              "properties": {
                "type": {
                  "const": "review.continuation.acknowledged"
                }
              }
            }
          ]
        },
        "bindings": {
          "http": {
            "method": "POST",
            "bindingVersion": "0.3.0"
          }
        }
      },
      "ReviewContinuationDeliveryFailed": {
        "name": "review.continuation.delivery_failed",
        "title": "review.continuation.delivery_failed",
        "summary": "VeriProof could not deliver the outcome to the application\u0027s callback.",
        "contentType": "application/json",
        "headers": {
          "$ref": "#/components/schemas/StandardWebhookHeaders"
        },
        "payload": {
          "allOf": [
            {
              "$ref": "#/components/schemas/ReviewEvent"
            },
            {
              "type": "object",
              "properties": {
                "type": {
                  "const": "review.continuation.delivery_failed"
                }
              }
            }
          ]
        },
        "bindings": {
          "http": {
            "method": "POST",
            "bindingVersion": "0.3.0"
          }
        }
      },
      "SubscriptionVerificationRequested": {
        "name": "subscription.verification_requested",
        "title": "subscription.verification_requested",
        "summary": "Prove you control the endpoint: answer 2xx with {\u0022challenge\u0022: \u0022\u003Cthe challenge value\u003E\u0022}.",
        "contentType": "application/json",
        "headers": {
          "$ref": "#/components/schemas/StandardWebhookHeaders"
        },
        "payload": {
          "allOf": [
            {
              "$ref": "#/components/schemas/SubscriptionLifecycleEvent"
            },
            {
              "type": "object",
              "properties": {
                "type": {
                  "const": "subscription.verification_requested"
                }
              }
            }
          ]
        },
        "bindings": {
          "http": {
            "method": "POST",
            "bindingVersion": "0.3.0"
          }
        }
      },
      "SubscriptionDisabled": {
        "name": "subscription.disabled",
        "title": "subscription.disabled",
        "summary": "VeriProof stopped sending events to this endpoint.",
        "contentType": "application/json",
        "headers": {
          "$ref": "#/components/schemas/StandardWebhookHeaders"
        },
        "payload": {
          "allOf": [
            {
              "$ref": "#/components/schemas/SubscriptionLifecycleEvent"
            },
            {
              "type": "object",
              "properties": {
                "type": {
                  "const": "subscription.disabled"
                }
              }
            }
          ]
        },
        "bindings": {
          "http": {
            "method": "POST",
            "bindingVersion": "0.3.0"
          }
        }
      },
      "SubscriptionSigningKeyRotating": {
        "name": "subscription.signing_key_rotating",
        "title": "subscription.signing_key_rotating",
        "summary": "The shared signing secret was rotated; the previous secret keeps signing until previousSecretValidUntil.",
        "contentType": "application/json",
        "headers": {
          "$ref": "#/components/schemas/StandardWebhookHeaders"
        },
        "payload": {
          "allOf": [
            {
              "$ref": "#/components/schemas/SubscriptionLifecycleEvent"
            },
            {
              "type": "object",
              "properties": {
                "type": {
                  "const": "subscription.signing_key_rotating"
                }
              }
            }
          ]
        },
        "bindings": {
          "http": {
            "method": "POST",
            "bindingVersion": "0.3.0"
          }
        }
      },
      "SubscriptionEventsMissed": {
        "name": "subscription.events_missed",
        "title": "subscription.events_missed",
        "summary": "The subscription is receiving again; events between missedFrom and missedUntil were not sent.",
        "contentType": "application/json",
        "headers": {
          "$ref": "#/components/schemas/StandardWebhookHeaders"
        },
        "payload": {
          "allOf": [
            {
              "$ref": "#/components/schemas/SubscriptionLifecycleEvent"
            },
            {
              "type": "object",
              "properties": {
                "type": {
                  "const": "subscription.events_missed"
                }
              }
            }
          ]
        },
        "bindings": {
          "http": {
            "method": "POST",
            "bindingVersion": "0.3.0"
          }
        }
      }
    },
    "schemas": {
      "ReviewEvent": {
        "description": "A thin review event. Fetch prompts, evidence, and reviewer detail from caseUrl with an application key.",
        "type": "object",
        "properties": {
          "id": {
            "description": "Stable event ID. Retries and replays reuse it, and it is also the webhook-id header. De-duplicate on it.",
            "type": "string"
          },
          "type": {
            "description": "One of the review.* event types.",
            "type": "string",
            "enum": [
              "review.case.created",
              "review.case.assignment_changed",
              "review.case.follow_up_required",
              "review.case.decided",
              "review.case.cancelled",
              "review.case.expired",
              "review.case.overdue",
              "review.continuation.acknowledged",
              "review.continuation.delivery_failed"
            ]
          },
          "schemaVersion": {
            "description": "Version of this payload shape.",
            "type": "integer",
            "const": 1
          },
          "time": {
            "description": "When the change happened (UTC).",
            "type": "string",
            "format": "date-time"
          },
          "tenantId": {
            "description": "Your VeriProof tenant ID.",
            "type": "string"
          },
          "applicationId": {
            "description": "The application that asked for the review.",
            "type": "string"
          },
          "sessionId": {
            "description": "The session the review belongs to.",
            "type": "string"
          },
          "reviewCaseId": {
            "description": "The review case ID.",
            "type": "string"
          },
          "caseVersion": {
            "description": "Case version after the change. Order events for a case by caseVersion, then eventSequence.",
            "type": "integer"
          },
          "eventSequence": {
            "description": "Strictly increasing sequence of recorded events for this case.",
            "type": "integer"
          },
          "decision": {
            "description": "Canonical decision when one exists: approved, rejected, follow_up_required, response_submitted, cancelled, or expired. Never includes reviewer comments.",
            "type": [
              "string",
              "null"
            ]
          },
          "reviewTier": {
            "description": "Review urgency tier: standard, high, or urgent.",
            "type": "string",
            "enum": [
              "standard",
              "high",
              "urgent"
            ]
          },
          "dueAt": {
            "description": "When a decision is due.",
            "type": "string",
            "format": "date-time"
          },
          "expiresAt": {
            "description": "When the case expires. An expired case never approves the action.",
            "type": "string",
            "format": "date-time"
          },
          "reasonCategory": {
            "description": "Bounded reason for the event; unknown values become other.",
            "type": "string",
            "enum": [
              "policy_requires_human_review",
              "high_risk_action",
              "sensitive_data",
              "end_user_cancelled",
              "parent_workflow_ended",
              "safer_alternative_completed",
              "checkpoint_unavailable",
              "checkpoint_superseded",
              "application_lifecycle",
              "policy_rule_withdrawn",
              "expired",
              "overdue",
              "callback_delivery_failed",
              "resumed",
              "terminated",
              "remained_paused",
              "superseded",
              "failed",
              "reassigned",
              "claimed",
              "other"
            ]
          },
          "presentationDigest": {
            "description": "SHA-256 (hex) of what the assigned reviewer is shown. Absent until the case has an assignment.",
            "type": [
              "string",
              "null"
            ]
          },
          "caseUrl": {
            "description": "Authenticated application API URL that reads the case, including any protected detail the caller is entitled to.",
            "type": "string"
          }
        },
        "required": [
          "id",
          "type",
          "schemaVersion",
          "time",
          "tenantId",
          "applicationId",
          "sessionId",
          "reviewCaseId",
          "caseVersion",
          "eventSequence",
          "reviewTier",
          "dueAt",
          "expiresAt",
          "reasonCategory",
          "caseUrl"
        ],
        "additionalProperties": false
      },
      "SubscriptionLifecycleEvent": {
        "description": "An event about the subscription itself. Every subscription receives these.",
        "type": "object",
        "properties": {
          "id": {
            "description": "Stable event ID, also the webhook-id header.",
            "type": "string"
          },
          "type": {
            "description": "One of the subscription.* event types.",
            "type": "string",
            "enum": [
              "subscription.verification_requested",
              "subscription.disabled",
              "subscription.signing_key_rotating",
              "subscription.events_missed"
            ]
          },
          "schemaVersion": {
            "description": "Version of this payload shape.",
            "type": "integer",
            "const": 1
          },
          "time": {
            "description": "When the event was created (UTC).",
            "type": "string",
            "format": "date-time"
          },
          "tenantId": {
            "description": "Your VeriProof tenant ID.",
            "type": "string"
          },
          "subscriptionId": {
            "description": "The subscription (webhook) ID.",
            "type": "string"
          },
          "challenge": {
            "description": "subscription.verification_requested only. Answer 2xx with {\u0022challenge\u0022: \u0022\u003Cthis value\u003E\u0022} within 10 seconds.",
            "type": [
              "string",
              "null"
            ]
          },
          "reason": {
            "description": "subscription.disabled only: endpoint_gone or retries_exhausted.",
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "endpoint_gone",
              "retries_exhausted",
              null
            ]
          },
          "previousSecretValidUntil": {
            "description": "subscription.signing_key_rotating only: when the previous shared secret stops signing.",
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "missedFrom": {
            "description": "subscription.events_missed only: start of the window in which events were not sent.",
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "missedUntil": {
            "description": "subscription.events_missed only: end of the window in which events were not sent.",
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "type",
          "schemaVersion",
          "time",
          "tenantId",
          "subscriptionId"
        ],
        "additionalProperties": false
      },
      "StandardWebhookHeaders": {
        "type": "object",
        "required": [
          "webhook-id",
          "webhook-timestamp",
          "webhook-signature"
        ],
        "properties": {
          "webhook-id": {
            "type": "string",
            "description": "The event id. Retries and replays of an event reuse it."
          },
          "webhook-timestamp": {
            "type": "string",
            "description": "Unix seconds when this attempt was signed. Reject values more than five minutes from your clock."
          },
          "webhook-signature": {
            "type": "string",
            "description": "Space-separated signatures over \u0022{webhook-id}.{webhook-timestamp}.{body}\u0022: v1a,\u003Ced25519\u003E by default, or v1,\u003CHMAC-SHA256\u003E for shared-secret subscriptions. One valid signature is enough."
          },
          "webhook-key-version": {
            "type": "string",
            "description": "Diagnostic only. Select keys by signature, not by this header."
          }
        }
      }
    }
  }
}
