Documentation

From the first block to a connected module

A concise guide to the real Buywell product: workflow usage first, then the module developer contract.
User guide

Build and run a workflow

Core concepts

A workflow is a versioned graph of actions and conditions. A block performs one step. An adapter calls a concrete external API from Buywell. A module connects Buywell to a platform and supplies its own events and blocks.

  • A draft can be edited and tested.
  • A published revision is immutable.
  • A connection links a published workflow to an exact module event version.

Your first workflow

01DraftBuild the graph
02TestFix diagnostics
03PublishPin revision N
04ConnectSelect an event
05RunInspect the log

A new workflow starts with the Start block. Add actions and conditions from the left panel, connect them, and lead every path to a successful or failed result.

Workflow inputs are declared separately. A field may use a manual value, a workflow input, or an earlier step result.

  • Use a clear workflow name.
  • Configure every required block field.
  • Lead every branch to a terminal block.

Validate and publish

Validation reports structural and compatibility problems. A test run uses your sample values and shows the ordered result of every step.

Publishing freezes an exact revision. Later changes remain in a new draft; selecting an older published revision is the rollback action.

  • Resolve issues in the single diagnostics area.
  • Test the successful and alternative branches.
  • Publish only after a test.

Events and connections

After publishing, choose an event from an installed module. Buywell exposes only trigger conditions and data sources declared by that module.

Compatibility is checked before enabling: package version, event, blocks, and the connected Edge driver must match.

  • Trigger conditions filter events.
  • Data fields populate workflow inputs.
  • A connection is enabled only after successful validation.

Run history

History shows the final result, ordered steps, duration, and the point of failure. Temporary errors follow the declared retry policy; permanent failures finish the run and remain visible.

  • Inspect the stopped step input and result.
  • Confirm the required module version is connected.
  • Never put passwords or access keys into ordinary workflow fields.
Developer guide

Build a module for Buywell

Module package

ONE IMMUTABLE ARCHIVEmodule-name.buywell-module.zipVersion + contents = package identity
manifest.jsoncontract and relative paths
edge/driver.pyEdge driver
guides/install.ru.mdrequired guide
guides/install.en.mdoptional translation
assets/icon.pngoptional local asset
Buywell validates filesBuywell calculates the digest× No driver URL× No hand-written hashes

A module is distributed as one ZIP archive using the .buywell-module.zip suffix. It contains manifest.json, one Edge driver, the required Russian Markdown installation guide, optional localized readme and changelog files, and optional local assets.

  • Manifest paths are relative to the archive.
  • Driver URLs and hand-written hashes are not required.
  • A published package version is immutable.

manifest.json specification

The manifest is the package's strict versioned contract. It declares module identity, packaged files, events, exposed data, nodes, and implementations of neutral actions.

In an Edge package, the module supplies the Russian and English label for every configuration field through configuration_field; Edge does not guess field meaning from its name.

Copy the minimal valid example, then check every field against the reference. Unknown fields are rejected, while related paths, types, namespaces, and versions are validated together.

MANIFEST REFERENCE

Everything manifest.json may declare

Every example on this page is checked by the same contract used when a package is installed. Start with the compact example and use the field reference for events, data sources, nodes, and compatibility rules.

For Buywell Edge, the Python SDK generates Manifest v2, schemas, file inventory, digest, and signature from typed declarations. A signed adapter-driver supplies its managed adapter and operation fields directly when Edge connects; Buywell verifies the signature before showing its user-scoped blocks. Existing modules can preserve the entire v1 manifest as their compatibility contract.

