{
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "$id": "https://docs.subscriby.net/connectors/connector.schema.json",
    "title": "Subscriby connector manifest",
    "description": "The connector.json a connector package keeps at its root: what the connector is, what it can do, how it talks and how the directory presents it. Strings a creator reads are English keys the package translates through its own lang files.",
    "type": "object",
    "additionalProperties": false,
    "required": ["key", "name", "version", "sdk", "vendor", "install", "messaging", "pacing", "listing"],
    "properties": {
        "$schema": { "type": "string" },
        "key": {
            "type": "string",
            "pattern": "^[a-z][a-z0-9_-]*$",
            "description": "The connector key: also the table prefix, the config key and the first half of every resource kind."
        },
        "name": { "type": "string", "minLength": 1 },
        "version": { "type": "string", "pattern": "^\\d+\\.\\d+\\.\\d+" },
        "sdk": { "type": "string", "minLength": 1, "description": "The connector-sdk constraint the package was built against, such as ^1.0." },
        "vendor": { "type": "string", "minLength": 1 },
        "install": {
            "type": "object",
            "additionalProperties": false,
            "required": ["mode", "scopes"],
            "properties": {
                "mode": { "enum": ["paste_credential", "oauth", "shared_platform"] },
                "scopes": {
                    "type": "array",
                    "minItems": 1,
                    "uniqueItems": true,
                    "items": { "enum": ["platform", "project"] }
                },
                "fields": { "type": "array", "items": { "$ref": "#/$defs/field" } },
                "settings_fields": { "type": "array", "items": { "$ref": "#/$defs/field" } }
            }
        },
        "resource_kinds": {
            "type": "array",
            "items": {
                "type": "object",
                "additionalProperties": false,
                "required": ["kind", "label", "portal_label", "icon", "grant_mode"],
                "properties": {
                    "kind": { "type": "string", "pattern": "^[a-z][a-z0-9_-]*$" },
                    "label": { "type": "string", "minLength": 1 },
                    "portal_label": { "type": "string", "minLength": 1 },
                    "icon": { "type": "string", "minLength": 1 },
                    "grant_mode": { "enum": ["bearer_link", "membership", "role", "creator_task"] },
                    "supports_early_admission_hold": { "type": "boolean" },
                    "mirrorable": { "type": "boolean", "description": "Whether a standby place of this kind can receive a live copy of every post." }
                }
            }
        },
        "capabilities": {
            "type": "array",
            "uniqueItems": true,
            "items": {
                "enum": [
                    "messaging", "broadcasts", "access_control", "early_admission_hold", "support_relay", "native_payments",
                    "portal_login", "creator_registration", "management_surface", "recovery_probes",
                    "recovery_standby_installations", "recovery_resource_standby", "recovery_mirror", "recovery_identity_relink"
                ]
            }
        },
        "messaging": {
            "type": "object",
            "additionalProperties": false,
            "required": ["max_length", "buttons_per_row", "max_buttons", "callback_data_bytes", "supports_underline", "supports_spoiler", "supports_files"],
            "properties": {
                "max_length": { "type": "integer", "minimum": 1 },
                "buttons_per_row": { "type": "integer", "minimum": 1 },
                "max_buttons": { "type": "integer", "minimum": 1 },
                "callback_data_bytes": { "type": "integer", "minimum": 1 },
                "supports_underline": { "type": "boolean" },
                "supports_spoiler": { "type": "boolean" },
                "supports_files": { "type": "boolean" }
            }
        },
        "pacing": {
            "type": "object",
            "additionalProperties": false,
            "required": ["min_interval_microseconds", "burst", "per_recipient_interval_microseconds"],
            "properties": {
                "min_interval_microseconds": { "type": "integer", "minimum": 0 },
                "burst": { "type": "integer", "minimum": 0 },
                "per_recipient_interval_microseconds": { "type": "integer", "minimum": 0 }
            }
        },
        "management_commands": {
            "type": "array",
            "uniqueItems": true,
            "items": {
                "enum": [
                    "project_create", "project_settings", "project_delete", "installation_connect", "manage_connectors",
                    "resource_link", "resource_manage", "plan_create", "plan_manage", "payment_method_setup", "coupon_create",
                    "access_codes_generate", "broadcast", "support_reply", "support_relay_setup", "creator_tasks",
                    "recovery_status", "recovery_relink", "recovery_standby", "recovery_replace_resource",
                    "account_recovery_email", "set_alert_destination", "donate"
                ]
            }
        },
        "relay_modes": { "type": "array", "items": { "type": "string", "minLength": 1 } },
        "recovery": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
                "probes": { "type": "boolean" },
                "standby_installations": { "type": "boolean" },
                "resource_standby": { "type": "boolean" },
                "mirror": { "type": "boolean" },
                "identity_relink": { "type": "boolean" }
            }
        },
        "listing": {
            "type": "object",
            "additionalProperties": false,
            "required": ["category", "tagline", "overview", "added_at"],
            "properties": {
                "category": { "enum": ["messaging", "community", "payments", "productivity"] },
                "tagline": { "type": "string", "minLength": 1, "maxLength": 80 },
                "overview": { "type": "string", "minLength": 1, "description": "Markdown." },
                "screenshots": { "type": "array", "items": { "type": "string", "format": "uri" } },
                "links": {
                    "type": "object",
                    "additionalProperties": false,
                    "properties": {
                        "documentation": { "$ref": "#/$defs/link" },
                        "support": { "$ref": "#/$defs/link" },
                        "privacy": { "$ref": "#/$defs/link" },
                        "terms": { "$ref": "#/$defs/link" },
                        "homepage": { "$ref": "#/$defs/link" }
                    }
                },
                "added_at": { "type": "string", "format": "date" },
                "changelog_url": { "$ref": "#/$defs/link" },
                "sign_in_required": { "type": "boolean" },
                "marketing": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": ["audience", "place", "places", "installation", "identity"],
                    "description": "The words the marketing site borrows: the home, vertical, comparison and legal pages name a platform only through these.",
                    "properties": {
                        "audience": { "type": "string", "minLength": 1, "description": "Who the connector serves, such as \"Telegram communities\"." },
                        "place": { "type": "string", "minLength": 1, "description": "One gated place, lower case, such as \"channel\"." },
                        "places": { "type": "string", "minLength": 1, "description": "The gated places as a list, such as \"channels, groups and supergroups\"." },
                        "installation": { "type": "string", "minLength": 1, "description": "What a project installs, lower case, such as \"bot\"." },
                        "identity": { "type": "string", "minLength": 1, "description": "A person's account on the platform, such as \"Telegram account\"." },
                        "native_payment": { "type": "string", "minLength": 1, "description": "The platform's own payment method, when it has one, such as \"Telegram Stars\"." }
                    }
                },
                "portal_cta": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": ["label"],
                    "description": "The button the member portal shows to open the connector, when the connector has somewhere to open; the core addresses it through the installation's start link.",
                    "properties": {
                        "label": { "type": "string", "minLength": 1, "description": "The button's text, such as \"Open Telegram Bot\"." },
                        "icon": { "type": "string", "minLength": 1, "description": "An icon slug; the connector's own icon when omitted." }
                    }
                }
            }
        }
    },
    "$defs": {
        "link": {
            "type": "string",
            "pattern": "^(https://[^\\s/]+|mailto:[^\\s@]+@[^\\s]+)",
            "description": "An https URL or a mailto address."
        },
        "field": {
            "type": "object",
            "additionalProperties": false,
            "required": ["name", "type", "label"],
            "properties": {
                "name": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$" },
                "type": { "enum": ["text", "secret", "select", "toggle", "instructions", "link"] },
                "label": { "type": "string", "minLength": 1 },
                "help": { "type": "string" },
                "required": { "type": "boolean" },
                "rules": { "type": "array", "items": { "type": "string", "minLength": 1 }, "description": "Laravel validation rules." },
                "options": { "type": "object", "additionalProperties": { "type": "string" }, "description": "For a select: value to label." },
                "steps": {
                    "type": "array",
                    "items": { "type": "string", "minLength": 1 },
                    "description": "Numbered steps shown with the field, in order. Renderers replace :app with the product name and :button with the label of the button that submits the form."
                },
                "links": {
                    "type": "object",
                    "additionalProperties": { "$ref": "#/$defs/link" },
                    "description": "Text to turn into a link wherever it appears in the label, help or steps: text to target."
                }
            }
        }
    }
}
