Workato (Platform API)
Control a Workato account by calling its REST API with a token. This skill bakes in the
endpoint map, the recipe code JSON format, and the non-obvious traps that otherwise cost
hours. Start every task by orienting (token + scope), then use scripts/wk.py — it
encodes the base URL, auth, and the body quirks so you never rewrite curl.
Setup & orientation (do this first)
- Token:
~/.config/workato/api_token (or $WORKATO_API_TOKEN). A wrkaus-… prefix = US region.
- Helper:
python3 ~/.claude/skills/workato/scripts/wk.py … (zero deps, stdlib only). Run wk.py -h.
- Optional MCP server: if a
workato MCP server is registered, its read + start/stop tools
also work — use fully-qualified names (workato:list_recipes, workato:get_recipe,
workato:list_connections, workato:list_folders, workato:list_projects,
workato:list_recipe_jobs, workato:start_recipe, workato:stop_recipe, workato:workato_get).
Use them for reads if present, but for creating/updating recipes use wk.py (the MCP server
has no write tools). The server is optional — wk.py alone covers everything.
- Always check scope before promising anything:
wk.py scope. A token is scoped to one
API client's role — many resources may be 401. The token this was built for does
recipes (R/W) + jobs + versions + connections + folders + projects; lookup tables,
properties, roles, API platform, audit logs, tags, on-prem are typically 401.
What you can do (and the command for it)
| Goal |
Command |
| See capability surface |
wk.py scope |
| List recipes / running ones |
wk.py recipes [--folder ID] [--running] |
| Inspect a recipe (and its code) |
wk.py recipe <id> [--code] |
| List connections / folders / projects |
wk.py connections · wk.py folders [--parent ID] · wk.py projects |
| Debug runs / discover field names |
wk.py jobs <id> then wk.py job <id> <job_id> --outputs |
| See version history |
wk.py versions <id> |
| Create a recipe (left stopped) |
wk.py create --name N --folder ID --code code.json --config config.json |
| Update a recipe (must be stopped) |
wk.py update <id> [--name N] [--code code.json] [--config config.json] |
| Start / stop |
wk.py start <id> · wk.py stop <id> |
| Delete a (scratch) recipe |
wk.py delete recipes/<id> |
| Anything else |
`wk.py get |
Four golden rules (internalize these)
- The API stores recipe
code verbatim and does NOT validate it. A {"success":true}
write can still be semantically broken (wrong operand key, wrong datapill field, bad input).
Only the editor/runtime validate. So a created recipe isn't "working" until verified — never
claim otherwise on the strength of the HTTP 200 alone.
wk.py start IS a free validator. It returns the editor's code_errors (invalid
provider/action names, missing required fields, bad pills) without opening the UI — so
unknown encodings can be discovered by probe loop on a scratch recipe (recipe-gotchas.md).
Stop a scratch immediately if it starts and its trigger polls a real source.
- Discover real encodings empirically, don't guess. Field names come from a real job:
GET /recipes/:id/jobs/:job_id → per-step lines[] with RESOLVED input/output (unknown
input keys are silently schema-filtered, so the surviving keys reveal an action's true
schema). Pill/picklist encodings: build once in the editor and read back.
- Validation ≠ runtime. Pills can validate yet resolve EMPTY (
_dp+"first" trap),
and runtime-only failures exist (lookup() wrong table name, nil-chain errors, Shopify
"Sold out"/"Record is invalid"). Full verification = start + one real job + inspect the
created record. Validation errors also hide behind HTTP 200 ({"success":false,…}).
Core workflows
Inspect / explore an account
wk.py scope → wk.py recipes / connections / folders / projects. To see how a recipe
ran, list jobs then dump a job. This is read-only and safe.
Build a recipe
- Pick a non-root folder (
wk.py folders) and the connection id (wk.py connections).
- Write the
code tree (trigger = step 0; children in block) and a config array. Follow
references/recipe-code-dsl.md for step structure, control flow (IF/ELSE_IF/ELSE as
sibling steps, foreach/repeat loops, try/catch), the verified condition operand
table, and datapill encoding. Get connector field names from references/connectors-gmail.md
(or a real job for other connectors).
wk.py create … (leaves it stopped). Read it back: wk.py recipe <id> --code.
- Verify before declaring success (golden rule #1): have the user open it in the editor, or
inspect a job once it runs. Then
wk.py start <id> when ready.
Fix / debug a recipe
wk.py recipe <id> --code to see the current tree → locate the bad step → fix in a local
code.json → wk.py update <id> --code code.json. The usual culprits (all in
references/recipe-gotchas.md): an invalid operand key (doesnt_contain → must be
not_contains; full table in the DSL ref), a datapill pointing at a non-existent field
(e.g. from instead of from_email), or folder_id/code body-type mistakes on create.
A fix isn't done at the update 200 (golden rule #1): re-read the code, then re-validate
with wk.py start and/or one real job before declaring it fixed.
Trigger timing
Most triggers (Gmail new_email included) are polling, not real-time; the interval is
plan-gated and cannot be changed via the API. Real-time needs a webhook trigger / external
push (Gmail → Pub/Sub). Details in recipe-gotchas.md.
When to read which reference
- references/recipe-code-dsl.md — building/fixing recipe
code: step keywords, control
flow (IF/ELSE, foreach/repeat loops, try/catch), the verified operand table, datapill
formats (incl. the array-pill validation-vs-runtime
table, = formula mode for non-first elements/ternaries/lookup(), list
.where(field:'val') filtering + the backward-compatible null-safe guard for the
[0]['x']-on-nil crash, the DB batch-insert rows/____source shape, the
extended-schema rules, formula conditions, and the stop step), a full worked example.
Read this for any build-or-fix task.
- references/recipe-gotchas.md — before any create/update: the verbatim-storage trap, the
start-as-validator probe loop, job
lines[] debugging (incl. ?include_payloads=true
and the try/catch-hides-failure trap — job succeeded while the source system shows
FAILED), editing a live recipe safely (backup → leaf-diff assert → stop/update/start →
rollback → re-test), forcing an immediate poll (stop+start), editor re-save rewrites,
folder_id-string / code-string rules, field discovery, polling vs real-time.
- references/connectors-utilities.md — verified encodings for json_parser (parse a
JSON-string output into pills;
document root + labeled-schema traps), logger
(log_message as a pill-resolution probe), lookup tables (the lookup() formula vs
the half-mapped lookup_table connector; API is 401 — tables are UI-maintained).
Read this whenever a connector returns JSON as a string, or a mapping needs a lookup table.
- references/api-endpoints.md — exact endpoints, regions, rate limits, the broader (often
401) API surface, the error model, and how to widen token scope.
- references/connectors-gmail.md — Gmail
new_email outputs + send_mail inputs.
- references/connectors-orderful-shopify.md — inbound-EDI playbook: Orderful → Workato →
Shopify (Walmart 850 PO → Shopify draft order). The poller-bucket routing trap
(Orderful Communication Channels, UI-only — recipe gets 0 jobs if inbound isn't routed to a
POLLER channel), the bucketId trailing-space bug, the Orderful poller trigger +
get_record
(returns the parsed message as a JSON string → json_parser), Shopify
create_draft_order (full verified input incl. addresses/note, the
extended_input_schema requirement, province/country naming, "Sold out" /
"Record is invalid" causes) and search_product (handle-only lookup → handle=UPC
convention), the three-tier item matching pattern (Shopify → lookup table → stop with
details), how to inject a test 850, and the full proven recipe with mapping formulas.
Read this for any Orderful/EDI-inbound recipe or Shopify draft-order action.
- references/connector-sdk.md — the boundary case: a task needs a connector built or
changed (not a recipe). This skill can't do that — connectors are authored with the Ruby
Workato Connector SDK (
workato new/exec/push). Read this only when no connector
exists for the app, or you must edit a custom connector's internals; for recipes, stay here.
Not the same as Workato's hosted MCP
This skill calls the Workato REST API with your own token from local scripts (deterministic,
endpoint-shaped). Workato also offers Remote MCP servers — Workato hosts an MCP server that
exposes selected recipes as LLM tools at a https://<instance>.apim.mcp.workato.com/…?wkt_token=…
URL you'd add as a Claude connector. That's a different, LLM-tool-shaped surface. Don't conflate
them: for "use my token to build/fix/inspect recipes," use this skill.
1---2name: workato3description: Drive a Workato account via its Platform REST API — inspect, build, fix, debug, and start/stop recipes; read connections, folders, projects, jobs. Use when a task touches a Workato account or recipe.4---56# Workato (Platform API)78Control a Workato account by calling its REST API with a token. This skill bakes in the9endpoint map, the recipe `code` JSON format, and the non-obvious traps that otherwise cost10hours. **Start every task by orienting (token + scope), then use `scripts/wk.py`** — it11encodes the base URL, auth, and the body quirks so you never rewrite curl.1213## Setup & orientation (do this first)1415- **Token:** `~/.config/workato/api_token` (or `$WORKATO_API_TOKEN`). A `wrkaus-…` prefix = US region.16- **Helper:** `python3 ~/.claude/skills/workato/scripts/wk.py …` (zero deps, stdlib only). Run `wk.py -h`.17- **Optional MCP server:** if a `workato` MCP server is registered, its read + start/stop tools18 also work — use fully-qualified names (`workato:list_recipes`, `workato:get_recipe`,19 `workato:list_connections`, `workato:list_folders`, `workato:list_projects`,20 `workato:list_recipe_jobs`, `workato:start_recipe`, `workato:stop_recipe`, `workato:workato_get`).21 Use them for reads if present, **but for creating/updating recipes use `wk.py`** (the MCP server22 has no write tools). The server is optional — `wk.py` alone covers everything.23- **Always check scope before promising anything:** `wk.py scope`. A token is scoped to one24 API client's role — many resources may be `401`. The token this was built for does25 **recipes (R/W) + jobs + versions + connections + folders + projects**; lookup tables,26 properties, roles, API platform, audit logs, tags, on-prem are typically `401`.2728## What you can do (and the command for it)2930| Goal | Command |31|---|---|32| See capability surface | `wk.py scope` |33| List recipes / running ones | `wk.py recipes [--folder ID] [--running]` |34| Inspect a recipe (and its code) | `wk.py recipe <id> [--code]` |35| List connections / folders / projects | `wk.py connections` · `wk.py folders [--parent ID]` · `wk.py projects` |36| Debug runs / discover field names | `wk.py jobs <id>` then `wk.py job <id> <job_id> --outputs` |37| See version history | `wk.py versions <id>` |38| Create a recipe (left stopped) | `wk.py create --name N --folder ID --code code.json --config config.json` |39| Update a recipe (must be stopped) | `wk.py update <id> [--name N] [--code code.json] [--config config.json]` |40| Start / stop | `wk.py start <id>` · `wk.py stop <id>` |41| Delete a (scratch) recipe | `wk.py delete recipes/<id>` |42| Anything else | `wk.py get|post|put|delete <path> [--data @file]` |4344## Four golden rules (internalize these)45461. **The API stores recipe `code` verbatim and does NOT validate it.** A `{"success":true}`47 write can still be semantically broken (wrong operand key, wrong datapill field, bad input).48 Only the editor/runtime validate. So a created recipe isn't "working" until verified — never49 claim otherwise on the strength of the HTTP 200 alone.502. **`wk.py start` IS a free validator.** It returns the editor's `code_errors` (invalid51 provider/action names, missing required fields, bad pills) without opening the UI — so52 unknown encodings can be discovered by probe loop on a scratch recipe (recipe-gotchas.md).53 Stop a scratch immediately if it starts and its trigger polls a real source.543. **Discover real encodings empirically, don't guess.** Field names come from a real job:55 `GET /recipes/:id/jobs/:job_id` → per-step `lines[]` with RESOLVED input/output (unknown56 input keys are silently schema-filtered, so the surviving keys reveal an action's true57 schema). Pill/picklist encodings: build once in the editor and read back.584. **Validation ≠ runtime.** Pills can validate yet resolve EMPTY (`_dp`+`"first"` trap),59 and runtime-only failures exist (`lookup()` wrong table name, nil-chain errors, Shopify60 "Sold out"/"Record is invalid"). Full verification = start + one real job + inspect the61 created record. Validation errors also hide behind HTTP 200 (`{"success":false,…}`).6263## Core workflows6465### Inspect / explore an account66`wk.py scope` → `wk.py recipes` / `connections` / `folders` / `projects`. To see how a recipe67ran, list jobs then dump a job. This is read-only and safe.6869### Build a recipe701. Pick a **non-root** folder (`wk.py folders`) and the **connection id** (`wk.py connections`).712. Write the `code` tree (trigger = step 0; children in `block`) and a `config` array. Follow72 **references/recipe-code-dsl.md** for step structure, control flow (IF/ELSE_IF/ELSE as73 sibling steps, `foreach`/`repeat` loops, `try`/`catch`), the verified condition operand74 table, and datapill encoding. Get connector field names from **references/connectors-gmail.md**75 (or a real job for other connectors).763. `wk.py create …` (leaves it **stopped**). Read it back: `wk.py recipe <id> --code`.774. **Verify** before declaring success (golden rule #1): have the user open it in the editor, or78 inspect a job once it runs. Then `wk.py start <id>` when ready.7980### Fix / debug a recipe81`wk.py recipe <id> --code` to see the current tree → locate the bad step → fix in a local82`code.json` → `wk.py update <id> --code code.json`. The usual culprits (all in83**references/recipe-gotchas.md**): an invalid operand key (`doesnt_contain` → must be84`not_contains`; full table in the DSL ref), a datapill pointing at a non-existent field85(e.g. `from` instead of `from_email`), or `folder_id`/`code` body-type mistakes on create.86**A fix isn't done at the `update` 200** (golden rule #1): re-read the code, then re-validate87with `wk.py start` and/or one real job before declaring it fixed.8889### Trigger timing90Most triggers (Gmail `new_email` included) are **polling**, not real-time; the interval is91plan-gated and **cannot be changed via the API**. Real-time needs a webhook trigger / external92push (Gmail → Pub/Sub). Details in recipe-gotchas.md.9394## When to read which reference9596- **references/recipe-code-dsl.md** — building/fixing recipe `code`: step keywords, control97 flow (IF/ELSE, `foreach`/`repeat` loops, `try`/`catch`), the verified operand table, datapill98 formats (incl. the **array-pill validation-vs-runtime99 table**, **`=` formula mode** for non-first elements/ternaries/`lookup()`, list100 **`.where(field:'val')` filtering + the backward-compatible null-safe guard** for the101 `[0]['x']`-on-nil crash, the **DB batch-insert `rows`/`____source` shape**, the102 extended-schema rules, formula conditions, and the `stop` step), a full worked example.103 *Read this for any build-or-fix task.*104- **references/recipe-gotchas.md** — before any create/update: the verbatim-storage trap, the105 **start-as-validator probe loop**, job `lines[]` debugging (incl. `?include_payloads=true`106 and the **try/catch-hides-failure** trap — job `succeeded` while the source system shows107 FAILED), **editing a live recipe safely** (backup → leaf-diff assert → stop/update/start →108 rollback → re-test), forcing an immediate poll (stop+start), editor re-save rewrites,109 `folder_id`-string / `code`-string rules, field discovery, polling vs real-time.110- **references/connectors-utilities.md** — verified encodings for **json_parser** (parse a111 JSON-string output into pills; `document` root + labeled-schema traps), **logger**112 (`log_message` as a pill-resolution probe), **lookup tables** (the `lookup()` formula vs113 the half-mapped `lookup_table` connector; API is 401 — tables are UI-maintained).114 *Read this whenever a connector returns JSON as a string, or a mapping needs a lookup table.*115- **references/api-endpoints.md** — exact endpoints, regions, rate limits, the broader (often116 `401`) API surface, the error model, and how to widen token scope.117- **references/connectors-gmail.md** — Gmail `new_email` outputs + `send_mail` inputs.118- **references/connectors-orderful-shopify.md** — inbound-EDI playbook: Orderful → Workato →119 Shopify (Walmart 850 PO → Shopify draft order). The poller-bucket **routing trap**120 (Orderful Communication Channels, UI-only — recipe gets 0 jobs if inbound isn't routed to a121 POLLER channel), the bucketId trailing-space bug, the Orderful poller trigger + `get_record`122 (returns the parsed message as a JSON **string** → json_parser), Shopify123 `create_draft_order` (full verified input incl. addresses/note, the124 extended_input_schema requirement, `province`/`country` naming, "Sold out" /125 "Record is invalid" causes) and `search_product` (handle-only lookup → handle=UPC126 convention), the **three-tier item matching** pattern (Shopify → lookup table → stop with127 details), how to inject a test 850, and the full proven recipe with mapping formulas.128 *Read this for any Orderful/EDI-inbound recipe or Shopify draft-order action.*129- **references/connector-sdk.md** — the boundary case: a task needs a **connector** built or130 changed (not a recipe). This skill can't do that — connectors are authored with the Ruby131 **Workato Connector SDK** (`workato new/exec/push`). *Read this only when no connector132 exists for the app, or you must edit a custom connector's internals; for recipes, stay here.*133134## Not the same as Workato's hosted MCP135136This skill calls the **Workato REST API** with your own token from local scripts (deterministic,137endpoint-shaped). Workato also offers **Remote MCP servers** — Workato *hosts* an MCP server that138exposes selected recipes as LLM tools at a `https://<instance>.apim.mcp.workato.com/…?wkt_token=…`139URL you'd add as a Claude connector. That's a different, LLM-tool-shaped surface. Don't conflate140them: for "use my token to build/fix/inspect recipes," use this skill.