VALID COPYABLE EXAMPLEJSON
{
  "schemaVersion": 1,
  "protocolVersion": "1.0.0",
  "module": {
    "id": "example.delivery",
    "version": "1.0.0",
    "displayName": "Example Delivery",
    "description": "A minimal module package example.",
    "publisher": "Example developer",
    "supportedPlatforms": [
      "Example Platform"
    ]
  },
  "nodes": [
    {
      "type": "example.delivery/send-message",
      "version": "1.0.0",
      "kind": "action",
      "displayName": "Send message",
      "localization": {
        "ru": {
          "displayName": "Отправить сообщение"
        },
        "en": {
          "displayName": "Send message"
        }
      },
      "inputSchema": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string"
          }
        },
        "required": [
          "message"
        ],
        "additionalProperties": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {},
        "required": [],
        "additionalProperties": false
      },
      "configSchema": {
        "type": "object",
        "properties": {},
        "required": [],
        "additionalProperties": false
      },
      "requiredEventContext": [
        {
          "eventType": "commerce.purchase.created",
          "eventVersion": "1.0.0",
          "source": "scope",
          "path": "conversationId"
        }
      ],
      "ui": {
        "category": "Messages",
        "icon": "message"
      }
    }
  ],
  "events": [
    {
      "type": "commerce.purchase.created",
      "version": "1.0.0",
      "displayName": "Purchase received",
      "localization": {
        "ru": {
          "displayName": "Получена покупка"
        },
        "en": {
          "displayName": "Purchase received"
        }
      },
      "payloadSchema": {
        "type": "object",
        "properties": {
          "purchaseId": {
            "type": "string"
          },
          "recipient": {
            "type": "string"
          }
        },
        "required": [
          "purchaseId",
          "recipient"
        ],
        "additionalProperties": false
      },
      "scopeSchema": {
        "type": "object",
        "properties": {
          "conversationId": {
            "type": "string"
          }
        },
        "required": [
          "conversationId"
        ],
        "additionalProperties": false
      },
      "selectors": [],
      "bindingFields": [
        {
          "id": "recipient",
          "source": "payload",
          "path": "recipient",
          "valueSchema": {
            "type": "string"
          },
          "displayName": "Recipient",
          "localization": {
            "ru": {
              "displayName": "Получатель"
            },
            "en": {
              "displayName": "Recipient"
            }
          },
          "recommended": true,
          "availability": "always"
        }
      ],
      "identityFields": [
        "purchaseId"
      ],
      "ui": {
        "category": "Sales",
        "icon": "cart"
      }
    }
  ],
  "abstractions": [
    {
      "abstractionId": "messaging.send-in-context",
      "abstractionVersion": "1.0.0",
      "nodeType": "example.delivery/send-message",
      "nodeVersion": "1.0.0"
    }
  ],
  "package": {
    "branding": {
      "icon": "assets/icon.png"
    },
    "artifact": {
      "path": "edge/driver.py",
      "filename": "driver.py"
    },
    "guides": {
      "installation": {
        "ru": "guides/install.ru.md",
        "en": "guides/install.en.md"
      },
      "readme": {
        "ru": "guides/README.ru.md",
        "en": "guides/README.en.md"
      },
      "changelog": {
        "ru": "guides/CHANGELOG.ru.md",
        "en": "guides/CHANGELOG.en.md"
      }
    },
    "compatibility": {
      "environments": [
        "Example Runtime 1.x"
      ]
    },
    "release": {
      "critical": false
    }
  }
}
MANIFEST FIELD REFERENCE

What every field controls and which values it accepts

Root manifest7 fields

Package identity, contents, and public capabilities.

schemaVersion1required

May be omitted; parsing and the canonical manifest set it to 1. · default: 1

protocolVersion"1.0.0"required

May be omitted; parsing and the canonical manifest set it to 1.0.0. · default: "1.0.0"

moduleobjectrequired

Identity, publisher, and supported platforms. · unknown fields are rejected

nodesarrayrequired

Blocks owned by this package. · maximum items: 100

eventsarray

Versioned module events. · maximum items: 100

abstractionsarray

Implementations of platform-neutral contracts. · maximum items: 100

packageobject

Archive files, compatibility, and release metadata. · unknown fields are rejected

module10 fields

Purpose, accepted values, and validation limits for this part of the manifest.

module.idstringrequired

Lowercase dot/dash-separated segments, such as example.delivery. · pattern: ^[a-z0-9]+(?:[.-][a-z0-9]+)+$

module.versionstringrequired

x.y.z with an optional prerelease suffix. · pattern: ^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$

module.displayNamestringrequired

Base name; RU/EN localization may replace it. · minimum length: 1 · maximum length: 120

module.descriptionstring

Optional short user-facing description. · maximum length: 2000

module.publisherstringrequired

Package publisher name. · minimum length: 1 · maximum length: 160

module.supportedPlatformsarrayrequired

Human-readable supported platform names. · minimum items: 1 · maximum items: 50

module.documentationobject

Optional HTTP(S) homepageUrl, supportUrl, and sourceUrl. · unknown fields are rejected

module.documentation.homepageUrlstring

Links to the module or publisher homepage. · maximum length: 2048 · format: uri

module.documentation.supportUrlstring

Tells users where to get support for the module. · maximum length: 2048 · format: uri

module.documentation.sourceUrlstring

Links to the module source when the publisher makes it available. · maximum length: 2048 · format: uri

nodes[]31 fields

Purpose, accepted values, and validation limits for this part of the manifest.

nodes[].typestringrequired

Must begin with the exact module.id/ namespace. · pattern: ^[a-z0-9]+(?:[.-][a-z0-9]+)*\/[a-z][a-z0-9.-]*$

nodes[].versionstringrequired

Node contract version. · pattern: ^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$

nodes[].kind"action" | "condition"required

condition requires branches; action forbids branches.

nodes[].displayNamestringrequired

displayName is required; description and RU/EN localization are optional. · minimum length: 1 · maximum length: 120

nodes[].descriptionstring

displayName is required; description and RU/EN localization are optional. · maximum length: 2000

nodes[].localizationobject

displayName is required; description and RU/EN localization are optional. · unknown fields are rejected

nodes[].localization.ruobject

