{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://developers.dentolize.com/schemas/plugin-manifest-v1.json",
  "title": "Dentolize plugin manifest v1",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "manifestVersion",
    "plugin",
    "requestedScopes",
    "requestedEvents"
  ],
  "properties": {
    "manifestVersion": {
      "const": 1
    },
    "plugin": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "slug",
        "name",
        "description",
        "developerName",
        "supportEmail",
        "privacyPolicyUrl"
      ],
      "properties": {
        "slug": {
          "type": "string",
          "pattern": "^[a-z][a-z0-9-]{2,29}$"
        },
        "name": {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "en"
          ],
          "properties": {
            "en": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            },
            "ar": {
              "type": "string",
              "maxLength": 200
            }
          }
        },
        "description": {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "en"
          ],
          "properties": {
            "en": {
              "type": "string",
              "minLength": 1,
              "maxLength": 5000
            },
            "ar": {
              "type": "string",
              "maxLength": 5000
            }
          }
        },
        "developerName": {
          "type": "string",
          "minLength": 1,
          "maxLength": 200
        },
        "developerUrl": {
          "type": "string",
          "format": "uri",
          "pattern": "^https://",
          "maxLength": 1000
        },
        "supportEmail": {
          "type": "string",
          "format": "email",
          "maxLength": 200
        },
        "privacyPolicyUrl": {
          "type": "string",
          "format": "uri",
          "pattern": "^https://",
          "maxLength": 1000
        },
        "iconUrl": {
          "type": "string",
          "format": "uri",
          "pattern": "^https://",
          "maxLength": 1000
        }
      }
    },
    "requestedScopes": {
      "type": "array",
      "minItems": 1,
      "uniqueItems": true,
      "items": {
        "type": "string",
        "enum": [
          "patients:read",
          "patients:read.pii",
          "patients:write",
          "appointments:read",
          "appointments:write",
          "invoices:read",
          "payments:read",
          "treatments:read",
          "availability:read",
          "webhooks:manage",
          "settings:read",
          "settings:write",
          "clinic:read",
          "practitioners:read",
          "practitioners:read.contact",
          "procedures:read",
          "laborders:read",
          "laborders:write",
          "quotations:read",
          "prescriptions:read",
          "forms:read",
          "forms:write",
          "encounters:read",
          "encounters:write",
          "files:read",
          "files:write",
          "insurance:read",
          "claims:read",
          "onlinepayments:read",
          "paymentlinks:write",
          "payments:write",
          "einvoices:read",
          "leads:read",
          "leads:write",
          "communications:read",
          "communications:send",
          "conversations:read",
          "conversations:write",
          "loyalty:read",
          "loyalty:write",
          "feedback:read",
          "tasks:read",
          "tasks:write",
          "inventory:read",
          "inventory:write",
          "bookkeeping:read",
          "analytics:read",
          "invoices:write"
        ]
      },
      "description": "Scopes the plugin requires; every one must be granted at install time."
    },
    "optionalScopes": {
      "type": "array",
      "uniqueItems": true,
      "items": {
        "type": "string",
        "enum": [
          "patients:read",
          "patients:read.pii",
          "patients:write",
          "appointments:read",
          "appointments:write",
          "invoices:read",
          "payments:read",
          "treatments:read",
          "availability:read",
          "webhooks:manage",
          "settings:read",
          "settings:write",
          "clinic:read",
          "practitioners:read",
          "practitioners:read.contact",
          "procedures:read",
          "laborders:read",
          "laborders:write",
          "quotations:read",
          "prescriptions:read",
          "forms:read",
          "forms:write",
          "encounters:read",
          "encounters:write",
          "files:read",
          "files:write",
          "insurance:read",
          "claims:read",
          "onlinepayments:read",
          "paymentlinks:write",
          "payments:write",
          "einvoices:read",
          "leads:read",
          "leads:write",
          "communications:read",
          "communications:send",
          "conversations:read",
          "conversations:write",
          "loyalty:read",
          "loyalty:write",
          "feedback:read",
          "tasks:read",
          "tasks:write",
          "inventory:read",
          "inventory:write",
          "bookkeeping:read",
          "analytics:read",
          "invoices:write"
        ]
      },
      "description": "Individually consentable scopes; must be disjoint from requestedScopes."
    },
    "requestedEvents": {
      "type": "array",
      "uniqueItems": true,
      "items": {
        "type": "string",
        "enum": [
          "patient.created",
          "patient.updated",
          "patient.deleted",
          "appointment.created",
          "appointment.updated",
          "appointment.cancelled",
          "appointment.checkedin",
          "appointment.completed",
          "appointment.noshow",
          "invoice.created",
          "invoice.updated",
          "invoice.paid",
          "payment.created",
          "payment.refunded",
          "installation.uninstalled",
          "plugin.settings.updated",
          "laborder.created",
          "laborder.updated",
          "laborder.received",
          "laborder.delivered",
          "treatment.status_changed",
          "treatmentstep.completed",
          "quotation.created",
          "quotation.viewed",
          "quotation.signed",
          "prescription.created",
          "encounter.created",
          "measurement.recorded",
          "form.submitted",
          "form.signed",
          "file.created",
          "xray.created",
          "videocall.started",
          "claim.created",
          "claim.status_changed",
          "claim.rejected_amount_updated",
          "treatment.approval_requested",
          "treatment.approved",
          "onlinepayment.succeeded",
          "onlinepayment.failed",
          "onlinepayment.refunded",
          "einvoice.submitted",
          "einvoice.cleared",
          "einvoice.rejected",
          "lead.created",
          "lead.stage_changed",
          "lead.converted",
          "lead.rejected",
          "message.sent",
          "message.failed",
          "conversation.message_received",
          "conversation.assigned",
          "conversation.resolved",
          "points.earned",
          "points.redeemed",
          "feedback.submitted",
          "task.created",
          "task.completed",
          "inventory.low_stock",
          "inventoryorder.created",
          "inventoryorder.received",
          "expense.created",
          "income.created"
        ]
      },
      "description": "Concrete webhook event types (no wildcards) the plugin wants to receive."
    },
    "settingsSchema": {
      "type": "object",
      "description": "Optional pluginSettingsSchema v1 document (see the settings-schema developer doc)."
    },
    "webhooks": {
      "type": "array",
      "maxItems": 10,
      "items": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "name",
          "events"
        ],
        "properties": {
          "name": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "en"
            ],
            "properties": {
              "en": {
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              },
              "ar": {
                "type": "string",
                "maxLength": 200
              }
            }
          },
          "description": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "en"
            ],
            "properties": {
              "en": {
                "type": "string",
                "minLength": 1,
                "maxLength": 1000
              },
              "ar": {
                "type": "string",
                "maxLength": 1000
              }
            }
          },
          "events": {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "string"
            },
            "description": "Event types (or family wildcards like \"appointment.*\") covered by requestedEvents; the clinic fills the endpoint URL at install time."
          }
        }
      }
    },
    "allowedIpRanges": {
      "type": "array",
      "maxItems": 50,
      "items": {
        "type": "string"
      },
      "description": "CIDR ranges (IPv4/IPv6) that pre-fill the token IP allowlist; empty means any source IP."
    }
  }
}