{
  "openapi": "3.1.0",
  "info": {
    "title": "DocinVault API",
    "version": "1.0.0",
    "description": "Create booking-linked guest compliance sessions, retrieve structured outcomes, compile evidence package manifests, and validate signed webhook events.",
    "contact": {
      "name": "DocinVault developer support",
      "email": "contact@docinvault.com",
      "url": "https://docinvault.com/developers"
    }
  },
  "jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
  "servers": [
    {
      "url": "https://sandbox.api.docinvault.com",
      "description": "Sandbox environment for controlled integration testing"
    },
    {
      "url": "https://api.docinvault.com",
      "description": "Production environment"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Compliance sessions",
      "description": "Booking-linked workflow creation and result retrieval"
    },
    {
      "name": "Evidence packages",
      "description": "Compiled manifests and cryptographic integrity references"
    },
    {
      "name": "Webhooks",
      "description": "Signature verification for asynchronous event delivery"
    }
  ],
  "paths": {
    "/v1/compliance-sessions": {
      "post": {
        "operationId": "createComplianceSession",
        "summary": "Create a booking-linked compliance session",
        "description": "Creates one compliance session from a configured workflow profile. Reusing the same Idempotency-Key with the same request body returns the original result.",
        "tags": ["Compliance sessions"],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ComplianceSessionCreateRequest"
              },
              "examples": {
                "remoteCheckIn": {
                  "summary": "Remote guest check-in",
                  "value": {
                    "bookingReference": "DV-1048",
                    "propertyReference": "property-tbilisi-01",
                    "workflowKey": "remote-check-in-v3",
                    "guest": {
                      "reference": "guest-a",
                      "email": "guest.a@example.com"
                    },
                    "locale": "en-GB",
                    "returnUrl": "https://operator.example/bookings/DV-1048",
                    "metadata": {
                      "arrivalDate": "2026-09-12",
                      "channel": "direct"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Compliance session created",
            "headers": {
              "Idempotency-Key": {
                "$ref": "#/components/headers/IdempotencyKey"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ComplianceSession"
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "409": { "$ref": "#/components/responses/Conflict" },
          "422": { "$ref": "#/components/responses/UnprocessableEntity" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/v1/compliance-sessions/{id}": {
      "get": {
        "operationId": "getComplianceSession",
        "summary": "Retrieve session status and step results",
        "description": "Returns the current workflow status, configured step outcomes, and machine-readable reason codes.",
        "tags": ["Compliance sessions"],
        "parameters": [
          { "$ref": "#/components/parameters/ComplianceSessionId" }
        ],
        "responses": {
          "200": {
            "description": "Current compliance session state",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ComplianceSession" },
                "examples": {
                  "needsReview": {
                    "value": {
                      "id": "cs_01J8DV1048",
                      "object": "compliance_session",
                      "bookingReference": "DV-1048",
                      "propertyReference": "property-tbilisi-01",
                      "workflowKey": "remote-check-in-v3",
                      "workflowVersion": 3,
                      "status": "NEEDS_REVIEW",
                      "reasonCodes": ["DOCUMENT_IMAGE_GLARE"],
                      "steps": [
                        {
                          "type": "DOCUMENT",
                          "status": "NEEDS_REVIEW",
                          "reasonCodes": ["DOCUMENT_IMAGE_GLARE"],
                          "completedAt": null
                        },
                        {
                          "type": "LIVENESS",
                          "status": "PASSED",
                          "reasonCodes": [],
                          "completedAt": "2026-09-01T09:18:22Z"
                        }
                      ],
                      "createdAt": "2026-09-01T09:15:00Z",
                      "updatedAt": "2026-09-01T09:18:22Z",
                      "expiresAt": "2026-09-02T09:15:00Z"
                    }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/v1/compliance-sessions/{id}/evidence-package": {
      "get": {
        "operationId": "getEvidencePackage",
        "summary": "Retrieve an evidence package manifest",
        "description": "Returns the compiled manifest, booking linkage, audit events, retention state, and SHA-256 integrity hashes available for the configured workflow.",
        "tags": ["Evidence packages"],
        "parameters": [
          { "$ref": "#/components/parameters/ComplianceSessionId" }
        ],
        "responses": {
          "200": {
            "description": "Evidence package manifest",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/EvidencePackage" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "409": { "$ref": "#/components/responses/Conflict" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/v1/webhooks/verify": {
      "post": {
        "operationId": "verifyWebhookSignature",
        "summary": "Validate a signed webhook payload",
        "description": "Validates the X-DocinVault-Signature header against the unmodified request body. Consumers should also reject event identifiers they have already processed.",
        "tags": ["Webhooks"],
        "security": [],
        "parameters": [
          { "$ref": "#/components/parameters/DocinVaultSignature" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/WebhookEvent" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Signature result",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/WebhookVerificationResult" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "422": { "$ref": "#/components/responses/UnprocessableEntity" }
        }
      }
    }
  },
  "webhooks": {
    "complianceSessionUpdated": {
      "post": {
        "summary": "Compliance session state changed",
        "description": "Asynchronous, signed event. Delivery may be retried, so consumers must process the event idempotently.",
        "parameters": [
          { "$ref": "#/components/parameters/DocinVaultSignature" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/WebhookEvent" }
            }
          }
        },
        "responses": {
          "200": { "description": "Event accepted" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "API token",
        "description": "Send the server-side API token as Authorization: Bearer <token>."
      }
    },
    "parameters": {
      "ComplianceSessionId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "Compliance session identifier",
        "schema": {
          "type": "string",
          "pattern": "^cs_[A-Za-z0-9]+$",
          "example": "cs_01J8DV1048"
        }
      },
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": true,
        "description": "A unique key for safely retrying a create request. Retain the same key only when the request body is unchanged.",
        "schema": {
          "type": "string",
          "minLength": 16,
          "maxLength": 255,
          "example": "booking-DV-1048-workflow-v3"
        }
      },
      "DocinVaultSignature": {
        "name": "X-DocinVault-Signature",
        "in": "header",
        "required": true,
        "description": "HMAC SHA-256 signature of the exact raw request body using the webhook signing secret.",
        "schema": {
          "type": "string",
          "pattern": "^sha256=[a-f0-9]{64}$",
          "example": "sha256=7fdc1d4d346f274b4a7fe25d0b62eeb0f8c59fce1f8cbbf5f72457a9a70e5b3d"
        }
      }
    },
    "headers": {
      "IdempotencyKey": {
        "description": "The idempotency key associated with the response",
        "schema": { "type": "string" }
      }
    },
    "schemas": {
      "ComplianceSessionCreateRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": ["bookingReference", "propertyReference", "workflowKey", "guest"],
        "properties": {
          "bookingReference": { "type": "string", "minLength": 1, "maxLength": 128 },
          "propertyReference": { "type": "string", "minLength": 1, "maxLength": 128 },
          "workflowKey": { "type": "string", "minLength": 1, "maxLength": 128 },
          "guest": { "$ref": "#/components/schemas/GuestReference" },
          "locale": { "type": "string", "pattern": "^[a-z]{2}(-[A-Z]{2})?$", "default": "en" },
          "returnUrl": { "type": "string", "format": "uri" },
          "metadata": {
            "type": "object",
            "description": "Customer-defined non-sensitive booking context. Do not send raw identity documents in metadata.",
            "additionalProperties": { "type": ["string", "number", "boolean", "null"] }
          }
        }
      },
      "GuestReference": {
        "type": "object",
        "additionalProperties": false,
        "required": ["reference"],
        "properties": {
          "reference": { "type": "string", "minLength": 1, "maxLength": 128 },
          "email": { "type": "string", "format": "email" },
          "phone": { "type": "string", "pattern": "^\\+[1-9][0-9]{6,14}$" }
        }
      },
      "ComplianceSession": {
        "type": "object",
        "additionalProperties": false,
        "required": ["id", "object", "bookingReference", "propertyReference", "workflowKey", "workflowVersion", "status", "reasonCodes", "steps", "createdAt", "updatedAt"],
        "properties": {
          "id": { "type": "string", "example": "cs_01J8DV1048" },
          "object": { "type": "string", "const": "compliance_session" },
          "bookingReference": { "type": "string" },
          "propertyReference": { "type": "string" },
          "workflowKey": { "type": "string" },
          "workflowVersion": { "type": "integer", "minimum": 1 },
          "status": { "$ref": "#/components/schemas/ComplianceSessionStatus" },
          "reasonCodes": { "type": "array", "items": { "type": "string" }, "uniqueItems": true },
          "steps": { "type": "array", "items": { "$ref": "#/components/schemas/StepResult" } },
          "createdAt": { "type": "string", "format": "date-time" },
          "updatedAt": { "type": "string", "format": "date-time" },
          "expiresAt": { "type": ["string", "null"], "format": "date-time" }
        }
      },
      "ComplianceSessionStatus": {
        "type": "string",
        "enum": ["PENDING", "IN_PROGRESS", "NEEDS_REVIEW", "VERIFIED", "INCOMPLETE", "FAILED", "EXPIRED"]
      },
      "StepResult": {
        "type": "object",
        "additionalProperties": false,
        "required": ["type", "status", "reasonCodes", "completedAt"],
        "properties": {
          "type": {
            "type": "string",
            "enum": ["DOCUMENT", "LIVENESS", "FACE_MATCH", "ADDRESS", "AML", "KYB", "AGE", "QUESTIONNAIRE", "NFC", "KYT", "MANUAL_REVIEW"]
          },
          "status": {
            "type": "string",
            "enum": ["PENDING", "IN_PROGRESS", "PASSED", "FAILED", "NEEDS_REVIEW", "SKIPPED"]
          },
          "reasonCodes": { "type": "array", "items": { "type": "string" }, "uniqueItems": true },
          "completedAt": { "type": ["string", "null"], "format": "date-time" }
        }
      },
      "EvidencePackage": {
        "type": "object",
        "additionalProperties": false,
        "required": ["id", "object", "complianceSessionId", "bookingReference", "workflowVersion", "generatedAt", "entries", "auditEvents", "exportManifest"],
        "properties": {
          "id": { "type": "string", "example": "ep_01J8DV1048" },
          "object": { "type": "string", "const": "evidence_package" },
          "complianceSessionId": { "type": "string", "example": "cs_01J8DV1048" },
          "bookingReference": { "type": "string", "example": "DV-1048" },
          "workflowVersion": { "type": "integer", "minimum": 1 },
          "generatedAt": { "type": "string", "format": "date-time" },
          "entries": { "type": "array", "items": { "$ref": "#/components/schemas/EvidenceEntry" } },
          "auditEvents": { "type": "array", "items": { "$ref": "#/components/schemas/AuditEvent" } },
          "exportManifest": { "$ref": "#/components/schemas/ExportManifest" }
        }
      },
      "EvidenceEntry": {
        "type": "object",
        "additionalProperties": false,
        "required": ["type", "reference", "sha256", "capturedAt", "retentionState"],
        "properties": {
          "type": { "type": "string", "enum": ["DOCUMENT_RESULT", "MRZ_DATA", "NFC_DATA", "LIVENESS_RESULT", "CONSENT_RECORD", "REVIEW_DECISION", "DELIVERY_RECEIPT"] },
          "reference": { "type": "string" },
          "sha256": { "type": "string", "pattern": "^[a-f0-9]{64}$" },
          "capturedAt": { "type": "string", "format": "date-time" },
          "retentionState": { "type": "string", "enum": ["ACTIVE", "SCHEDULED_FOR_DELETION", "DELETED", "LEGAL_HOLD"] }
        }
      },
      "AuditEvent": {
        "type": "object",
        "additionalProperties": false,
        "required": ["id", "type", "actorType", "occurredAt"],
        "properties": {
          "id": { "type": "string" },
          "type": { "type": "string" },
          "actorType": { "type": "string", "enum": ["AGENT", "HUMAN", "SYSTEM", "GUEST"] },
          "reasonCode": { "type": ["string", "null"] },
          "occurredAt": { "type": "string", "format": "date-time" }
        }
      },
      "ExportManifest": {
        "type": "object",
        "additionalProperties": false,
        "required": ["format", "version", "sha256"],
        "properties": {
          "format": { "type": "string", "enum": ["JSON"] },
          "version": { "type": "string", "example": "1.0" },
          "sha256": { "type": "string", "pattern": "^[a-f0-9]{64}$" }
        }
      },
      "WebhookEvent": {
        "type": "object",
        "additionalProperties": false,
        "required": ["id", "type", "createdAt", "data"],
        "properties": {
          "id": { "type": "string", "example": "evt_01J8DV1048" },
          "type": { "type": "string", "enum": ["compliance_session.updated", "compliance_session.completed", "compliance_session.review_required", "evidence_package.ready"] },
          "createdAt": { "type": "string", "format": "date-time" },
          "data": {
            "type": "object",
            "additionalProperties": false,
            "required": ["complianceSessionId", "status"],
            "properties": {
              "complianceSessionId": { "type": "string" },
              "status": { "$ref": "#/components/schemas/ComplianceSessionStatus" }
            }
          }
        }
      },
      "WebhookVerificationResult": {
        "type": "object",
        "additionalProperties": false,
        "required": ["valid", "eventId"],
        "properties": {
          "valid": { "type": "boolean" },
          "eventId": { "type": "string" }
        }
      },
      "Error": {
        "type": "object",
        "additionalProperties": false,
        "required": ["error"],
        "properties": {
          "error": {
            "type": "object",
            "additionalProperties": false,
            "required": ["code", "message", "requestId"],
            "properties": {
              "code": { "type": "string", "example": "INVALID_REQUEST" },
              "message": { "type": "string", "example": "The request could not be processed." },
              "requestId": { "type": "string", "example": "req_01J8DV1048" },
              "fieldErrors": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": ["field", "message"],
                  "properties": {
                    "field": { "type": "string" },
                    "message": { "type": "string" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Malformed request",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "Unauthorized": {
        "description": "Missing or invalid credentials or signature",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "NotFound": {
        "description": "Resource not found",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "Conflict": {
        "description": "State or idempotency conflict",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "UnprocessableEntity": {
        "description": "Validation failed",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "RateLimited": {
        "description": "Request rate exceeded",
        "headers": {
          "Retry-After": {
            "description": "Seconds until the request may be retried",
            "schema": { "type": "integer", "minimum": 1 }
          }
        },
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      }
    }
  }
}