Required non-empty UTF-8 Markdown guide. · unknown fields are rejected

nodes[].localization.ru.displayNamestring

displayName is required; description and RU/EN localization are optional. · minimum length: 1 · maximum length: 120

nodes[].localization.ru.descriptionstring

displayName is required; description and RU/EN localization are optional. · maximum length: 2000

nodes[].localization.enobject

Optional translation; RU is the fallback. · unknown fields are rejected

nodes[].localization.en.displayNamestring

displayName is required; description and RU/EN localization are optional. · minimum length: 1 · maximum length: 120

nodes[].localization.en.descriptionstring

displayName is required; description and RU/EN localization are optional. · maximum length: 2000

nodes[].inputSchemavaluerequired

Action or condition inputs.

nodes[].outputSchemavaluerequired

Default to closed empty objects. · default: {"type":"object","properties":{},"required":[],"additionalProperties":false}

nodes[].configSchemavaluerequired

Default to closed empty objects. · default: {"type":"object","properties":{},"required":[],"additionalProperties":false}

nodes[].requiredEventContextarray

Existing eventType@version and payload/scope paths. · maximum items: 100

nodes[].requiredEventContext[].eventTypestringrequired

Selects the event whose context the node needs to run. · pattern: ^[a-z0-9]+(?:[.-][a-z0-9]+)+$

nodes[].requiredEventContext[].eventVersionstringrequired

Pins the exact required event version. · pattern: ^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$

nodes[].requiredEventContext[].source"payload" | "scope"required

The path must exist in the selected schema.

nodes[].requiredEventContext[].pathstringrequired

The single Edge driver stored in the archive. · minimum length: 1 · maximum length: 512

nodes[].branchesarray

condition only; every branch contains id and label. · minimum items: 2 · maximum items: 20

nodes[].branches[].idstringrequired

Lowercase dot/dash-separated segments, such as example.delivery. · pattern: ^[A-Za-z0-9][A-Za-z0-9_.:-]{0,127}$

nodes[].branches[].labelstringrequired

Names a condition output as users see it in the editor. · minimum length: 1 · maximum length: 120

nodes[].retryPolicyobject

maxAttempts, initialBackoffMs, and maxBackoffMs within contract limits. · unknown fields are rejected

nodes[].retryPolicy.maxAttemptsintegerrequired

Limits the total number of node execution attempts. · ≥ 1 · ≤ 10

nodes[].retryPolicy.initialBackoffMsintegerrequired

Sets the delay before the first node retry. · ≥ 0 · ≤ 300000

nodes[].retryPolicy.maxBackoffMsintegerrequired

Caps the delay between node retries. · ≥ 0 · ≤ 3600000

nodes[].uiobjectrequired

category, #RRGGBB color, and icon. · default: {"category":"Other"} · unknown fields are rejected

nodes[].ui.categorystringrequired

Places the node in a section of the block library. · default: "Other" · minimum length: 1 · maximum length: 80

nodes[].ui.colorstring

Sets the node accent color in the editor. · pattern: ^#[0-9A-Fa-f]{6}$

nodes[].ui.iconstring

PNG, JPEG, or WebP with content matching its extension. · minimum length: 1 · maximum length: 80

events[]106 fields

Purpose, accepted values, and validation limits for this part of the manifest.

events[].typestringrequired

Versioned event identity. · pattern: ^[a-z0-9]+(?:[.-][a-z0-9]+)+$

events[].versionstringrequired

Versioned event identity. · pattern: ^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$

events[].displayNamestringrequired

displayName is required; description is optional and limited to 2,000 characters. · minimum length: 1 · maximum length: 120

events[].descriptionstring

displayName is required; description is optional and limited to 2,000 characters. · maximum length: 2000

events[].localizationobject

displayName is required; description and RU/EN localization are optional. · unknown fields are rejected

events[].localization.ruobject

Required non-empty UTF-8 Markdown guide. · unknown fields are rejected

events[].localization.ru.displayNamestring

displayName is required; description is optional and limited to 2,000 characters. · minimum length: 1 · maximum length: 120

events[].localization.ru.descriptionstring

displayName is required; description is optional and limited to 2,000 characters. · maximum length: 2000

events[].localization.enobject

Optional translation; RU is the fallback. · unknown fields are rejected

events[].localization.en.displayNamestring

displayName is required; description is optional and limited to 2,000 characters. · minimum length: 1 · maximum length: 120

events[].localization.en.descriptionstring

displayName is required; description is optional and limited to 2,000 characters. · maximum length: 2000

events[].payloadSchemavaluerequired

Event body; every identityFields path must exist and be required.

events[].scopeSchemavaluerequired

Execution context. Defaults to a closed empty object. · default: {"type":"object","properties":{},"required":[],"additionalProperties":false}

events[].selectorsarrayrequired

Launch filter fields; defaults to []. · default: [] · maximum items: 100

events[].selectors[].idstringrequired

