install

How a creator connects the connector — the install mode, the scopes, and the field specification the install and settings forms are declared with.

The install block is required. It says how an installation comes to exist, whose it can be, and what a creator types to make one. The forms are data, not views: the dashboard, GET /connectors, the MCP catalogue and the creator apps all render the same fields.

"install": {
    "mode": "paste_credential",
    "scopes": ["project", "platform"],
    "fields": [  ],
    "settings_fields": [  ]
}

mode

Required. One of three ways a creator connects:

ModeWhat happensInstallationLifecycle::begin() returns
paste_credentialThe creator creates something on the platform themselves (a bot, an app, an API key) and pastes its secret into the install form. Telegram's BotFather token is this mode.A complete draft: complete() runs at once with the pasted values.
oauthThe creator signs in on the platform and authorises Subscriby; the platform hands back a token. The connector owns the round trip.A draft with continueUrl, built on the request's returnUrl. The core parks the draft, sends the creator to the URL and, when the platform brings them back, calls complete() with the draft's returned query (code, state); the connector exchanges the code and puts the token in the summary's meta. See the lifecycle port.
shared_platformSubscriby runs one installation for everyone (its own app on the platform) and a project only links to it. Nothing is pasted.A complete draft; the connector's platformInstallation() must answer.

The kit's settings.install_fields rule expects a paste_credential connector to declare at least one input field and at least one secret among them, because there is nothing to paste otherwise.

scopes

Required, one or both of:

  • project: an installation a project owns (the project's bot, the project's server). Most connectors support this.
  • platform: an installation Subscriby itself owns on the platform and every creator shares (the sign-in bot creators talk to, the presence alerts arrive from). A connector that lists it must answer InstallationLifecycle::platformInstallation() with that installation; the core hands it to startLink() for creator handshakes, to RegistersCreators::signupEntry() and to the recovery facets that need the platform's own installation to act.

Telegram declares both: each project has its own bot, and Subscriby's platform bot signs creators in.

fields and settings_fields

Both optional, both a list of fields in display order. fields is the install form a creator fills in to connect; settings_fields is what they may change afterwards, on the installation's Configuration tab. When a connector declares them here it binds no SettingsSchema of its own: the core wires the SDK's ManifestSettingsSchema over the file, which also translates every label through the package's language files. Bind your own SettingsSchema only when the fields depend on the installation (a list of the server's channels, say), and then declare none here.

A field

{
    "name": "token",
    "type": "secret",
    "label": "Bot token",
    "help": "Paste the token @BotFather gave you. Keep it secret: anyone who has it controls the bot.",
    "required": true,
    "rules": ["string", "regex:/^\\d{6,12}:[A-Za-z0-9_-]{30,64}$/"],
    "links": { "@BotFather": "https://t.me/BotFather" }
}
KeyRequiredMeaning
name^[a-z][a-z0-9_]*$, unique within its form. The key the value is stored and submitted under; the connector reads it back from InstallationRequest::$fields or, for a secret, from the CredentialBag.
typeOne of the six types below.
labelShown beside the input, or as the heading of an instructions block. A translation key.
helpOne sentence under the input. A translation key.
requiredWhether the form refuses an empty value. Default false.
rulesLaravel validation rules applied to the value as strings ("string", "min:20", "regex:/…/", "url"). A regex is written as it would be in PHP, with JSON escaping of backslashes.
optionsFor a select only: a map of stored value to label; the labels are translation keys.
stepsNumbered steps shown with the field, in order. Two placeholders are replaced by every renderer: :app with the product name and :button with the label of the form's submit button.
linksText to turn into a link wherever it appears in the label, help or steps: "@BotFather": "https://t.me/BotFather". https:// and mailto: only.

The six types

TypeInputWhere the value goes
textA single-line text box.InstallationRequest::$fields[name]; stored on the installation's settings when it is a settings field.
secretA masked text box.The installation's CredentialBag, encrypted at rest in the core's table, never shown again after saving.
selectA drop-down over options.The chosen key, as text.
toggleA switch.A boolean, as text.
instructionsNo input: a walkthrough.Nothing. The label heads it, steps and help explain, links turn names into links.
linkNo input: a button.Nothing. The label is the button text and the field's value is where it goes, which only a PHP-bound SettingsSchema can fill per installation (a link to the installation's own page on the platform). A manifest-declared link has no target.

How the values flow

  1. The creator submits the install form. The core validates every field's rules and refuses the form with the messages a Laravel form would show.
  2. The core puts every submitted install field, secret or not, into the CredentialBag, builds an InstallationRequest (scope, the acting creator, the project, the same fields as an array, and the existing installation when the creator is reconnecting) and calls InstallationLifecycle::begin().
  3. For a complete draft the core calls complete() with that bag, then stores it encrypted on the installation row it records from the summary, merged with whatever the connector put in the summary's meta (a webhook signing secret it minted). The connector never sees how the bag is kept and keeps no secret of its own; every port receives the merged bag, and Core\Installations::credentials() reads it back before any port is called.
  4. Settings fields are read through SettingsSchema::settingsFields($installation) with their current values filled in, and written through PATCH …/installation/settings or the Configuration tab.

The Telegram block

"install": {
    "mode": "paste_credential",
    "scopes": ["project", "platform"],
    "fields": [
        {
            "name": "instructions",
            "type": "instructions",
            "label": "Create a bot with @BotFather, then paste its token here.",
            "steps": [
                "Open the Telegram app and search for @BotFather.",
                "Start a chat with @BotFather and send the command /newbot.",
                "Follow the instructions to create your bot and get the token.",
                "Copy the token by tapping on it and paste it in the input below.",
                "Click on \":button\" to connect your bot to :app."
            ],
            "help": "You can use the @BotFather bot to customize your bot such as adding a bio description, adding a display picture or even adding the startup greeting message. Bot activation may take several seconds.",
            "links": { "@BotFather": "https://t.me/BotFather" }
        },
        {
            "name": "token",
            "type": "secret",
            "label": "Bot token",
            "help": "Paste the token @BotFather gave you. Keep it secret: anyone who has it controls the bot.",
            "required": true,
            "rules": ["string", "regex:/^\\d{6,12}:[A-Za-z0-9_-]{30,64}$/"]
        }
    ],
    "settings_fields": []
}

The Connect Bot dialog creators see is this block rendered: the numbered BotFather steps, the @BotFather link, the masked token box and the regex that refuses anything that is not a bot token. The walkthrough video beside it is the connector's install slot, which dresses the form up on the web without replacing it.

What the kit checks

settings.install_fields: every entry is a Field, names are unique, every field has a label, and a paste_credential connector has an input and a secret. settings.settings_fields: the same shape rules for settingsFields(null). The loader itself refuses a name outside its pattern, a type outside the six, a select without options, an unknown key inside a field, and a link that is not https:// or mailto:.

How is this guide?

On this page

Subscriby is a product designed by you — for you.

No boardroom full of executives deciding what we ships next. Our roadmap always shaped by you with your feedback.

Share feedback or a request