DEVELOPER DOCUMENTATION

Build powerful integrations with Buywell

Connect a marketplace or a specialized signed API driver using the public Edge SDK, immutable packages, and real open-source implementations.

2extension kindsPython 3.12Edge SDKEd25519signed packages
Marketplace
API driver
Buywell Edge
Workflow
Signed package
BUYWELL
integration fabric
Quick start

Run one workflow first

Your first result does not require a custom module. Build and test a workflow, publish it, and only then connect a real event.

01

Create a workflow

Declare typed inputs and connect every path from Start to a terminal result.

02

Test it

A test run shows inputs, step results, and the exact point of failure.

03

Publish

Publishing creates an immutable revision. Later edits stay in a new draft.

04

Connect an event

Select an exact module version and event, add trigger conditions, and bind event fields to inputs.

05

Run and observe

Enable the connection and follow events, retries, delivery queues, and execution metrics.

Ready to try it?

Create an account and test a built-in workflow before developing an integration.

Create account
Architecture choice

What are you integrating?

The public Edge SDK supports two extension kinds. A marketplace module describes a platform; an adapter-driver adds operations for one specialized API.

CapabilityMarketplace moduleManaged adapter
Receives platform events
Publishes workflow actions
Runs through Edge
Keeps secrets on user device
Custom request signingwhen needed
Live account catalog
Integrator guide

Add your marketplace

A module translates one platform API into versioned Buywell events, actions, and catalogs. The SDK owns the Edge protocol, delivery, heartbeat, and package manifest.

01Provider API
02Your extension
03Buywell Edge
04Workflow
05Result

1. Define the contract

Choose a stable extension ID and semver. Declare Pydantic event and action models with equivalent RU and EN field meaning.

2. Connect the provider

Start the platform client in on_start. Emit only expected events through session.emit_event and use a deterministic event_id for deduplication.

3. Add actions

Each action receives typed input and returns only its output schema. Redelivery keeps the same idempotency key.

4. Build the package

The local builder generates Manifest v2, pins files and dependencies, calculates the digest, and signs a deterministic archive.

5. Verify in Edge

Install in dev mode, connect a test account, and verify health, one event, redelivery, and an upgrade from the previous version.

Install the public SDK

The Edge repository contains the daemon, CLI, package builder, and the same Python SDK used by official integrations.

github.com/moreveal/buywell-edge ↗
TERMINALCODE
git clone https://github.com/moreveal/buywell-edge.git
cd buywell-edge
python3.12 -m venv .venv
. .venv/bin/activate
pip install -e '.[test]'

# From your extension repository:
buywell-edge module build extension:extension --source .
extension.py — MINIMAL MARKETPLACE SKELETONPYTHON
import asyncio
from pydantic import BaseModel
from buywell_edge_sdk import contract_field, module

class PaidOrder(BaseModel):
    order_id: str = contract_field(
        label={"ru": "Номер заказа", "en": "Order ID"},
    )
    buyer: str = contract_field(
        label={"ru": "Покупатель", "en": "Buyer"},
    )

extension = module(
    extension_id="example.market",
    version="1.0.0",
    display_name={"ru": "Пример", "en": "Example"},
    publisher="Example",
    entrypoint="extension:extension",
    network_domains=["api.example.com"],
)

@extension.event(
    "commerce.purchase.created",
    "1.0.0",
    payload_model=PaidOrder,
    identity_fields=["order_id"],
    display_name={"ru": "Заказ оплачен", "en": "Order paid"},
)
async def paid_order_contract(_context):
    return {}

async def forward_order(session, order):
    await session.emit_event(
        "commerce.purchase.created",
        "1.0.0",
        PaidOrder(order_id=order.id, buyer=order.buyer).model_dump(),
        {"shopId": order.shop_id},
        event_id=f"example:{order.id}:paid",
    )
1

Do not implement the Buywell WebSocket, leases, outbox, or heartbeat in an extension; Edge owns them.

2

Never put platform tokens in the package, manifest, or workflow. Configuration secrets belong to the local connection.

3

Trigger selectors filter launches; binding fields and catalogs supply typed values. They are different contracts.

4

Changing a public event, action, or field requires a new contract version. Updating internal provider code may not.

Specialized API

Build a signed adapter-driver

Use a managed adapter when a request cannot honestly be represented by a regular cloud HTTP adapter. The driver runs near the user, and its blocks appear only after signature verification and a live connection.

USE IT WHEN
  • HMAC or a custom per-request signature
  • TOTP, refresh sessions, or device identity
  • supplier-side IP allowlisting
  • a local library or pinned upstream
  • secrets must not leave the user's device
sourcedigestEd25519verified operations
driver.py — SIGNED SPECIALIZED APIPYTHON
from pydantic import BaseModel, SecretStr
from buywell_edge_sdk import adapter_driver, contract_field