Lowercase dot/dash-separated segments, such as example.delivery. · pattern: ^[A-Za-z0-9][A-Za-z0-9_.:-]{0,127}$

events[].selectors[].displayNamestringrequired

displayName is required; description is optional and limited to 2,000 characters. · minimum length: 1 · maximum length: 120

events[].selectors[].source"payload" | "scope"required

The path must exist in the selected schema.

events[].selectors[].pathstringrequired

The single Edge driver stored in the archive. · minimum length: 1 · maximum length: 512

events[].selectors[].operatorsarrayrequired

exists, equals, not-equals, in, contains, starts-with, ends-with, or matches. · minimum items: 1 · maximum items: 8

events[].selectors[].localizationobject

displayName is required; description and RU/EN localization are optional. · unknown fields are rejected

events[].selectors[].localization.ruobject

Required non-empty UTF-8 Markdown guide. · unknown fields are rejected

events[].selectors[].localization.ru.displayNamestring

displayName is required; description is optional and limited to 2,000 characters. · minimum length: 1 · maximum length: 120

events[].selectors[].localization.ru.descriptionstring

displayName is required; description is optional and limited to 2,000 characters. · maximum length: 2000

events[].selectors[].localization.enobject

Optional translation; RU is the fallback. · unknown fields are rejected

events[].selectors[].localization.en.displayNamestring

displayName is required; description is optional and limited to 2,000 characters. · minimum length: 1 · maximum length: 120

events[].selectors[].localization.en.descriptionstring

displayName is required; description is optional and limited to 2,000 characters. · maximum length: 2000

events[].bindingFieldsarray

Typed payload/scope values exposed as input sources. · maximum items: 200

events[].bindingFields[].idstringrequired

Lowercase dot/dash-separated segments, such as example.delivery. · pattern: ^[A-Za-z0-9][A-Za-z0-9_.:-]{0,127}$

events[].bindingFields[].source"payload" | "scope"required

The path must exist in the selected schema.

events[].bindingFields[].pathstringrequired

The single Edge driver stored in the archive. · minimum length: 1 · maximum length: 512

events[].bindingFields[].valueSchemavaluerequired

Type must match the declared path type.

events[].bindingFields[].displayNamestringrequired

displayName is required; description is optional and limited to 2,000 characters. · minimum length: 1 · maximum length: 120

events[].bindingFields[].descriptionstring

displayName is required; description is optional and limited to 2,000 characters. · maximum length: 2000

events[].bindingFields[].localizationobject

displayName is required; description and RU/EN localization are optional. · unknown fields are rejected

events[].bindingFields[].localization.ruobject

Required non-empty UTF-8 Markdown guide. · unknown fields are rejected

events[].bindingFields[].localization.ru.displayNamestring

displayName is required; description is optional and limited to 2,000 characters. · minimum length: 1 · maximum length: 120

events[].bindingFields[].localization.ru.descriptionstring

displayName is required; description is optional and limited to 2,000 characters. · maximum length: 2000

events[].bindingFields[].localization.enobject

Optional translation; RU is the fallback. · unknown fields are rejected

events[].bindingFields[].localization.en.displayNamestring

displayName is required; description is optional and limited to 2,000 characters. · minimum length: 1 · maximum length: 120

events[].bindingFields[].localization.en.descriptionstring

displayName is required; description is optional and limited to 2,000 characters. · maximum length: 2000

events[].bindingFields[].categorystring

Groups the value in the data-source picker. · minimum length: 1 · maximum length: 80

events[].bindingFields[].orderinteger

Orders the value among other event data sources. · ≥ 0 · ≤ 10000

events[].bindingFields[].recommendedboolean

UI hints and data-handling metadata.

events[].bindingFields[].nullableboolean

UI hints and data-handling metadata.

events[].bindingFields[].availability"always" | "when-present"required

Defaults to always. · default: "always"

events[].bindingFields[].sensitiveboolean

UI hints and data-handling metadata.

events[].bindingFields[].keyedobject

For an object path, declares guardPath and guardParameter for a parameterized string value. · unknown fields are rejected

events[].bindingFields[].keyed.guardPathstringrequired

Checks context before reading a parameterized key from an object field. · minimum length: 1 · maximum length: 512

events[].bindingFields[].keyed.guardParameterstringrequired

Names the binding parameter whose value must match guardPath. · pattern: ^[A-Za-z0-9][A-Za-z0-9_.:-]{0,127}$

events[].bindingCatalogsarray

Declares category, product, or other scope catalogs from which users can select event context. · maximum items: 20

events[].bindingCatalogs[].idstringrequired

Lowercase dot/dash-separated segments, such as example.delivery. · pattern: ^[a-z0-9]+(?:[.-][a-z0-9]+)+$

events[].bindingCatalogs[].versionstringrequired

Versioned event identity. · pattern: ^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$

events[].bindingCatalogs[].displayNamestringrequired

