Connector recipes

Ready-made connectors (a supplier, a print partner, a nightly report, low-stock reordering, chat alerts, a sheet sync), installed switched off.

A recipe is a whole integration in one file: the flows it needs, the subscriptions it needs, the credentials it will ask you for and the custom fields it reads and writes. Installing one writes it into your store — switched off — and tells you exactly what is still on you.

Recipes exist because the pieces already did. Events, flows, inbound hooks, the secrets vault and custom fields are each simple on their own; wiring six of them together correctly is the part nobody wants to do twice. A recipe is that wiring, written once, with nothing store-specific in it.

1. The library

idWhat it doesYou supply
dropship-supplier-webhookEvery paid order is posted to your supplier; their status pushes come back on an inbound hook and wake your agent to set the trackingsupplier endpoint, supplier API key, optional agent endpoint
print-on-demandEvery paid order becomes a print job at your partner, with the artwork on the product as a custom fieldpartner endpoint, partner API key
nightly-sales-reportOne email to you each morning with the date and the links, and an optional nudge to your agent to write up the numberssend time, timezone, optional agent endpoint
low-stock-reorderA product that drops to your threshold is posted to your reordering system and you are toldreorder endpoint, threshold, optional API key
discord-order-alertsEvery paid order over an amount you choose is posted to a chat channel's incoming webhookthe channel's webhook URL (kept in the vault)
sheet-syncYour spreadsheet endpoint is pinged on a clock, and every paid order is delivered to it as it happenssheet endpoint, a token your script checks

2. What a recipe file looks like

{
  "id": "low-stock-reorder",
  "name": "Low stock → reorder",
  "category": "Inventory",
  "description": "…",
  "needs": {
    "scopes": ["settings:write"],
    "secrets": [{ "name": "reorder_api_key", "purpose": "…" }],
    "customFields": ["ops.reorder_point"],
    "options": [
      { "name": "reorder_endpoint", "label": "Reorder endpoint", "kind": "url", "required": true, "help": "…" },
      { "name": "threshold", "label": "Reorder at", "kind": "number", "required": false, "default": "3", "help": "…" }
    ]
  },
  "flows": [{ "name": "Low stock → reorder", "topics": ["product.updated"],
              "filter": "changed contains \"inventory\" and data.inventory <= ${threshold}",
              "actions": [{ "type": "webhook", "url": "${reorder_endpoint}",
                            "headers": { "Authorization": "Bearer {{ secrets.reorder_api_key }}" } }] }],
  "customFieldDefinitions": [{ "ownerType": "product", "namespace": "ops", "key": "reorder_point",
                               "type": "number", "purpose": "…" }],
  "subscriptions": [],
  "notes": ["…"]
}

Two kinds of placeholder, and the difference matters:

  • ${option_name} is filled in at install time, on the platform, from the options you pass. It can appear anywhere — a URL, a filter, a schedule interval.
  • {{ secrets.name }} and {{ data.… }} are the ordinary template language (automations.md §3), rendered at run time inside your store. A secret may only appear in a webhook action's URL or headers, or a wake_agent bearer.

A recipe never contains a secret value, a store id, a hostname or anything else belonging to one merchant. That is enforced by the schema and by the tests, and it is why the library can be public.

3. Installing

POST /api/recipes/install
{ "id": "low-stock-reorder",
  "options": { "reorder_endpoint": "https://supplier.example/reorder", "threshold": "5" },
  "secrets": { "reorder_api_key": "…" } }

or install_recipe { id, options?, secrets? } from an agent. What happens, in order:

  1. The options are substituted and the flows are validated before anything is written. A missing required option, an unknown option name or a flow that would not survive the store's own validation is a 400 that names the field.
  2. Each secret is encrypted on the platform and stored write-only in your store's vault. No route or tool ever reads one back.
  3. The flows are created disabled, and so are the subscriptions. Nothing talks to anyone until you switch it on — read it first.
  4. Custom fields are documented, not created: a field exists once something sets a value, so the result repeats the namespaced keys the recipe uses and the types it expects.

The response says what was created, what was dropped (an optional option left blank removes the action that needed it — this is how one recipe covers both "wake my agent" and "just email me"), and what is still on you:

{ "recipe": { "id": "low-stock-reorder", "name": "Low stock → reorder" },
  "created": { "flows": [{ "id": "…", "name": "Low stock → reorder", "enabled": false }],
               "subscriptions": [], "secrets": ["reorder_api_key"] },
  "documented": [{ "ownerType": "product", "namespace": "ops", "key": "reorder_point", "type": "number", "purpose": "…" }],
  "dropped": [],
  "todo": ["Dry-run each flow with test_flow, then switch it on with enable_flow { flowId } — …", "…"] }

uninstall_recipe { id } (or POST /api/recipes/install { id, uninstall: true }) deletes the flows and subscriptions the recipe created, matched by name. It deliberately leaves your secrets (another flow may use them) and your custom field values (they are your data) and says so.

4. The API and the tools

RouteScopeWhat
GET /api/recipessettings:readthe library as cards: { recipes: [{ id, name, category, description, needs, flows, subscriptions, customFields }] }
GET /api/recipes?id=settings:readone recipe in full
POST /api/recipes/installsettings:writeinstall (or { uninstall: true })

Tools: list_recipes, get_recipe { id }, install_recipe { id, secrets?, options? }, uninstall_recipe { id }. They act on the token's environment, so a sandbox token installs into the sandbox — which is the sensible place to try a connector before it touches real orders.

In the dashboard, Automations → Flows → Start from a recipe (#automations/flows/recipes) shows the ready-made single flows with the connectors below them: each card lists what the connector needs, the fields appear inline, and installing reports the same "what is still on you" list.

5. Adding one

One JSON file in src/lib/recipes/, one line in catalog.ts, one row in the table above. The schema test checks every recipe in the folder: the id and shape, that every ${placeholder} is a declared option, that every flow survives flowInputSchema once the options are filled in, that no secret value or store-specific value appears anywhere, and that nothing the recipe installs arrives enabled.

See also

  • agents.md — the four recipe tools and why install_recipe comes before hand-building a flow.
  • automations.md — what a recipe writes: flows, actions, templates, schedules and hooks.
  • events.md — the topics a recipe's subscriptions listen to.
  • custom-fields.md — the fields a recipe documents and then reads.