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
| id | What it does | You supply |
|---|---|---|
dropship-supplier-webhook | Every paid order is posted to your supplier; their status pushes come back on an inbound hook and wake your agent to set the tracking | supplier endpoint, supplier API key, optional agent endpoint |
print-on-demand | Every paid order becomes a print job at your partner, with the artwork on the product as a custom field | partner endpoint, partner API key |
nightly-sales-report | One email to you each morning with the date and the links, and an optional nudge to your agent to write up the numbers | send time, timezone, optional agent endpoint |
low-stock-reorder | A product that drops to your threshold is posted to your reordering system and you are told | reorder endpoint, threshold, optional API key |
discord-order-alerts | Every paid order over an amount you choose is posted to a chat channel's incoming webhook | the channel's webhook URL (kept in the vault) |
sheet-sync | Your spreadsheet endpoint is pinged on a clock, and every paid order is delivered to it as it happens | sheet 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 theoptionsyou 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 awake_agentbearer.
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:
- 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.
- Each secret is encrypted on the platform and stored write-only in your store's vault. No route or tool ever reads one back.
- The flows are created disabled, and so are the subscriptions. Nothing talks to anyone until you switch it on — read it first.
- 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
| Route | Scope | What |
|---|---|---|
GET /api/recipes | settings:read | the library as cards: { recipes: [{ id, name, category, description, needs, flows, subscriptions, customFields }] } |
GET /api/recipes?id= | settings:read | one recipe in full |
POST /api/recipes/install | settings:write | install (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_recipecomes 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.