displayName is required; description is optional and limited to 2,000 characters. · minimum length: 1 · maximum length: 120

events[].bindingCatalogs[].localizationobject

displayName is required; description and RU/EN localization are optional. · unknown fields are rejected

events[].bindingCatalogs[].localization.ruobject

Required non-empty UTF-8 Markdown guide. · unknown fields are rejected

events[].bindingCatalogs[].localization.ru.displayNamestring

displayName is required; description is optional and limited to 2,000 characters. · minimum length: 1 · maximum length: 120

events[].bindingCatalogs[].localization.ru.descriptionstring

displayName is required; description is optional and limited to 2,000 characters. · maximum length: 2000

events[].bindingCatalogs[].localization.enobject

Optional translation; RU is the fallback. · unknown fields are rejected

events[].bindingCatalogs[].localization.en.displayNamestring

displayName is required; description is optional and limited to 2,000 characters. · minimum length: 1 · maximum length: 120

events[].bindingCatalogs[].localization.en.descriptionstring

displayName is required; description is optional and limited to 2,000 characters. · maximum length: 2000

events[].bindingCatalogs[].scopeobjectrequired

Defines the selector and parameter that bind a catalog choice to event context. · unknown fields are rejected

events[].bindingCatalogs[].scope.displayNamestringrequired

displayName is required; description is optional and limited to 2,000 characters. · minimum length: 1 · maximum length: 120

events[].bindingCatalogs[].scope.localizationobject

displayName is required; description and RU/EN localization are optional. · unknown fields are rejected

events[].bindingCatalogs[].scope.localization.ruobject

Required non-empty UTF-8 Markdown guide. · unknown fields are rejected

events[].bindingCatalogs[].scope.localization.ru.displayNamestring

displayName is required; description is optional and limited to 2,000 characters. · minimum length: 1 · maximum length: 120

events[].bindingCatalogs[].scope.localization.ru.descriptionstring

displayName is required; description is optional and limited to 2,000 characters. · maximum length: 2000

events[].bindingCatalogs[].scope.localization.enobject

Optional translation; RU is the fallback. · unknown fields are rejected

events[].bindingCatalogs[].scope.localization.en.displayNamestring

displayName is required; description is optional and limited to 2,000 characters. · minimum length: 1 · maximum length: 120

events[].bindingCatalogs[].scope.localization.en.descriptionstring

displayName is required; description is optional and limited to 2,000 characters. · maximum length: 2000

events[].bindingCatalogs[].scope.selectorIdstringrequired

References an event selector with the equals operator that constrains the selected scope. · pattern: ^[A-Za-z0-9][A-Za-z0-9_.:-]{0,127}$

events[].bindingCatalogs[].scope.guardParameterstringrequired

Names the parameter that passes the selected catalog value into keyed fields. · pattern: ^[A-Za-z0-9][A-Za-z0-9_.:-]{0,127}$

events[].bindingCatalogs[].valueFieldIdstringrequired

References the keyed field containing a catalog item's internal value. · pattern: ^[A-Za-z0-9][A-Za-z0-9_.:-]{0,127}$

events[].bindingCatalogs[].choiceFieldIdstringrequired

References the keyed field containing the catalog choice shown to users. · pattern: ^[A-Za-z0-9][A-Za-z0-9_.:-]{0,127}$

events[].identityFieldsarrayrequired

Payload paths that form event identity. · minimum items: 1 · maximum items: 20

events[].inputResolversarray

Versioned immediate/deferred data sources. · maximum items: 50

events[].inputResolvers[].idstringrequired

Lowercase dot/dash-separated segments, such as example.delivery. · pattern: ^[a-z0-9]+(?:[.-][a-z0-9]+)+$

events[].inputResolvers[].versionstringrequired

Versioned event identity. · pattern: ^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$

events[].inputResolvers[].abstractionIdstring

Optional exact Buywell abstraction; both fields are declared together. · pattern: ^[a-z0-9]+(?:[.-][a-z0-9]+)+$

events[].inputResolvers[].abstractionVersionstring

Optional exact Buywell abstraction; both fields are declared together. · pattern: ^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$

events[].inputResolvers[].displayNamestringrequired

displayName is required; description is optional and limited to 2,000 characters. · minimum length: 1 · maximum length: 120

events[].inputResolvers[].descriptionstring

displayName is required; description is optional and limited to 2,000 characters. · maximum length: 2000

events[].inputResolvers[].outputSchemavaluerequired

Exact returned value type.

events[].inputResolvers[].parameterSchemavalue

For an abstraction, it must exactly match its versioned contract.

events[].inputResolvers[].mode"immediate" | "deferred"required

Production executes deferred; immediate is not activated as a remote job.

events[].inputResolvers[].localizationobject

displayName is required; description and RU/EN localization are optional. · unknown fields are rejected

events[].inputResolvers[].localization.ruobject

Required non-empty UTF-8 Markdown guide. · unknown fields are rejected