class Settings(BaseModel):
    api_key: SecretStr

class ReserveRequest(BaseModel):
    item_id: str = contract_field(
        label={"ru": "ID товара", "en": "Item ID"},
    )

class ReserveResult(BaseModel):
    reserved: bool = contract_field(
        label={"ru": "Зарезервировано", "en": "Reserved"},
    )

driver = adapter_driver(
    extension_id="adapter.example-supplier",
    version="1.0.0",
    display_name={"ru": "Поставщик", "en": "Supplier"},
    publisher="Example",
    entrypoint="driver:driver",
    config_model=Settings,
    network_domains=["api.example.com"],
)

@driver.operation(
    "adapter.example-supplier/reserve",
    "1.0.0",
    input_model=ReserveRequest,
    output_model=ReserveResult,
    display_name={"ru": "Зарезервировать", "en": "Reserve"},
)
async def reserve(context, value):
    # Sign the provider request here with context.secrets["api_key"].
    return ReserveResult(reserved=True)
01

Secrets stay local

SecretStr and secret metadata become configuration.secretFields, never workflow inputs.

02

Network is bounded

The package declares network_domains up front. Permission is not inferred from a user URL.

03

Contract is signed

Edge sends the manifest, digest, and Ed25519 signature; Buywell verifies them before registering operations.

04

Visibility is isolated

Operations exist only for the account with that verified connection and disappear with it.

What Buywell registers

Pydantic models become operation schemas. contract_field supplies localized UI labels. The signed managedAdapter and adapterOperations sections create account-scoped workflow blocks; no duplicate cloud definition is required.

Open source

Read working implementations

Official extensions use the same public SDK and package format available to third-party developers.

PUBLIC REPOSITORY

moreveal/buywell-runtimes

The buywell-runtimes repository is the source of truth for official integration source and immutable release packages.

GitHub ↗
buywell-automation

Control plane, workflow contracts, validation, editor, and execution.

buywell-edge

User-owned daemon, CLI, package builder, public SDK, and binary releases.

buywell-runtimes

Official provider implementations, tests, pinned upstreams, and package releases.

Publishing and compatibility

Git remains the source of truth

A version already delivered to a user is immutable. New code gets a new version, while existing workflows keep their previous contract.

01

Source

Commit implementation, schemas, RU/EN guides, changelog, and exact dependencies in a public or reviewable git commit.

02

Checks

Run unit and contract tests, self-test, and an upgrade test. The builder must not read files outside the source tree.

03

Release

Create the tag and release assets from that commit. Never overwrite a published archive, digest, or version.

04

Delivery

The official catalog points to an exact release URL and SHA-256. Edge downloads, verifies, and cuts the connection over atomically.

05

Migration

A new version installs alongside the old one. Contract changes and published-workflow migration are always explicit.

1.0.0immutable
+
1.1.0new package
overwrite 1.0.0never
TELEGRAM
Follow Buywell updates

New integrations, Edge and runtime releases, product changes, and migration notes.

Subscribe
Package contract

Complete Manifest reference

The reference below is generated from the current validator and uses checked examples. For Edge packages, prefer typed SDK declarations over hand-written JSON.

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"
          },
          "orderUrl": {
            "type": "string"
          }
        },
        "required": [
          "conversationId",
          "orderUrl"
        ],
        "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"
      ],
      "buyerForm": {
        "returnUrl": {
          "source": "scope",
          "path": "orderUrl",
          "allowedOrigins": [
            "https://shop.example"
          ]
        }
      },
      "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[]111 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[].buyerFormobject

Declares a safe store return for the public buyer form. · unknown fields are rejected

events[].buyerForm.returnUrlobjectrequired

Defines the return URL source and allowed stores. · unknown fields are rejected

events[].buyerForm.returnUrl.source"payload" | "scope"required

Selects payload or scope as the source of the return URL.

events[].buyerForm.returnUrl.pathstringrequired

Points to the guaranteed string path containing the return URL. · minimum length: 1 · maximum length: 512

events[].buyerForm.returnUrl.allowedOriginsarrayrequired

Restricts redirects to an exact list of allowed HTTPS origins. · minimum items: 1 · maximum items: 20

events[].inputResolversarray

Versioned immediate/deferred data sources; messaging.collect-input enables chat and may coexist with buyerForm. · 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"
          },
          "orderUrl": {
            "type": "string"
          }
        },
        "required": [
          "conversationId",
          "orderUrl"
        ],
        "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"
      ],
      "buyerForm": {
        "returnUrl": {
          "source": "scope",
          "path": "orderUrl",
          "allowedOrigins": [
            "https://shop.example"
          ]
        }
      },
      "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
    }
  }
}