events[].inputResolvers[].localization.ru.displayNamestring

displayName is required; description is optional and limited to 2,000 characters. · minimum length: 1 · maximum length: 120

events[].inputResolvers[].localization.ru.descriptionstring

displayName is required; description is optional and limited to 2,000 characters. · maximum length: 2000

events[].inputResolvers[].localization.enobject

Optional translation; RU is the fallback. · unknown fields are rejected

events[].inputResolvers[].localization.en.displayNamestring

displayName is required; description is optional and limited to 2,000 characters. · minimum length: 1 · maximum length: 120

events[].inputResolvers[].localization.en.descriptionstring

displayName is required; description is optional and limited to 2,000 characters. · maximum length: 2000

events[].inputResolvers[].requiredContextarray

Every payload/scope path exists and is guaranteed required. · maximum items: 50

events[].inputResolvers[].requiredContext[].source"payload" | "scope"required

The path must exist in the selected schema.

events[].inputResolvers[].requiredContext[].pathstringrequired

The single Edge driver stored in the archive. · minimum length: 1 · maximum length: 512

events[].inputResolvers[].timeoutMsinteger

Optional wait limit. · ≥ 100 · ≤ 300000

events[].inputResolvers[].retryobject

maxAttempts 1…10 and initialBackoffMs 0…300000. · unknown fields are rejected

events[].inputResolvers[].retry.maxAttemptsintegerrequired

Limits attempts to obtain deferred data. · ≥ 1 · ≤ 10

events[].inputResolvers[].retry.initialBackoffMsintegerrequired

Sets the delay before retrying deferred data resolution. · ≥ 0 · ≤ 300000

events[].inputResolvers[].sensitiveboolean

UI hints and data-handling metadata.

events[].inputResolvers[].uiobject

category defaults to Other; icon is optional. · unknown fields are rejected

events[].inputResolvers[].ui.categorystring

Groups the data resolver in the editor. · minimum length: 1 · maximum length: 80

events[].inputResolvers[].ui.orderinteger

Orders the data resolver in the editor. · ≥ 0 · ≤ 10000

events[].inputResolvers[].ui.recommendedboolean

UI hints and data-handling metadata.

events[].uiobjectrequired

category defaults to Other; icon is optional. · default: {"category":"Other"} · unknown fields are rejected

events[].ui.categorystringrequired

Places the event in a section of the trigger picker. · default: "Other" · minimum length: 1 · maximum length: 80

events[].ui.iconstring

PNG, JPEG, or WebP with content matching its extension. · minimum length: 1 · maximum length: 80

abstractions[]4 fields

Purpose, accepted values, and validation limits for this part of the manifest.

abstractions[].abstractionIdstringrequired

Selects the stable neutral-action contract implemented by the module. · pattern: ^[a-z0-9]+(?:[.-][a-z0-9]+)+$

abstractions[].abstractionVersionstringrequired

Pins the exact version of that neutral-action contract. · pattern: ^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$

abstractions[].nodeTypestringrequired

References an existing node owned by this module.id. · pattern: ^[a-z0-9]+(?:[.-][a-z0-9]+)*\/[a-z][a-z0-9.-]*$

abstractions[].nodeVersionstringrequired

References an existing node owned by this module.id. · pattern: ^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$

package25 fields

Purpose, accepted values, and validation limits for this part of the manifest.

package.brandingobject

Describes the module visuals included in the archive. · unknown fields are rejected

package.branding.iconstringrequired

PNG, JPEG, or WebP with content matching its extension. · minimum length: 1 · maximum length: 240

package.artifactobjectrequired

Points to the executable Edge driver for this module version. · unknown fields are rejected

package.artifact.pathstringrequired

The single Edge driver stored in the archive. · minimum length: 1 · maximum length: 240

package.artifact.filenamestring

Download filename; never a URL. · minimum length: 1 · maximum length: 180

package.guidesobjectrequired

Collects installation and maintenance guidance for the module. · unknown fields are rejected

package.guides.installationobjectrequired

Contains the required Russian installation guide and optional English translation. · unknown fields are rejected

package.guides.installation.rustringrequired

Required non-empty UTF-8 Markdown guide. · minimum length: 1 · maximum length: 240

package.guides.installation.enstring

Optional translation; RU is the fallback. · minimum length: 1 · maximum length: 240

package.guides.readmeobject

Contains the localized module overview shown in About. · unknown fields are rejected

package.guides.readme.rustringrequired

Points to the required Russian About Markdown when a readme is declared. · minimum length: 1 · maximum length: 240

package.guides.readme.enstring

Points to the optional English readme; the Russian file is the fallback. · minimum length: 1 · maximum length: 240

package.guides.changelogobject

Contains the localized, version-by-version user changelog. · unknown fields are rejected

package.guides.changelog.rustringrequired

Points to the required Russian changelog Markdown when a changelog is declared. · minimum length: 1 · maximum length: 240

package.guides.changelog.enstring

Points to the optional English changelog; the Russian file is the fallback. · minimum length: 1 · maximum length: 240

package.guides.updateUrlstring

Links to module update instructions. · maximum length: 2048 · format: uri

package.guides.rollbackUrlstring

Links to rollback instructions. · maximum length: 2048 · format: uri

package.guides.troubleshootingUrlstring

Links to troubleshooting guidance. · maximum length: 2048 · format: uri

package.guides.removalUrlstring

Links to safe module removal instructions. · maximum length: 2048 · format: uri

package.compatibilityobjectrequired

Declares the service versions and environments where the package can run. · unknown fields are rejected

package.compatibility.minimumBuywellVersionstring

Optional minimum compatible service version. · pattern: ^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$

package.compatibility.environmentsarrayrequired

Supported Buywell Edge environments. · minimum items: 1 · maximum items: 30

package.releaseobjectrequired

Carries release importance and changelog information. · default: {"critical":false} · unknown fields are rejected

package.release.criticalbooleanrequired

Defaults to false. · default: false

package.release.changelogUrlstring

Optional release changelog. · maximum length: 2048 · format: uri

AVAILABLE ABSTRACTIONS

Neutral actions a module may implement

An abstraction lets a workflow request a familiar action without depending on one platform. A compatible module binds that action to its own node.

messaging.send-in-context@1.0.0action

Send message

Send a message in the current conversation.

Workflow block
abstract/send-in-context@1.0.0
Inputs
message*
Known implementations
example.delivery/send-message@1.0.0
Extended neutral manifest1 events · 2 nodes

This example demonstrates events, filters, workflow data, resolvers, actions, and conditions executed through Buywell Edge.

EXTENDED EXAMPLE / manifest.jsonJSON
{
  "schemaVersion": 1,
  "protocolVersion": "1.0.0",
  "module": {
    "id": "example.delivery",
    "version": "1.1.0",
    "displayName": "Example Delivery",
    "description": "A complete production-compatible manifest example.",
    "publisher": "Example developer",
    "supportedPlatforms": [
      "Example Platform"
    ]
  },
  "nodes": [
    {
      "type": "example.delivery/send-message",
      "version": "1.0.0",
      "kind": "action",
      "displayName": "Send message",
      "localization": {
        "ru": {
          "displayName": "Отправить сообщение"
        },
        "en": {
          "displayName": "Send message"
        }
      },
      "inputSchema": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string"
          }
        },
        "required": [
          "message"
        ],
        "additionalProperties": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {},
        "required": [],
        "additionalProperties": false
      },
      "configSchema": {
        "type": "object",
        "properties": {},
        "required": [],
        "additionalProperties": false
      },
      "requiredEventContext": [
        {
          "eventType": "commerce.purchase.created",
          "eventVersion": "1.0.0",
          "source": "scope",
          "path": "conversationId"
        }
      ],
      "ui": {
        "category": "Messages",
        "icon": "message"
      }
    },
    {
      "type": "example.delivery/has-recipient",
      "version": "1.0.0",
      "kind": "condition",
      "displayName": "Recipient is present",
      "localization": {
        "ru": {
          "displayName": "Получатель указан"
        },
        "en": {
          "displayName": "Recipient is present"
        }
      },
      "inputSchema": {
        "type": "object",
        "properties": {
          "recipient": {
            "type": "string"
          }
        },
        "required": [
          "recipient"
        ],
        "additionalProperties": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {},
        "required": [],
        "additionalProperties": false
      },
      "configSchema": {
        "type": "object",
        "properties": {},
        "required": [],
        "additionalProperties": false
      },
      "branches": [
        {
          "id": "yes",
          "label": "Yes"
        },
        {
          "id": "no",
          "label": "No"
        }
      ],
      "ui": {
        "category": "Checks",
        "icon": "question"
      }
    }
  ],
  "events": [
    {
      "type": "commerce.purchase.created",
      "version": "1.0.0",
      "displayName": "Purchase received",
      "localization": {
        "ru": {
          "displayName": "Получена покупка"
        },
        "en": {
          "displayName": "Purchase received"
        }
      },
      "payloadSchema": {
        "type": "object",
        "properties": {
          "purchaseId": {
            "type": "string"
          },
          "recipient": {
            "type": "string"
          },
          "categoryId": {
            "type": "string"
          },
          "customFields": {
            "type": "object",
            "additionalProperties": true
          }
        },
        "required": [
          "purchaseId",
          "recipient"
        ],
        "additionalProperties": false
      },
      "scopeSchema": {
        "type": "object",
        "properties": {
          "conversationId": {
            "type": "string"
          }
        },
        "required": [
          "conversationId"
        ],
        "additionalProperties": false
      },
      "selectors": [
        {
          "id": "category-id",
          "displayName": "Category",
          "source": "payload",
          "path": "categoryId",
          "operators": [
            "equals"
          ]
        },
        {
          "id": "recipient",
          "displayName": "Recipient",
          "source": "payload",
          "path": "recipient",
          "operators": [
            "exists",
            "equals",
            "contains"
          ],
          "localization": {
            "ru": {
              "displayName": "Получатель"
            },
            "en": {
              "displayName": "Recipient"
            }
          }
        }
      ],
      "bindingFields": [
        {
          "id": "recipient",
          "source": "payload",
          "path": "recipient",
          "valueSchema": {
            "type": "string"
          },
          "displayName": "Recipient",
          "localization": {
            "ru": {
              "displayName": "Получатель"
            },
            "en": {
              "displayName": "Recipient"
            }
          },
          "recommended": true,
          "availability": "always"
        },
        {
          "id": "custom-field",
          "source": "payload",
          "path": "customFields",
          "valueSchema": {
            "type": "string"
          },
          "displayName": "Custom field",
          "localization": {
            "ru": {
              "displayName": "Дополнительное поле"
            },
            "en": {
              "displayName": "Custom field"
            }
          },
          "availability": "when-present",
          "keyed": {
            "guardPath": "categoryId",
            "guardParameter": "categoryId"
          }
        }
      ],
      "bindingCatalogs": [
        {
          "id": "example.categories",
          "version": "1.0.0",
          "displayName": "Category fields",
          "scope": {
            "displayName": "Category",
            "selectorId": "category-id",
            "guardParameter": "categoryId"
          },
          "valueFieldId": "custom-field",
          "choiceFieldId": "custom-field"
        }
      ],
      "identityFields": [
        "purchaseId"
      ],
      "inputResolvers": [
        {
          "id": "commerce.recipient-profile",
          "version": "1.0.0",
          "displayName": "Recipient profile",
          "outputSchema": {
            "type": "object",
            "additionalProperties": true
          },
          "mode": "deferred",
          "localization": {
            "ru": {
              "displayName": "Профиль получателя"
            },
            "en": {
              "displayName": "Recipient profile"
            }
          },
          "requiredContext": [
            {
              "source": "scope",
              "path": "conversationId"
            }
          ],
          "timeoutMs": 30000,
          "retry": {
            "maxAttempts": 3,
            "initialBackoffMs": 1000
          },
          "ui": {
            "category": "Customer data",
            "order": 20
          }
        }
      ],
      "ui": {
        "category": "Sales",
        "icon": "cart"
      }
    }
  ],
  "abstractions": [
    {
      "abstractionId": "messaging.send-in-context",
      "abstractionVersion": "1.0.0",
      "nodeType": "example.delivery/send-message",
      "nodeVersion": "1.0.0"
    }
  ],
  "package": {
    "branding": {
      "icon": "assets/icon.png"
    },
    "artifact": {
      "path": "edge/driver.py",
      "filename": "driver.py"
    },
    "guides": {
      "installation": {
        "ru": "guides/install.ru.md",
        "en": "guides/install.en.md"
      },
      "readme": {
        "ru": "guides/README.ru.md",
        "en": "guides/README.en.md"
      },
      "changelog": {
        "ru": "guides/CHANGELOG.ru.md",
        "en": "guides/CHANGELOG.en.md"
      }
    },
    "compatibility": {
      "environments": [
        "Example Runtime 1.x"
      ]
    },
    "release": {
      "critical": false
    }
  }
}

Minimal archive layout

A conventional archive contains manifest.json, edge/driver.py, and guides/install.ru.md. guides/install.en.md and a PNG/JPEG/WebP icon are optional.

Buywell validates safe paths, sizes, file count, UTF-8 Markdown, image formats, and every referenced file. The digest covers the canonical manifest and archive contents, so ZIP entry order and timestamps do not affect identity.

Events and data

An event declares its version, payload/scope schemas, and required identity fields. Trigger selectors and binding fields are intentionally separate: selectors permit launch filtering, while binding fields expose a typed value as a workflow input.

  • Do not expose arbitrary JSON paths in the UI.
  • Mark sensitive fields.
  • A deferred resolver declares only the event context it actually needs.

Blocks and Edge

An action receives declared inputs/config and returns typed outputs. A condition also selects one declared branch. The Edge driver connects outbound and confirms the exact module ID, version, and package digest.

Buywell persists jobs and may redeliver unfinished work. The driver must honor the idempotency key and echo request correlation.

  • Never store credentials in a package.
  • Do not treat the connection as execution state.
  • Return only values allowed by the output schema.

Install and update

1.0.0Current workflows stay pinned
1.1.0Installed alongside it
Explicit choiceUpdate or roll back

The UI, API, and live registration use the same ZIP validator. A new version is installed alongside the old one and never migrates workflows silently. Rollback selects an already installed exact version.

A package referenced by a draft or published workflow cannot be removed. Installation instructions are always read from the pinned archive rather than an external site.