{"id":"1b024399-a1a9-4145-a815-b64b7856910e","entityType":"agent","slug":"clawhub-chrischall-myhotlunchbox-mcp","name":"myhotlunchbox-mcp","canonicalUrl":"https://www.xpersona.co/agent/clawhub-chrischall-myhotlunchbox-mcp","canonicalPath":"/agent/clawhub-chrischall-myhotlunchbox-mcp","generatedAt":"2026-10-11T03:56:38.043Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"editorial-content","verified":true,"confidence":"high","updatedAt":"2026-10-11T00:50:03.445Z","emptyReason":null},"description":"Read and manage a My Hot Lunchbox school-lunch account from a shell with curl — sign in, list students, read the lunch calendar and cart, check orders, deliveries and payments. Use when you want My Hot Lunchbox data without running the MCP server, in a script, or on a machine where the MCP is not installed. Skill: myhotlunchbox-mcp Owner: chrischall Summary: Read and manage a My Hot Lunchbox school-lunch account from a shell with curl — sign in, list students, read the lunch calendar and cart, check orders, deliveries and payments. Use when you want My Hot Lunchbox data without running the MCP server, in a script, or on a machine where the MCP is not installed. Tags: latest:1.2.6 Version history: v1.2.6 | 2026-10-09T23:","descriptionLabel":"Technical summary","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 1.2K downloads reported by the source. Last updated 10/11/2026.","installCommand":"clawhub skill install s17cjx1a349nz5apaqp02vgz4h85728z:myhotlunchbox-mcp","sourceUrl":"https://clawhub.ai/chrischall/myhotlunchbox-mcp","homepage":"https://clawhub.ai/chrischall/skills/myhotlunchbox-mcp","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/chrischall/myhotlunchbox-mcp","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/chrischall/skills/myhotlunchbox-mcp","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":62,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"Read and manage a My Hot Lunchbox school-lunch account from a shell with curl — sign in, list students, read the lunch calendar and cart, check orders, deliveri"},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-11T00:50:03.445Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T00:50:03.445Z","emptyReason":null},"stars":null,"forks":null,"downloads":1214,"packageName":null,"latestVersion":"1.2.6","tractionLabel":"1.2K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T00:50:03.378Z","emptyReason":null},"lastUpdatedAt":"2026-10-11T00:50:03.445Z","lastCrawledAt":"2026-10-11T00:50:03.378Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-12T00:50:03.378Z","lastVerifiedAt":null,"highlights":[{"version":"1.2.6","createdAt":"2026-10-09T23:27:01.483Z","changelog":"- Update documentation in SKILL.md to clarify MCP confirmation behavior and mention the `MCP_CONFIRM_ELICITATION=off` environment variable. - Remove redundant skill-card.md file. - No changes to actual skill logic; update is documentation-only.","fileCount":4,"zipByteSize":7351},{"version":"1.2.5","createdAt":"2026-10-07T13:40:04.353Z","changelog":"- Removed the outdated skill-card.md file. - No user-facing changes to commands or documentation.","fileCount":4,"zipByteSize":7278},{"version":"1.2.4","createdAt":"2026-10-05T02:48:19.953Z","changelog":"- Removed the sample file skill-card.md. - No changes to code or user-facing functionality.","fileCount":4,"zipByteSize":7367},{"version":"1.2.3","createdAt":"2026-10-03T01:42:48.396Z","changelog":"- Removed the skill-card.md file. - No functional or interface changes to the skill itself. - Documentation and usage remain unchanged.","fileCount":4,"zipByteSize":7253},{"version":"1.2.2","createdAt":"2026-09-30T16:56:52.301Z","changelog":"- removed 1 file(s). - Updated SKILL.md and bundle contents.","fileCount":4,"zipByteSize":7302},{"version":"1.2.1","createdAt":"2026-09-25T15:50:28.908Z","changelog":"- Removed the skill-card.md file. - No feature or documentation changes; functionality remains unchanged.","fileCount":4,"zipByteSize":7338},{"version":"1.2.0","createdAt":"2026-09-24T15:13:39.936Z","changelog":"- Adds a summary of MCP's mutation confirmation feature to documentation. - Updates the SKILL.md file to reflect the use of confirmation prompts and tokens in MCP. - Removes the obsolete skill-card.md file.","fileCount":4,"zipByteSize":7454},{"version":"1.1.4","createdAt":"2026-09-23T21:40:12.460Z","changelog":"- Removed the file: skill-card.md - No user-facing changes to features or documentation - Version bump to 1.1.4","fileCount":4,"zipByteSize":7638}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s17cjx1a349nz5apaqp02vgz4h85728z:myhotlunchbox-mcp","setupComplexity":"low","setupSteps":["Setup complexity is classified as HIGH. You must provision dedicated cloud infrastructure or an isolated VM. Do not run this directly on your local workstation.","Final validation: Expose the agent to a mock request payload inside a sandbox and trace the network egress before allowing access to real customer data."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-myhotlunchbox-mcp/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-myhotlunchbox-mcp/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-myhotlunchbox-mcp/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-myhotlunchbox-mcp/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-myhotlunchbox-mcp/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-myhotlunchbox-mcp/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-11T03:56:38.041Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-myhotlunchbox-mcp/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-myhotlunchbox-mcp/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-myhotlunchbox-mcp/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-myhotlunchbox-mcp/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"high","updatedAt":"2026-10-11T00:50:03.445Z","emptyReason":null},"readme":"Skill: myhotlunchbox-mcp\n\nOwner: chrischall\n\nSummary: Read and manage a My Hot Lunchbox school-lunch account from a shell with curl — sign in, list students, read the lunch calendar and cart, check orders, deliveries and payments. Use when you want My Hot Lunchbox data without running the MCP server, in a script, or on a machine where the MCP is not installed.\n\nTags: latest:1.2.6\n\nVersion history:\n\nv1.2.6 | 2026-10-09T23:27:01.483Z | auto\n\n- Update documentation in SKILL.md to clarify MCP confirmation behavior and mention the `MCP_CONFIRM_ELICITATION=off` environment variable.\n- Remove redundant skill-card.md file.\n- No changes to actual skill logic; update is documentation-only.\n\nv1.2.5 | 2026-10-07T13:40:04.353Z | auto\n\n- Removed the outdated skill-card.md file.\n- No user-facing changes to commands or documentation.\n\nv1.2.4 | 2026-10-05T02:48:19.953Z | auto\n\n- Removed the sample file skill-card.md.\n- No changes to code or user-facing functionality.\n\nv1.2.3 | 2026-10-03T01:42:48.396Z | auto\n\n- Removed the skill-card.md file.\n- No functional or interface changes to the skill itself.\n- Documentation and usage remain unchanged.\n\nv1.2.2 | 2026-09-30T16:56:52.301Z | auto\n\n- removed 1 file(s).\n- Updated SKILL.md and bundle contents.\n\nv1.2.1 | 2026-09-25T15:50:28.908Z | auto\n\n- Removed the skill-card.md file.\n- No feature or documentation changes; functionality remains unchanged.\n\nv1.2.0 | 2026-09-24T15:13:39.936Z | auto\n\n- Adds a summary of MCP's mutation confirmation feature to documentation.\n- Updates the SKILL.md file to reflect the use of confirmation prompts and tokens in MCP.\n- Removes the obsolete skill-card.md file.\n\nv1.1.4 | 2026-09-23T21:40:12.460Z | auto\n\n- Removed the file: skill-card.md\n- No user-facing changes to features or documentation\n- Version bump to 1.1.4\n\nv1.1.3 | 2026-09-23T15:45:35.147Z | auto\n\n- Removed the skill-card.md file.\n- No functional or user-facing changes; documentation and usage remain the same.\n\nv1.1.2 | 2026-09-21T11:10:24.368Z | auto\n\n- Removed the file skill-card.md.\n- No user-facing feature changes were made in this release.\n\nv1.1.1 | 2026-09-21T04:12:37.767Z | auto\n\n- Removed the skill-card.md file.\n- No changes to functionality or documentation content.\n\nv1.1.0 | 2026-09-20T02:49:45.203Z | auto\n\n- Removed the file skill-card.md.\n- No changes to core functionality or documentation content.\n- This update is internal and does not affect user features or usage.\n\nv1.0.0 | 2026-09-19T11:18:16.021Z | auto\n\n- Removed the skill-card.md file.\n- No user-facing changes were made to functionality or documentation.\n\nv0.5.1 | 2026-09-10T17:50:44.361Z | auto\n\n## myhotlunchbox-mcp 0.5.1\n\n- Removed the file `skill-card.md`.\n- No changes to functionality or usage instructions.\n\nv0.5.0 | 2026-09-04T22:21:44.811Z | auto\n\n- Removed the skill-card.md file.\n- No changes to functionality or documentation in SKILL.md.\n\nv0.4.0 | 2026-09-02T00:16:56.647Z | auto\n\n- Removed the skill-card.md file to streamline the repository.\n- No other changes to functionality or documentation.\n\nv0.3.0 | 2026-08-28T11:35:02.001Z | auto\n\n- Removed the file skill-card.md.\n- No user-facing changes to commands, features, or documentation content.\n- This update is maintenance-only and does not affect functionality.\n\nv0.2.1 | 2026-08-25T14:01:22.600Z | auto\n\n- Documentation update: Removed the redundant skill-card.md file.\n- Updated references/endpoints.md for accuracy and completeness.\n- No feature or interface changes; usage remains the same.\n\nv0.2.0 | 2026-08-24T22:31:39.031Z | auto\n\n- Removed the skill-card.md file.\n- No changes to functionality or documentation in this release.\n\nv0.1.1 | 2026-08-24T21:25:59.711Z | auto\n\n- Documentation updated: references/endpoints.md was changed.\n- No changes to code or user-facing functionality.\n\nv0.1.0 | 2026-08-24T21:01:55.796Z | auto\n\nInitial release of myhotlunchbox-mcp shell skill:\n\n- Enables shell-based management of My Hot Lunchbox accounts using curl and environment variables for credentials.\n- Supports signing in, listing students, reading the lunch calendar, checking cart contents, orders, deliveries, and payments via the My Hot Lunchbox JSON API.\n- Emphasizes safe authentication practices (e.g., avoiding unnecessary retries to prevent lockouts).\n- Provides example shell functions for authentication and common read operations.\n- Notes caveats with API behavior, error handling, and best practices for making changes to orders.\n- Intended for use without the MCP server, or in automation/scripts where GUI tools are unavailable.\n\nArchive index:\n\nArchive v1.2.6: 4 files, 7351 bytes\n\nFiles: references/endpoints.md (7715b), skill-card.md (2044b), SKILL.md (4864b), _meta.json (136b)\n\nFile v1.2.6:SKILL.md\n\n---\nname: myhotlunchbox\ndescription: Read and manage a My Hot Lunchbox school-lunch account from a shell with curl — sign in, list students, read the lunch calendar and cart, check orders, deliveries and payments. Use when you want My Hot Lunchbox data without running the MCP server, in a script, or on a machine where the MCP is not installed.\n---\n\n# My Hot Lunchbox from the shell\n\n`ordernow.myhotlunchbox.com` exposes a plain JSON API behind an OAuth2 password\ngrant. It is reachable server-side — no browser, no extension, no bridge. Two\n`curl` calls get you data: one to sign in, one per read.\n\n## Sign in once per shell\n\nCredentials come from the environment; never paste them into a command line\n(that puts them in shell history).\n\n```sh\nexport MHLB_USER='you@example.com'\nexport MHLB_PASS='…'          # e.g. read -rs MHLB_PASS\nexport MHLB=https://ordernow.myhotlunchbox.com\n\nmhlb_login() {\n  local resp\n  resp=$(curl -sS -X POST \"$MHLB/api/auth/login\" \\\n    -H 'Content-Type: application/x-www-form-urlencoded' \\\n    -H 'Accept: application/json' \\\n    --data-urlencode 'grant_type=password' \\\n    --data-urlencode \"username=$MHLB_USER\" \\\n    --data-urlencode \"password=$MHLB_PASS\" \\\n    --data-urlencode 'scope=openid offline_access email profile roles') || return 1\n  MHLB_TOKEN=$(printf '%s' \"$resp\" | jq -r '.access_token // empty')\n  if [ -z \"$MHLB_TOKEN\" ]; then\n    printf '%s' \"$resp\" | jq -r '.error_description // .error // \"login failed\"' >&2\n    return 1\n  fi\n  export MHLB_TOKEN\n}\n\n# Authenticated GET.  usage: mhlb_get /parent/childrenInfo [curl args…]\nmhlb_get() {\n  local endpoint=$1; shift   # NOT `path`: zsh ties $path to $PATH\n  curl -sS \"$MHLB/api$endpoint\" -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Accept: application/json' \"$@\"\n}\n\nmhlb_login && mhlb_get /auth/userinfo | jq '{name, email, students_count, pending_orders_count, parent_credit_value}'\n```\n\n**A failed sign-in must not be retried.** The server is OpenIddict and counts\nfailed attempts; repeated failures can escalate to a CAPTCHA and remove\nserver-side sign-in for that account entirely. If `invalid_grant` comes back,\nstop and check the credentials.\n\nThe token lasts about an hour. Re-run `mhlb_login` when a call starts returning\n`401`.\n\n## The three reads that answer most questions\n\n```sh\n# Who the students are — the id feeds everything else\nmhlb_get /parent/childrenInfo | jq '.[] | {id, firstName, schoolName, gradeTeacher, isInactive}'\n\n# The lunch calendar for a date range (POST, despite being a read).\n# The fields are `start`/`end`. Using `startDate`/`endDate` returns 200 with an\n# EMPTY events array — a silent wrong answer, not an error.\ncurl -sS -X POST \"$MHLB/api/calendar/studentSchoolData\" \\\n  -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Content-Type: application/json' \\\n  -d '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\"}' | jq '.events[] | {studentId, id, start, className}'\n\n# What is in the cart but not yet paid for\nmhlb_get '/event/shoppingCart' | jq .\n```\n\n`references/endpoints.md` has the rest — deliveries, transactions,\nsubscriptions, gift cards, per-day order detail, and the printable reports.\n\n## Ordering is read-modify-write\n\nThere is no \"add item X\" call. To place or change an order you fetch the model,\nedit it, and post it back whole:\n\n```sh\nmhlb_get '/event/createOrder?eventId=123&studentId=456' > order.json\n# edit quantities in order.json\ncurl -sS -X POST \"$MHLB/api/event/createOrder\" \\\n  -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Content-Type: application/json' \\\n  -d @order.json\n```\n\nAnything missing from the payload is **cleared**, not preserved.\n\n**The write request bodies are unverified** — their paths and verbs were read\nout of the site's own compiled client, but no write has been exercised against a\nlive account. Inspect what you are about to send, and re-read the resource\nafterwards to confirm it landed. A `200` is not proof.\n\n`/payment/checkout` charges a real card. Do not call it speculatively.\n\n## Reading the errors\n\n| Status | Meaning |\n|---|---|\n| `400` + `invalid_grant` | wrong username/password — **do not retry** |\n| `401` on an API call | token expired; run `mhlb_login` again |\n| `403` | the endpoint belongs to the school-admin or vendor role, not a parent |\n| non-JSON `200` | either a `/parentReports/print*` PDF (expected — see references) or the session lapsed into an HTML page |\n| `500` on `/parentReports/printOrders` | usually a caller mistake: empty `studentIds`, or no order matching that date and status |\n\n## Prefer the MCP when it is available\n\n`myhotlunchbox-mcp` wraps all of this with typed tools and a confirmation step\nfor every mutation — a prompt where the client can show one (unless the server\nsets `MCP_CONFIRM_ELICITATION=off`), otherwise a preview plus a single-use\n`confirmToken`.\nUse this skill when the MCP is not installed, or inside a script.\n\nFile v1.2.6:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"myhotlunchbox-mcp\",\n  \"version\": \"1.2.6\",\n  \"publishedAt\": 1791588421483\n}\n\nFile v1.2.6:references/endpoints.md\n\n# My Hot Lunchbox endpoints — ready-to-run\n\nAll paths are relative to `$MHLB/api`. All need `Authorization: Bearer $MHLB_TOKEN`.\nAssumes the `mhlb_get` helper from `SKILL.md` is defined.\n\n## Account\n\n```sh\n# Account claims: name, role, student count, credit balances, subscription state\nmhlb_get /auth/userinfo | jq .\n```\n\n## Students\n\n```sh\nmhlb_get /parent/childrenInfo | jq '.[] | {id, firstName, schoolName, gradeTeacher, hasOrders, isInactive, isInvited}'\n\n# Editable profile for one student (also the model that POST /parent/editChild takes back)\nmhlb_get '/parent/editChild?childId=456' | jq .\n\n# Blank profile + dropdown options for adding a student\nmhlb_get /parent/createChild | jq .\n```\n\n## Calendar and deliveries\n\n```sh\n# Lunch calendar for a range — a POST that reads\nmhlb_post() {\n  local endpoint=$1; shift   # NOT `path`: zsh ties $path to $PATH\n  curl -sS -X POST \"$MHLB/api$endpoint\" -H \"Authorization: Bearer $MHLB_TOKEN\" \\\n    -H 'Content-Type: application/json' -d \"${1:-{\\}}\"\n}\n\n# Fields are `start`/`end` — `startDate`/`endDate` silently returns zero events.\nmhlb_post /calendar/studentSchoolData '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\"}' | jq .\n\n# Events carry the ids the ordering endpoints need:\nmhlb_post /calendar/studentSchoolData '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\"}' \\\n  | jq '.events[] | {studentId, eventId: .id, orderId, date: .start[0:10], className}'\n\n# What one student has on one day\nmhlb_get '/calendar/studentOrderItems?studentId=456&date=2026-09-14' | jq .\n```\n\n`/deliveryInfo/*` and `/calendar/viewMatchedVendors` look parent-facing in the\nsite's compiled client but return **403** for a parent account — they belong to\nthe school and vendor dashboards. Verified live; don't reach for them.\n\n## Cart and menu\n\n```sh\n# Valid filter values first — periods (semesters) and status tabs\nmhlb_get /event/ShoppingCartBaseData | jq '{periods: [.periods[] | {text, value, selected}]}'\n\n# The cart itself; every filter is optional\nmhlb_get '/event/shoppingCart' | jq .\nmhlb_get '/event/shoppingCart?selectedStudentId=456' | jq .\n\n# The orderable menu for a student on a date — vendor, items, sizes, prices, cutoff\nmhlb_get '/event/orderBaseData?studentId=456&eventDate=2026-09-14' | jq .\n```\n\n## Transactions and subscriptions\n\n```sh\nmhlb_get /event/transactionsList              | jq .\nmhlb_get '/event/transactionDetails?id=999' | jq .   # id comes from transactionsList\nmhlb_get /event/subscription                  | jq .\nmhlb_get '/event/upcomingSubscriptions'       | jq .\n```\n\n## Gift cards and coupons\n\n```sh\nmhlb_get /parent/giftCardDataTables | jq .\nmhlb_get /parent/coupon             | jq .\n```\n\n## Printable reports\n\nThese stream a **binary PDF**, not JSON — pipe to a file, never to `jq`. Their\npayloads are not date ranges.\n\n```sh\nmhlb_pdf() {  # usage: mhlb_pdf <endpoint> <json> <out.pdf>\n  curl -sS -X POST \"$MHLB/api$1\" -H \"Authorization: Bearer $MHLB_TOKEN\" \\\n    -H 'Content-Type: application/json' -d \"$2\" -o \"$3\" && file \"$3\"\n}\n\n# Calendar — needs `middle` (the midpoint date, which titles the PDF) and a\n# NON-EMPTY studentIds. There is no \"all students\" default: an empty or omitted\n# list answers 500, same as printOrders.\nmhlb_pdf /parentReports/printCalendar \\\n  '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\",\"middle\":\"2026-09-15\",\"studentIds\":[111627]}' \\\n  'Lunch Calendar.pdf'\n\n# Orders — ONE date, not a range. studentIds must be non-empty.\n# orderStatus: 0 = Pending, 1 = Paid, 2 = Credited.\nmhlb_pdf /parentReports/printOrders \\\n  '{\"orderStatus\":1,\"eventDate\":\"2026-09-14\",\"studentIds\":[111627]}' \\\n  'Orders Details.pdf'\n\n# One transaction receipt — send the record from transactionDetails.\n# (A transactionsList ROW is a different shape and renders a thinner PDF;\n#  the list is only used here to get the id.)\nID=$(mhlb_get /event/transactionsList | jq -r '.transactions[0].id')\nmhlb_get \"/event/transactionDetails?id=$ID\" | jq -c '. + {isCreditType:false}' > tx.json\nmhlb_pdf /parentReports/printTransactions \"$(cat tx.json)\" 'Transaction.pdf'\n```\n\nBoth `printCalendar` and `printOrders` answer **500** — not a 4xx — when\n`studentIds` is empty, and `printOrders` also 500s when no order matches the\ndate and status. Treat a 500 from either as a bad request, not an outage.\n\n`printTransactions` wants the record from `/event/transactionDetails`, **not** a\nrow from `/event/transactionsList` — both render, but they are different shapes\nand different documents. The list is only used to get the id, as the recipe\nabove does.\n\n## Writes — all UNVERIFIED\n\nPaths and verbs are read out of the site's compiled client and are reliable.\nThe **request bodies** have not been exercised against a live account. Fetch the\nmodel, edit it, post it back whole, then re-read to confirm.\n\n| Action | Read the model | Post it back |\n|---|---|---|\n| Place an order | `GET /event/createOrder?eventId=&studentId=` | `POST /event/createOrder` |\n| Change an order | `GET /event/editOrder?orderId=` | `POST /event/editOrder` |\n| Cancel an order | — | `POST /event/deleteOrder` — body below, **not** the order model |\n| Add a student | `GET /parent/createChild` | `POST /parent/createChild` |\n| Edit a student | `GET /parent/editChild?childId=` | `POST /parent/editChild` |\n| Remove a student | — | `POST /parent/deleteChild?id=` |\n| Apply a gift card | — | `POST /parent/applyGiftCard?giftCardCode=` |\n| Apply a coupon | — | `POST /parent/applyCoupon?couponCode=` |\n| Remove the coupon | — | `POST /parent/removeCoupon` |\n| Toggle subscriptions | `GET /event/subscription` | `POST /parent/changeSubscriptionStatus?isEnableSubscription=` |\n| Stop one subscription | `GET /event/upcomingSubscriptions` | `POST /event/unsubcribeOrder` — same body as deleteOrder |\n| Price the cart | — | `POST /payment/initCheckout` |\n| **Pay** | — | `POST /payment/checkout` |\n\n`POST /event/unsubcribeOrder` is spelled that way upstream — the typo is theirs.\n\nCancelling and unsubscribing take a small identifier payload, **not** the order\nmodel that create/edit round-trip. Captured from the site's own `order-mixin`:\n\n```sh\n# isRepeated: true acts on the whole recurring series, not just this date.\nmhlb_post /event/deleteOrder \\\n  '{\"orderId\":17284377,\"eventDate\":\"2026-08-26\",\"studentId\":111627,\"isRepeated\":false,\"isSubscribed\":false}'\n```\n\nCheckout takes `{orderIds, checkoutType, couponCode, giftCardCode, schoolDonations}`,\nwith the nulls sent explicitly, plus `{availableCredits, idempotencyKey, stripeToken}`\non `/payment/checkout`:\n\n```sh\nmhlb_post /payment/initCheckout \\\n  '{\"orderIds\":[123],\"checkoutType\":null,\"couponCode\":null,\"giftCardCode\":null,\"schoolDonations\":null}'\n```\n\nTwo things about paying:\n\n- **`stripeToken` cannot be produced outside a browser.** The site mints it with\n  Stripe.js, and only when paying by a NEW card. Server-side you can only pay\n  with a card already saved on the account.\n- **`idempotencyKey` is yours to generate** — the site uses\n  `\"$(uuidgen | tr A-Z a-z)-$(date +%s000)\"`. Reuse the SAME key when retrying an\n  ambiguous checkout; a fresh one risks a second charge.\n\n`POST /payment/checkout` charges a real payment method. Price with\n`initCheckout` first, read the total it returns, and confirm that figure before\npaying.\n\n## Endpoints a parent account cannot reach\n\nThe same bundle serves school-admin and vendor roles. These return `403` for a\nparent and are listed only so a `403` is not mistaken for a broken session:\n`/school`, `/schoolManagement`, `/schoolOnboarding`, `/vendor`, `/vendorReports`,\n`/schoolVendorReports`, `/item`, `/adminTasks`, `/quickbooks`, `/docusign`,\n`/interactiveDistributionReport`, `/upload`, `/deliveryInfo`, and\n`/calendar/viewMatchedVendors`.\n\nFile v1.2.6:skill-card.md\n\n## Description:\n\nHelps agents access and manage a My Hot Lunchbox school-lunch account using shell commands when the MCP server is unavailable.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nParents and their authorized assistants can check students, lunch calendars, carts, orders, deliveries, and payments, or prepare account changes from a shell without the MCP server.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Account credentials and access tokens are handled by an agent or shell script.\n\nMitigation: Use a trusted environment, keep credentials out of command history, and avoid exposing tokens or account data.\n\nRisk: Raw account-changing commands may alter or clear existing orders; write request bodies have not been verified against a live account.\n\nMitigation: Inspect the complete payload before sending it, confirm each mutation, and read the resource again afterward; prefer the MCP wrapper when available.\n\nRisk: Checkout and subscription actions can cause real charges or account changes.\n\nMitigation: Check prices and totals manually, obtain explicit approval, and never call checkout speculatively.\n\n## Reference(s):\n\n- [ClawHub skill release](https://clawhub.ai/chrischall/skills/myhotlunchbox-mcp)\n- [My Hot Lunchbox endpoint reference](artifact/references/endpoints.md)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, Guidance]\n\n**Output Format:** [Markdown with shell command examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Commands can retrieve JSON account data or save PDF reports.]\n\n## Skill Version(s):\n\n1.2.6 (source: ClawHub release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.2.5: 4 files, 7278 bytes\n\nFiles: references/endpoints.md (7715b), skill-card.md (2077b), SKILL.md (4772b), _meta.json (136b)\n\nFile v1.2.5:SKILL.md\n\n---\nname: myhotlunchbox\ndescription: Read and manage a My Hot Lunchbox school-lunch account from a shell with curl — sign in, list students, read the lunch calendar and cart, check orders, deliveries and payments. Use when you want My Hot Lunchbox data without running the MCP server, in a script, or on a machine where the MCP is not installed.\n---\n\n# My Hot Lunchbox from the shell\n\n`ordernow.myhotlunchbox.com` exposes a plain JSON API behind an OAuth2 password\ngrant. It is reachable server-side — no browser, no extension, no bridge. Two\n`curl` calls get you data: one to sign in, one per read.\n\n## Sign in once per shell\n\nCredentials come from the environment; never paste them into a command line\n(that puts them in shell history).\n\n```sh\nexport MHLB_USER='you@example.com'\nexport MHLB_PASS='…'          # e.g. read -rs MHLB_PASS\nexport MHLB=https://ordernow.myhotlunchbox.com\n\nmhlb_login() {\n  local resp\n  resp=$(curl -sS -X POST \"$MHLB/api/auth/login\" \\\n    -H 'Content-Type: application/x-www-form-urlencoded' \\\n    -H 'Accept: application/json' \\\n    --data-urlencode 'grant_type=password' \\\n    --data-urlencode \"username=$MHLB_USER\" \\\n    --data-urlencode \"password=$MHLB_PASS\" \\\n    --data-urlencode 'scope=openid offline_access email profile roles') || return 1\n  MHLB_TOKEN=$(printf '%s' \"$resp\" | jq -r '.access_token // empty')\n  if [ -z \"$MHLB_TOKEN\" ]; then\n    printf '%s' \"$resp\" | jq -r '.error_description // .error // \"login failed\"' >&2\n    return 1\n  fi\n  export MHLB_TOKEN\n}\n\n# Authenticated GET.  usage: mhlb_get /parent/childrenInfo [curl args…]\nmhlb_get() {\n  local endpoint=$1; shift   # NOT `path`: zsh ties $path to $PATH\n  curl -sS \"$MHLB/api$endpoint\" -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Accept: application/json' \"$@\"\n}\n\nmhlb_login && mhlb_get /auth/userinfo | jq '{name, email, students_count, pending_orders_count, parent_credit_value}'\n```\n\n**A failed sign-in must not be retried.** The server is OpenIddict and counts\nfailed attempts; repeated failures can escalate to a CAPTCHA and remove\nserver-side sign-in for that account entirely. If `invalid_grant` comes back,\nstop and check the credentials.\n\nThe token lasts about an hour. Re-run `mhlb_login` when a call starts returning\n`401`.\n\n## The three reads that answer most questions\n\n```sh\n# Who the students are — the id feeds everything else\nmhlb_get /parent/childrenInfo | jq '.[] | {id, firstName, schoolName, gradeTeacher, isInactive}'\n\n# The lunch calendar for a date range (POST, despite being a read).\n# The fields are `start`/`end`. Using `startDate`/`endDate` returns 200 with an\n# EMPTY events array — a silent wrong answer, not an error.\ncurl -sS -X POST \"$MHLB/api/calendar/studentSchoolData\" \\\n  -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Content-Type: application/json' \\\n  -d '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\"}' | jq '.events[] | {studentId, id, start, className}'\n\n# What is in the cart but not yet paid for\nmhlb_get '/event/shoppingCart' | jq .\n```\n\n`references/endpoints.md` has the rest — deliveries, transactions,\nsubscriptions, gift cards, per-day order detail, and the printable reports.\n\n## Ordering is read-modify-write\n\nThere is no \"add item X\" call. To place or change an order you fetch the model,\nedit it, and post it back whole:\n\n```sh\nmhlb_get '/event/createOrder?eventId=123&studentId=456' > order.json\n# edit quantities in order.json\ncurl -sS -X POST \"$MHLB/api/event/createOrder\" \\\n  -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Content-Type: application/json' \\\n  -d @order.json\n```\n\nAnything missing from the payload is **cleared**, not preserved.\n\n**The write request bodies are unverified** — their paths and verbs were read\nout of the site's own compiled client, but no write has been exercised against a\nlive account. Inspect what you are about to send, and re-read the resource\nafterwards to confirm it landed. A `200` is not proof.\n\n`/payment/checkout` charges a real card. Do not call it speculatively.\n\n## Reading the errors\n\n| Status | Meaning |\n|---|---|\n| `400` + `invalid_grant` | wrong username/password — **do not retry** |\n| `401` on an API call | token expired; run `mhlb_login` again |\n| `403` | the endpoint belongs to the school-admin or vendor role, not a parent |\n| non-JSON `200` | either a `/parentReports/print*` PDF (expected — see references) or the session lapsed into an HTML page |\n| `500` on `/parentReports/printOrders` | usually a caller mistake: empty `studentIds`, or no order matching that date and status |\n\n## Prefer the MCP when it is available\n\n`myhotlunchbox-mcp` wraps all of this with typed tools and a confirmation step\nfor every mutation — a prompt, or a preview plus a single-use `confirmToken`.\nUse this skill when the MCP is not installed, or inside a script.\n\nFile v1.2.5:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"myhotlunchbox-mcp\",\n  \"version\": \"1.2.5\",\n  \"publishedAt\": 1791380404353\n}\n\nFile v1.2.5:references/endpoints.md\n\n# My Hot Lunchbox endpoints — ready-to-run\n\nAll paths are relative to `$MHLB/api`. All need `Authorization: Bearer $MHLB_TOKEN`.\nAssumes the `mhlb_get` helper from `SKILL.md` is defined.\n\n## Account\n\n```sh\n# Account claims: name, role, student count, credit balances, subscription state\nmhlb_get /auth/userinfo | jq .\n```\n\n## Students\n\n```sh\nmhlb_get /parent/childrenInfo | jq '.[] | {id, firstName, schoolName, gradeTeacher, hasOrders, isInactive, isInvited}'\n\n# Editable profile for one student (also the model that POST /parent/editChild takes back)\nmhlb_get '/parent/editChild?childId=456' | jq .\n\n# Blank profile + dropdown options for adding a student\nmhlb_get /parent/createChild | jq .\n```\n\n## Calendar and deliveries\n\n```sh\n# Lunch calendar for a range — a POST that reads\nmhlb_post() {\n  local endpoint=$1; shift   # NOT `path`: zsh ties $path to $PATH\n  curl -sS -X POST \"$MHLB/api$endpoint\" -H \"Authorization: Bearer $MHLB_TOKEN\" \\\n    -H 'Content-Type: application/json' -d \"${1:-{\\}}\"\n}\n\n# Fields are `start`/`end` — `startDate`/`endDate` silently returns zero events.\nmhlb_post /calendar/studentSchoolData '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\"}' | jq .\n\n# Events carry the ids the ordering endpoints need:\nmhlb_post /calendar/studentSchoolData '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\"}' \\\n  | jq '.events[] | {studentId, eventId: .id, orderId, date: .start[0:10], className}'\n\n# What one student has on one day\nmhlb_get '/calendar/studentOrderItems?studentId=456&date=2026-09-14' | jq .\n```\n\n`/deliveryInfo/*` and `/calendar/viewMatchedVendors` look parent-facing in the\nsite's compiled client but return **403** for a parent account — they belong to\nthe school and vendor dashboards. Verified live; don't reach for them.\n\n## Cart and menu\n\n```sh\n# Valid filter values first — periods (semesters) and status tabs\nmhlb_get /event/ShoppingCartBaseData | jq '{periods: [.periods[] | {text, value, selected}]}'\n\n# The cart itself; every filter is optional\nmhlb_get '/event/shoppingCart' | jq .\nmhlb_get '/event/shoppingCart?selectedStudentId=456' | jq .\n\n# The orderable menu for a student on a date — vendor, items, sizes, prices, cutoff\nmhlb_get '/event/orderBaseData?studentId=456&eventDate=2026-09-14' | jq .\n```\n\n## Transactions and subscriptions\n\n```sh\nmhlb_get /event/transactionsList              | jq .\nmhlb_get '/event/transactionDetails?id=999' | jq .   # id comes from transactionsList\nmhlb_get /event/subscription                  | jq .\nmhlb_get '/event/upcomingSubscriptions'       | jq .\n```\n\n## Gift cards and coupons\n\n```sh\nmhlb_get /parent/giftCardDataTables | jq .\nmhlb_get /parent/coupon             | jq .\n```\n\n## Printable reports\n\nThese stream a **binary PDF**, not JSON — pipe to a file, never to `jq`. Their\npayloads are not date ranges.\n\n```sh\nmhlb_pdf() {  # usage: mhlb_pdf <endpoint> <json> <out.pdf>\n  curl -sS -X POST \"$MHLB/api$1\" -H \"Authorization: Bearer $MHLB_TOKEN\" \\\n    -H 'Content-Type: application/json' -d \"$2\" -o \"$3\" && file \"$3\"\n}\n\n# Calendar — needs `middle` (the midpoint date, which titles the PDF) and a\n# NON-EMPTY studentIds. There is no \"all students\" default: an empty or omitted\n# list answers 500, same as printOrders.\nmhlb_pdf /parentReports/printCalendar \\\n  '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\",\"middle\":\"2026-09-15\",\"studentIds\":[111627]}' \\\n  'Lunch Calendar.pdf'\n\n# Orders — ONE date, not a range. studentIds must be non-empty.\n# orderStatus: 0 = Pending, 1 = Paid, 2 = Credited.\nmhlb_pdf /parentReports/printOrders \\\n  '{\"orderStatus\":1,\"eventDate\":\"2026-09-14\",\"studentIds\":[111627]}' \\\n  'Orders Details.pdf'\n\n# One transaction receipt — send the record from transactionDetails.\n# (A transactionsList ROW is a different shape and renders a thinner PDF;\n#  the list is only used here to get the id.)\nID=$(mhlb_get /event/transactionsList | jq -r '.transactions[0].id')\nmhlb_get \"/event/transactionDetails?id=$ID\" | jq -c '. + {isCreditType:false}' > tx.json\nmhlb_pdf /parentReports/printTransactions \"$(cat tx.json)\" 'Transaction.pdf'\n```\n\nBoth `printCalendar` and `printOrders` answer **500** — not a 4xx — when\n`studentIds` is empty, and `printOrders` also 500s when no order matches the\ndate and status. Treat a 500 from either as a bad request, not an outage.\n\n`printTransactions` wants the record from `/event/transactionDetails`, **not** a\nrow from `/event/transactionsList` — both render, but they are different shapes\nand different documents. The list is only used to get the id, as the recipe\nabove does.\n\n## Writes — all UNVERIFIED\n\nPaths and verbs are read out of the site's compiled client and are reliable.\nThe **request bodies** have not been exercised against a live account. Fetch the\nmodel, edit it, post it back whole, then re-read to confirm.\n\n| Action | Read the model | Post it back |\n|---|---|---|\n| Place an order | `GET /event/createOrder?eventId=&studentId=` | `POST /event/createOrder` |\n| Change an order | `GET /event/editOrder?orderId=` | `POST /event/editOrder` |\n| Cancel an order | — | `POST /event/deleteOrder` — body below, **not** the order model |\n| Add a student | `GET /parent/createChild` | `POST /parent/createChild` |\n| Edit a student | `GET /parent/editChild?childId=` | `POST /parent/editChild` |\n| Remove a student | — | `POST /parent/deleteChild?id=` |\n| Apply a gift card | — | `POST /parent/applyGiftCard?giftCardCode=` |\n| Apply a coupon | — | `POST /parent/applyCoupon?couponCode=` |\n| Remove the coupon | — | `POST /parent/removeCoupon` |\n| Toggle subscriptions | `GET /event/subscription` | `POST /parent/changeSubscriptionStatus?isEnableSubscription=` |\n| Stop one subscription | `GET /event/upcomingSubscriptions` | `POST /event/unsubcribeOrder` — same body as deleteOrder |\n| Price the cart | — | `POST /payment/initCheckout` |\n| **Pay** | — | `POST /payment/checkout` |\n\n`POST /event/unsubcribeOrder` is spelled that way upstream — the typo is theirs.\n\nCancelling and unsubscribing take a small identifier payload, **not** the order\nmodel that create/edit round-trip. Captured from the site's own `order-mixin`:\n\n```sh\n# isRepeated: true acts on the whole recurring series, not just this date.\nmhlb_post /event/deleteOrder \\\n  '{\"orderId\":17284377,\"eventDate\":\"2026-08-26\",\"studentId\":111627,\"isRepeated\":false,\"isSubscribed\":false}'\n```\n\nCheckout takes `{orderIds, checkoutType, couponCode, giftCardCode, schoolDonations}`,\nwith the nulls sent explicitly, plus `{availableCredits, idempotencyKey, stripeToken}`\non `/payment/checkout`:\n\n```sh\nmhlb_post /payment/initCheckout \\\n  '{\"orderIds\":[123],\"checkoutType\":null,\"couponCode\":null,\"giftCardCode\":null,\"schoolDonations\":null}'\n```\n\nTwo things about paying:\n\n- **`stripeToken` cannot be produced outside a browser.** The site mints it with\n  Stripe.js, and only when paying by a NEW card. Server-side you can only pay\n  with a card already saved on the account.\n- **`idempotencyKey` is yours to generate** — the site uses\n  `\"$(uuidgen | tr A-Z a-z)-$(date +%s000)\"`. Reuse the SAME key when retrying an\n  ambiguous checkout; a fresh one risks a second charge.\n\n`POST /payment/checkout` charges a real payment method. Price with\n`initCheckout` first, read the total it returns, and confirm that figure before\npaying.\n\n## Endpoints a parent account cannot reach\n\nThe same bundle serves school-admin and vendor roles. These return `403` for a\nparent and are listed only so a `403` is not mistaken for a broken session:\n`/school`, `/schoolManagement`, `/schoolOnboarding`, `/vendor`, `/vendorReports`,\n`/schoolVendorReports`, `/item`, `/adminTasks`, `/quickbooks`, `/docusign`,\n`/interactiveDistributionReport`, `/upload`, `/deliveryInfo`, and\n`/calendar/viewMatchedVendors`.\n\nFile v1.2.5:skill-card.md\n\n## Description:\n\nGuides agents through reading and managing a My Hot Lunchbox school-lunch account using shell commands when the MCP server is unavailable.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nAccount holders and developers use this skill to inspect students, calendars, orders, and payments, or to manage lunch orders from a shell when the MCP server is unavailable.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Live order and account changes have no enforced confirmation step in these shell commands.\n\nMitigation: Require explicit user direction, inspect each request body, and prefer the MCP version with confirmation gates when available.\n\nRisk: Incomplete order payloads may clear existing items, and deletion or cancellation changes account state.\n\nMitigation: Review the full payload before sending; never delete or cancel speculatively, and re-read the resource afterward.\n\nRisk: Checkout can charge a saved payment method, including an accidental duplicate charge on retry.\n\nMitigation: Confirm the priced total and user authorization before paying; reuse the same idempotency key for an ambiguous retry.\n\n## Reference(s):\n\n- [My Hot Lunchbox endpoint guide](references/endpoints.md)\n- [ClawHub skill release](https://clawhub.ai/chrischall/skills/myhotlunchbox-mcp)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, Guidance]\n\n**Output Format:** [Markdown with shell commands and JSON request examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Commands may read account data or modify live orders, student details, and payments.]\n\n## Skill Version(s):\n\n1.2.5 (source: server-resolved release)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.2.4: 4 files, 7367 bytes\n\nFiles: references/endpoints.md (7715b), skill-card.md (2226b), SKILL.md (4772b), _meta.json (136b)\n\nFile v1.2.4:SKILL.md\n\n---\nname: myhotlunchbox\ndescription: Read and manage a My Hot Lunchbox school-lunch account from a shell with curl — sign in, list students, read the lunch calendar and cart, check orders, deliveries and payments. Use when you want My Hot Lunchbox data without running the MCP server, in a script, or on a machine where the MCP is not installed.\n---\n\n# My Hot Lunchbox from the shell\n\n`ordernow.myhotlunchbox.com` exposes a plain JSON API behind an OAuth2 password\ngrant. It is reachable server-side — no browser, no extension, no bridge. Two\n`curl` calls get you data: one to sign in, one per read.\n\n## Sign in once per shell\n\nCredentials come from the environment; never paste them into a command line\n(that puts them in shell history).\n\n```sh\nexport MHLB_USER='you@example.com'\nexport MHLB_PASS='…'          # e.g. read -rs MHLB_PASS\nexport MHLB=https://ordernow.myhotlunchbox.com\n\nmhlb_login() {\n  local resp\n  resp=$(curl -sS -X POST \"$MHLB/api/auth/login\" \\\n    -H 'Content-Type: application/x-www-form-urlencoded' \\\n    -H 'Accept: application/json' \\\n    --data-urlencode 'grant_type=password' \\\n    --data-urlencode \"username=$MHLB_USER\" \\\n    --data-urlencode \"password=$MHLB_PASS\" \\\n    --data-urlencode 'scope=openid offline_access email profile roles') || return 1\n  MHLB_TOKEN=$(printf '%s' \"$resp\" | jq -r '.access_token // empty')\n  if [ -z \"$MHLB_TOKEN\" ]; then\n    printf '%s' \"$resp\" | jq -r '.error_description // .error // \"login failed\"' >&2\n    return 1\n  fi\n  export MHLB_TOKEN\n}\n\n# Authenticated GET.  usage: mhlb_get /parent/childrenInfo [curl args…]\nmhlb_get() {\n  local endpoint=$1; shift   # NOT `path`: zsh ties $path to $PATH\n  curl -sS \"$MHLB/api$endpoint\" -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Accept: application/json' \"$@\"\n}\n\nmhlb_login && mhlb_get /auth/userinfo | jq '{name, email, students_count, pending_orders_count, parent_credit_value}'\n```\n\n**A failed sign-in must not be retried.** The server is OpenIddict and counts\nfailed attempts; repeated failures can escalate to a CAPTCHA and remove\nserver-side sign-in for that account entirely. If `invalid_grant` comes back,\nstop and check the credentials.\n\nThe token lasts about an hour. Re-run `mhlb_login` when a call starts returning\n`401`.\n\n## The three reads that answer most questions\n\n```sh\n# Who the students are — the id feeds everything else\nmhlb_get /parent/childrenInfo | jq '.[] | {id, firstName, schoolName, gradeTeacher, isInactive}'\n\n# The lunch calendar for a date range (POST, despite being a read).\n# The fields are `start`/`end`. Using `startDate`/`endDate` returns 200 with an\n# EMPTY events array — a silent wrong answer, not an error.\ncurl -sS -X POST \"$MHLB/api/calendar/studentSchoolData\" \\\n  -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Content-Type: application/json' \\\n  -d '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\"}' | jq '.events[] | {studentId, id, start, className}'\n\n# What is in the cart but not yet paid for\nmhlb_get '/event/shoppingCart' | jq .\n```\n\n`references/endpoints.md` has the rest — deliveries, transactions,\nsubscriptions, gift cards, per-day order detail, and the printable reports.\n\n## Ordering is read-modify-write\n\nThere is no \"add item X\" call. To place or change an order you fetch the model,\nedit it, and post it back whole:\n\n```sh\nmhlb_get '/event/createOrder?eventId=123&studentId=456' > order.json\n# edit quantities in order.json\ncurl -sS -X POST \"$MHLB/api/event/createOrder\" \\\n  -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Content-Type: application/json' \\\n  -d @order.json\n```\n\nAnything missing from the payload is **cleared**, not preserved.\n\n**The write request bodies are unverified** — their paths and verbs were read\nout of the site's own compiled client, but no write has been exercised against a\nlive account. Inspect what you are about to send, and re-read the resource\nafterwards to confirm it landed. A `200` is not proof.\n\n`/payment/checkout` charges a real card. Do not call it speculatively.\n\n## Reading the errors\n\n| Status | Meaning |\n|---|---|\n| `400` + `invalid_grant` | wrong username/password — **do not retry** |\n| `401` on an API call | token expired; run `mhlb_login` again |\n| `403` | the endpoint belongs to the school-admin or vendor role, not a parent |\n| non-JSON `200` | either a `/parentReports/print*` PDF (expected — see references) or the session lapsed into an HTML page |\n| `500` on `/parentReports/printOrders` | usually a caller mistake: empty `studentIds`, or no order matching that date and status |\n\n## Prefer the MCP when it is available\n\n`myhotlunchbox-mcp` wraps all of this with typed tools and a confirmation step\nfor every mutation — a prompt, or a preview plus a single-use `confirmToken`.\nUse this skill when the MCP is not installed, or inside a script.\n\nFile v1.2.4:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"myhotlunchbox-mcp\",\n  \"version\": \"1.2.4\",\n  \"publishedAt\": 1791168499953\n}\n\nFile v1.2.4:references/endpoints.md\n\n# My Hot Lunchbox endpoints — ready-to-run\n\nAll paths are relative to `$MHLB/api`. All need `Authorization: Bearer $MHLB_TOKEN`.\nAssumes the `mhlb_get` helper from `SKILL.md` is defined.\n\n## Account\n\n```sh\n# Account claims: name, role, student count, credit balances, subscription state\nmhlb_get /auth/userinfo | jq .\n```\n\n## Students\n\n```sh\nmhlb_get /parent/childrenInfo | jq '.[] | {id, firstName, schoolName, gradeTeacher, hasOrders, isInactive, isInvited}'\n\n# Editable profile for one student (also the model that POST /parent/editChild takes back)\nmhlb_get '/parent/editChild?childId=456' | jq .\n\n# Blank profile + dropdown options for adding a student\nmhlb_get /parent/createChild | jq .\n```\n\n## Calendar and deliveries\n\n```sh\n# Lunch calendar for a range — a POST that reads\nmhlb_post() {\n  local endpoint=$1; shift   # NOT `path`: zsh ties $path to $PATH\n  curl -sS -X POST \"$MHLB/api$endpoint\" -H \"Authorization: Bearer $MHLB_TOKEN\" \\\n    -H 'Content-Type: application/json' -d \"${1:-{\\}}\"\n}\n\n# Fields are `start`/`end` — `startDate`/`endDate` silently returns zero events.\nmhlb_post /calendar/studentSchoolData '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\"}' | jq .\n\n# Events carry the ids the ordering endpoints need:\nmhlb_post /calendar/studentSchoolData '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\"}' \\\n  | jq '.events[] | {studentId, eventId: .id, orderId, date: .start[0:10], className}'\n\n# What one student has on one day\nmhlb_get '/calendar/studentOrderItems?studentId=456&date=2026-09-14' | jq .\n```\n\n`/deliveryInfo/*` and `/calendar/viewMatchedVendors` look parent-facing in the\nsite's compiled client but return **403** for a parent account — they belong to\nthe school and vendor dashboards. Verified live; don't reach for them.\n\n## Cart and menu\n\n```sh\n# Valid filter values first — periods (semesters) and status tabs\nmhlb_get /event/ShoppingCartBaseData | jq '{periods: [.periods[] | {text, value, selected}]}'\n\n# The cart itself; every filter is optional\nmhlb_get '/event/shoppingCart' | jq .\nmhlb_get '/event/shoppingCart?selectedStudentId=456' | jq .\n\n# The orderable menu for a student on a date — vendor, items, sizes, prices, cutoff\nmhlb_get '/event/orderBaseData?studentId=456&eventDate=2026-09-14' | jq .\n```\n\n## Transactions and subscriptions\n\n```sh\nmhlb_get /event/transactionsList              | jq .\nmhlb_get '/event/transactionDetails?id=999' | jq .   # id comes from transactionsList\nmhlb_get /event/subscription                  | jq .\nmhlb_get '/event/upcomingSubscriptions'       | jq .\n```\n\n## Gift cards and coupons\n\n```sh\nmhlb_get /parent/giftCardDataTables | jq .\nmhlb_get /parent/coupon             | jq .\n```\n\n## Printable reports\n\nThese stream a **binary PDF**, not JSON — pipe to a file, never to `jq`. Their\npayloads are not date ranges.\n\n```sh\nmhlb_pdf() {  # usage: mhlb_pdf <endpoint> <json> <out.pdf>\n  curl -sS -X POST \"$MHLB/api$1\" -H \"Authorization: Bearer $MHLB_TOKEN\" \\\n    -H 'Content-Type: application/json' -d \"$2\" -o \"$3\" && file \"$3\"\n}\n\n# Calendar — needs `middle` (the midpoint date, which titles the PDF) and a\n# NON-EMPTY studentIds. There is no \"all students\" default: an empty or omitted\n# list answers 500, same as printOrders.\nmhlb_pdf /parentReports/printCalendar \\\n  '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\",\"middle\":\"2026-09-15\",\"studentIds\":[111627]}' \\\n  'Lunch Calendar.pdf'\n\n# Orders — ONE date, not a range. studentIds must be non-empty.\n# orderStatus: 0 = Pending, 1 = Paid, 2 = Credited.\nmhlb_pdf /parentReports/printOrders \\\n  '{\"orderStatus\":1,\"eventDate\":\"2026-09-14\",\"studentIds\":[111627]}' \\\n  'Orders Details.pdf'\n\n# One transaction receipt — send the record from transactionDetails.\n# (A transactionsList ROW is a different shape and renders a thinner PDF;\n#  the list is only used here to get the id.)\nID=$(mhlb_get /event/transactionsList | jq -r '.transactions[0].id')\nmhlb_get \"/event/transactionDetails?id=$ID\" | jq -c '. + {isCreditType:false}' > tx.json\nmhlb_pdf /parentReports/printTransactions \"$(cat tx.json)\" 'Transaction.pdf'\n```\n\nBoth `printCalendar` and `printOrders` answer **500** — not a 4xx — when\n`studentIds` is empty, and `printOrders` also 500s when no order matches the\ndate and status. Treat a 500 from either as a bad request, not an outage.\n\n`printTransactions` wants the record from `/event/transactionDetails`, **not** a\nrow from `/event/transactionsList` — both render, but they are different shapes\nand different documents. The list is only used to get the id, as the recipe\nabove does.\n\n## Writes — all UNVERIFIED\n\nPaths and verbs are read out of the site's compiled client and are reliable.\nThe **request bodies** have not been exercised against a live account. Fetch the\nmodel, edit it, post it back whole, then re-read to confirm.\n\n| Action | Read the model | Post it back |\n|---|---|---|\n| Place an order | `GET /event/createOrder?eventId=&studentId=` | `POST /event/createOrder` |\n| Change an order | `GET /event/editOrder?orderId=` | `POST /event/editOrder` |\n| Cancel an order | — | `POST /event/deleteOrder` — body below, **not** the order model |\n| Add a student | `GET /parent/createChild` | `POST /parent/createChild` |\n| Edit a student | `GET /parent/editChild?childId=` | `POST /parent/editChild` |\n| Remove a student | — | `POST /parent/deleteChild?id=` |\n| Apply a gift card | — | `POST /parent/applyGiftCard?giftCardCode=` |\n| Apply a coupon | — | `POST /parent/applyCoupon?couponCode=` |\n| Remove the coupon | — | `POST /parent/removeCoupon` |\n| Toggle subscriptions | `GET /event/subscription` | `POST /parent/changeSubscriptionStatus?isEnableSubscription=` |\n| Stop one subscription | `GET /event/upcomingSubscriptions` | `POST /event/unsubcribeOrder` — same body as deleteOrder |\n| Price the cart | — | `POST /payment/initCheckout` |\n| **Pay** | — | `POST /payment/checkout` |\n\n`POST /event/unsubcribeOrder` is spelled that way upstream — the typo is theirs.\n\nCancelling and unsubscribing take a small identifier payload, **not** the order\nmodel that create/edit round-trip. Captured from the site's own `order-mixin`:\n\n```sh\n# isRepeated: true acts on the whole recurring series, not just this date.\nmhlb_post /event/deleteOrder \\\n  '{\"orderId\":17284377,\"eventDate\":\"2026-08-26\",\"studentId\":111627,\"isRepeated\":false,\"isSubscribed\":false}'\n```\n\nCheckout takes `{orderIds, checkoutType, couponCode, giftCardCode, schoolDonations}`,\nwith the nulls sent explicitly, plus `{availableCredits, idempotencyKey, stripeToken}`\non `/payment/checkout`:\n\n```sh\nmhlb_post /payment/initCheckout \\\n  '{\"orderIds\":[123],\"checkoutType\":null,\"couponCode\":null,\"giftCardCode\":null,\"schoolDonations\":null}'\n```\n\nTwo things about paying:\n\n- **`stripeToken` cannot be produced outside a browser.** The site mints it with\n  Stripe.js, and only when paying by a NEW card. Server-side you can only pay\n  with a card already saved on the account.\n- **`idempotencyKey` is yours to generate** — the site uses\n  `\"$(uuidgen | tr A-Z a-z)-$(date +%s000)\"`. Reuse the SAME key when retrying an\n  ambiguous checkout; a fresh one risks a second charge.\n\n`POST /payment/checkout` charges a real payment method. Price with\n`initCheckout` first, read the total it returns, and confirm that figure before\npaying.\n\n## Endpoints a parent account cannot reach\n\nThe same bundle serves school-admin and vendor roles. These return `403` for a\nparent and are listed only so a `403` is not mistaken for a broken session:\n`/school`, `/schoolManagement`, `/schoolOnboarding`, `/vendor`, `/vendorReports`,\n`/schoolVendorReports`, `/item`, `/adminTasks`, `/quickbooks`, `/docusign`,\n`/interactiveDistributionReport`, `/upload`, `/deliveryInfo`, and\n`/calendar/viewMatchedVendors`.\n\nFile v1.2.4:skill-card.md\n\n## Description:\n\nGuides agents in using shell commands to read and manage a My Hot Lunchbox school-lunch account without the MCP server.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nMy Hot Lunchbox account holders and developers can use this skill to inspect students, lunch calendars, carts, orders, and payments from a shell when the MCP server is unavailable, and to prepare carefully reviewed account changes.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Credentials or account data may be exposed when running manual account commands.\n\nMitigation: Keep credentials in environment variables, avoid logging tokens or sensitive responses, and use only trusted machines.\n\nRisk: Incorrect or incomplete write requests can change orders, profiles, and subscriptions unexpectedly.\n\nMitigation: Inspect the complete JSON body before posting and re-read the affected resource afterwards; prefer the MCP version's confirmation steps when available.\n\nRisk: Speculative payment requests can charge a real card.\n\nMitigation: Check the priced total and obtain explicit confirmation before checkout; do not issue speculative payment calls.\n\nRisk: Repeated failed sign-ins can restrict account access.\n\nMitigation: Do not retry an invalid-grant response; verify credentials before signing in again.\n\n## Reference(s):\n\n- [ClawHub skill release](https://clawhub.ai/chrischall/skills/myhotlunchbox-mcp)\n- [Endpoint reference](references/endpoints.md)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, Guidance]\n\n**Output Format:** [Text or Markdown with shell examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Commands can retrieve JSON account data or PDF reports; account-changing requests require review.]\n\n## Skill Version(s):\n\n1.2.4 (source: ClawHub release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.2.3: 4 files, 7253 bytes\n\nFiles: references/endpoints.md (7715b), skill-card.md (2053b), SKILL.md (4772b), _meta.json (136b)\n\nFile v1.2.3:SKILL.md\n\n---\nname: myhotlunchbox\ndescription: Read and manage a My Hot Lunchbox school-lunch account from a shell with curl — sign in, list students, read the lunch calendar and cart, check orders, deliveries and payments. Use when you want My Hot Lunchbox data without running the MCP server, in a script, or on a machine where the MCP is not installed.\n---\n\n# My Hot Lunchbox from the shell\n\n`ordernow.myhotlunchbox.com` exposes a plain JSON API behind an OAuth2 password\ngrant. It is reachable server-side — no browser, no extension, no bridge. Two\n`curl` calls get you data: one to sign in, one per read.\n\n## Sign in once per shell\n\nCredentials come from the environment; never paste them into a command line\n(that puts them in shell history).\n\n```sh\nexport MHLB_USER='you@example.com'\nexport MHLB_PASS='…'          # e.g. read -rs MHLB_PASS\nexport MHLB=https://ordernow.myhotlunchbox.com\n\nmhlb_login() {\n  local resp\n  resp=$(curl -sS -X POST \"$MHLB/api/auth/login\" \\\n    -H 'Content-Type: application/x-www-form-urlencoded' \\\n    -H 'Accept: application/json' \\\n    --data-urlencode 'grant_type=password' \\\n    --data-urlencode \"username=$MHLB_USER\" \\\n    --data-urlencode \"password=$MHLB_PASS\" \\\n    --data-urlencode 'scope=openid offline_access email profile roles') || return 1\n  MHLB_TOKEN=$(printf '%s' \"$resp\" | jq -r '.access_token // empty')\n  if [ -z \"$MHLB_TOKEN\" ]; then\n    printf '%s' \"$resp\" | jq -r '.error_description // .error // \"login failed\"' >&2\n    return 1\n  fi\n  export MHLB_TOKEN\n}\n\n# Authenticated GET.  usage: mhlb_get /parent/childrenInfo [curl args…]\nmhlb_get() {\n  local endpoint=$1; shift   # NOT `path`: zsh ties $path to $PATH\n  curl -sS \"$MHLB/api$endpoint\" -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Accept: application/json' \"$@\"\n}\n\nmhlb_login && mhlb_get /auth/userinfo | jq '{name, email, students_count, pending_orders_count, parent_credit_value}'\n```\n\n**A failed sign-in must not be retried.** The server is OpenIddict and counts\nfailed attempts; repeated failures can escalate to a CAPTCHA and remove\nserver-side sign-in for that account entirely. If `invalid_grant` comes back,\nstop and check the credentials.\n\nThe token lasts about an hour. Re-run `mhlb_login` when a call starts returning\n`401`.\n\n## The three reads that answer most questions\n\n```sh\n# Who the students are — the id feeds everything else\nmhlb_get /parent/childrenInfo | jq '.[] | {id, firstName, schoolName, gradeTeacher, isInactive}'\n\n# The lunch calendar for a date range (POST, despite being a read).\n# The fields are `start`/`end`. Using `startDate`/`endDate` returns 200 with an\n# EMPTY events array — a silent wrong answer, not an error.\ncurl -sS -X POST \"$MHLB/api/calendar/studentSchoolData\" \\\n  -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Content-Type: application/json' \\\n  -d '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\"}' | jq '.events[] | {studentId, id, start, className}'\n\n# What is in the cart but not yet paid for\nmhlb_get '/event/shoppingCart' | jq .\n```\n\n`references/endpoints.md` has the rest — deliveries, transactions,\nsubscriptions, gift cards, per-day order detail, and the printable reports.\n\n## Ordering is read-modify-write\n\nThere is no \"add item X\" call. To place or change an order you fetch the model,\nedit it, and post it back whole:\n\n```sh\nmhlb_get '/event/createOrder?eventId=123&studentId=456' > order.json\n# edit quantities in order.json\ncurl -sS -X POST \"$MHLB/api/event/createOrder\" \\\n  -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Content-Type: application/json' \\\n  -d @order.json\n```\n\nAnything missing from the payload is **cleared**, not preserved.\n\n**The write request bodies are unverified** — their paths and verbs were read\nout of the site's own compiled client, but no write has been exercised against a\nlive account. Inspect what you are about to send, and re-read the resource\nafterwards to confirm it landed. A `200` is not proof.\n\n`/payment/checkout` charges a real card. Do not call it speculatively.\n\n## Reading the errors\n\n| Status | Meaning |\n|---|---|\n| `400` + `invalid_grant` | wrong username/password — **do not retry** |\n| `401` on an API call | token expired; run `mhlb_login` again |\n| `403` | the endpoint belongs to the school-admin or vendor role, not a parent |\n| non-JSON `200` | either a `/parentReports/print*` PDF (expected — see references) or the session lapsed into an HTML page |\n| `500` on `/parentReports/printOrders` | usually a caller mistake: empty `studentIds`, or no order matching that date and status |\n\n## Prefer the MCP when it is available\n\n`myhotlunchbox-mcp` wraps all of this with typed tools and a confirmation step\nfor every mutation — a prompt, or a preview plus a single-use `confirmToken`.\nUse this skill when the MCP is not installed, or inside a script.\n\nFile v1.2.3:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"myhotlunchbox-mcp\",\n  \"version\": \"1.2.3\",\n  \"publishedAt\": 1790991768396\n}\n\nFile v1.2.3:references/endpoints.md\n\n# My Hot Lunchbox endpoints — ready-to-run\n\nAll paths are relative to `$MHLB/api`. All need `Authorization: Bearer $MHLB_TOKEN`.\nAssumes the `mhlb_get` helper from `SKILL.md` is defined.\n\n## Account\n\n```sh\n# Account claims: name, role, student count, credit balances, subscription state\nmhlb_get /auth/userinfo | jq .\n```\n\n## Students\n\n```sh\nmhlb_get /parent/childrenInfo | jq '.[] | {id, firstName, schoolName, gradeTeacher, hasOrders, isInactive, isInvited}'\n\n# Editable profile for one student (also the model that POST /parent/editChild takes back)\nmhlb_get '/parent/editChild?childId=456' | jq .\n\n# Blank profile + dropdown options for adding a student\nmhlb_get /parent/createChild | jq .\n```\n\n## Calendar and deliveries\n\n```sh\n# Lunch calendar for a range — a POST that reads\nmhlb_post() {\n  local endpoint=$1; shift   # NOT `path`: zsh ties $path to $PATH\n  curl -sS -X POST \"$MHLB/api$endpoint\" -H \"Authorization: Bearer $MHLB_TOKEN\" \\\n    -H 'Content-Type: application/json' -d \"${1:-{\\}}\"\n}\n\n# Fields are `start`/`end` — `startDate`/`endDate` silently returns zero events.\nmhlb_post /calendar/studentSchoolData '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\"}' | jq .\n\n# Events carry the ids the ordering endpoints need:\nmhlb_post /calendar/studentSchoolData '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\"}' \\\n  | jq '.events[] | {studentId, eventId: .id, orderId, date: .start[0:10], className}'\n\n# What one student has on one day\nmhlb_get '/calendar/studentOrderItems?studentId=456&date=2026-09-14' | jq .\n```\n\n`/deliveryInfo/*` and `/calendar/viewMatchedVendors` look parent-facing in the\nsite's compiled client but return **403** for a parent account — they belong to\nthe school and vendor dashboards. Verified live; don't reach for them.\n\n## Cart and menu\n\n```sh\n# Valid filter values first — periods (semesters) and status tabs\nmhlb_get /event/ShoppingCartBaseData | jq '{periods: [.periods[] | {text, value, selected}]}'\n\n# The cart itself; every filter is optional\nmhlb_get '/event/shoppingCart' | jq .\nmhlb_get '/event/shoppingCart?selectedStudentId=456' | jq .\n\n# The orderable menu for a student on a date — vendor, items, sizes, prices, cutoff\nmhlb_get '/event/orderBaseData?studentId=456&eventDate=2026-09-14' | jq .\n```\n\n## Transactions and subscriptions\n\n```sh\nmhlb_get /event/transactionsList              | jq .\nmhlb_get '/event/transactionDetails?id=999' | jq .   # id comes from transactionsList\nmhlb_get /event/subscription                  | jq .\nmhlb_get '/event/upcomingSubscriptions'       | jq .\n```\n\n## Gift cards and coupons\n\n```sh\nmhlb_get /parent/giftCardDataTables | jq .\nmhlb_get /parent/coupon             | jq .\n```\n\n## Printable reports\n\nThese stream a **binary PDF**, not JSON — pipe to a file, never to `jq`. Their\npayloads are not date ranges.\n\n```sh\nmhlb_pdf() {  # usage: mhlb_pdf <endpoint> <json> <out.pdf>\n  curl -sS -X POST \"$MHLB/api$1\" -H \"Authorization: Bearer $MHLB_TOKEN\" \\\n    -H 'Content-Type: application/json' -d \"$2\" -o \"$3\" && file \"$3\"\n}\n\n# Calendar — needs `middle` (the midpoint date, which titles the PDF) and a\n# NON-EMPTY studentIds. There is no \"all students\" default: an empty or omitted\n# list answers 500, same as printOrders.\nmhlb_pdf /parentReports/printCalendar \\\n  '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\",\"middle\":\"2026-09-15\",\"studentIds\":[111627]}' \\\n  'Lunch Calendar.pdf'\n\n# Orders — ONE date, not a range. studentIds must be non-empty.\n# orderStatus: 0 = Pending, 1 = Paid, 2 = Credited.\nmhlb_pdf /parentReports/printOrders \\\n  '{\"orderStatus\":1,\"eventDate\":\"2026-09-14\",\"studentIds\":[111627]}' \\\n  'Orders Details.pdf'\n\n# One transaction receipt — send the record from transactionDetails.\n# (A transactionsList ROW is a different shape and renders a thinner PDF;\n#  the list is only used here to get the id.)\nID=$(mhlb_get /event/transactionsList | jq -r '.transactions[0].id')\nmhlb_get \"/event/transactionDetails?id=$ID\" | jq -c '. + {isCreditType:false}' > tx.json\nmhlb_pdf /parentReports/printTransactions \"$(cat tx.json)\" 'Transaction.pdf'\n```\n\nBoth `printCalendar` and `printOrders` answer **500** — not a 4xx — when\n`studentIds` is empty, and `printOrders` also 500s when no order matches the\ndate and status. Treat a 500 from either as a bad request, not an outage.\n\n`printTransactions` wants the record from `/event/transactionDetails`, **not** a\nrow from `/event/transactionsList` — both render, but they are different shapes\nand different documents. The list is only used to get the id, as the recipe\nabove does.\n\n## Writes — all UNVERIFIED\n\nPaths and verbs are read out of the site's compiled client and are reliable.\nThe **request bodies** have not been exercised against a live account. Fetch the\nmodel, edit it, post it back whole, then re-read to confirm.\n\n| Action | Read the model | Post it back |\n|---|---|---|\n| Place an order | `GET /event/createOrder?eventId=&studentId=` | `POST /event/createOrder` |\n| Change an order | `GET /event/editOrder?orderId=` | `POST /event/editOrder` |\n| Cancel an order | — | `POST /event/deleteOrder` — body below, **not** the order model |\n| Add a student | `GET /parent/createChild` | `POST /parent/createChild` |\n| Edit a student | `GET /parent/editChild?childId=` | `POST /parent/editChild` |\n| Remove a student | — | `POST /parent/deleteChild?id=` |\n| Apply a gift card | — | `POST /parent/applyGiftCard?giftCardCode=` |\n| Apply a coupon | — | `POST /parent/applyCoupon?couponCode=` |\n| Remove the coupon | — | `POST /parent/removeCoupon` |\n| Toggle subscriptions | `GET /event/subscription` | `POST /parent/changeSubscriptionStatus?isEnableSubscription=` |\n| Stop one subscription | `GET /event/upcomingSubscriptions` | `POST /event/unsubcribeOrder` — same body as deleteOrder |\n| Price the cart | — | `POST /payment/initCheckout` |\n| **Pay** | — | `POST /payment/checkout` |\n\n`POST /event/unsubcribeOrder` is spelled that way upstream — the typo is theirs.\n\nCancelling and unsubscribing take a small identifier payload, **not** the order\nmodel that create/edit round-trip. Captured from the site's own `order-mixin`:\n\n```sh\n# isRepeated: true acts on the whole recurring series, not just this date.\nmhlb_post /event/deleteOrder \\\n  '{\"orderId\":17284377,\"eventDate\":\"2026-08-26\",\"studentId\":111627,\"isRepeated\":false,\"isSubscribed\":false}'\n```\n\nCheckout takes `{orderIds, checkoutType, couponCode, giftCardCode, schoolDonations}`,\nwith the nulls sent explicitly, plus `{availableCredits, idempotencyKey, stripeToken}`\non `/payment/checkout`:\n\n```sh\nmhlb_post /payment/initCheckout \\\n  '{\"orderIds\":[123],\"checkoutType\":null,\"couponCode\":null,\"giftCardCode\":null,\"schoolDonations\":null}'\n```\n\nTwo things about paying:\n\n- **`stripeToken` cannot be produced outside a browser.** The site mints it with\n  Stripe.js, and only when paying by a NEW card. Server-side you can only pay\n  with a card already saved on the account.\n- **`idempotencyKey` is yours to generate** — the site uses\n  `\"$(uuidgen | tr A-Z a-z)-$(date +%s000)\"`. Reuse the SAME key when retrying an\n  ambiguous checkout; a fresh one risks a second charge.\n\n`POST /payment/checkout` charges a real payment method. Price with\n`initCheckout` first, read the total it returns, and confirm that figure before\npaying.\n\n## Endpoints a parent account cannot reach\n\nThe same bundle serves school-admin and vendor roles. These return `403` for a\nparent and are listed only so a `403` is not mistaken for a broken session:\n`/school`, `/schoolManagement`, `/schoolOnboarding`, `/vendor`, `/vendorReports`,\n`/schoolVendorReports`, `/item`, `/adminTasks`, `/quickbooks`, `/docusign`,\n`/interactiveDistributionReport`, `/upload`, `/deliveryInfo`, and\n`/calendar/viewMatchedVendors`.\n\nFile v1.2.3:skill-card.md\n\n## Description:\n\nGuides agents to read and manage a My Hot Lunchbox school-lunch account with shell commands when the MCP server is unavailable.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nParents and their agents can use shell commands to check students, lunch calendars, carts, orders, and payments or manage the account when the MCP server is unavailable.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: A checkout command can charge a saved payment method.\n\nMitigation: Price the cart first and require explicit user confirmation of the total before paying; prefer the MCP's built-in confirmation when available.\n\nRisk: Order, student, subscription, coupon, and gift-card commands can change live account data; write request bodies have not been verified against a live account.\n\nMitigation: Require explicit user approval, inspect the complete request before sending it, and re-read the account to confirm changes.\n\nRisk: Credentials and exported account or transaction data are sensitive.\n\nMitigation: Keep credentials out of shell history and clean up local JSON and PDF files containing account or transaction details.\n\n## Reference(s):\n\n- [My Hot Lunchbox API endpoints](references/endpoints.md)\n- [My Hot Lunchbox MCP on ClawHub](https://clawhub.ai/chrischall/skills/myhotlunchbox-mcp)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, Guidance]\n\n**Output Format:** [Markdown with shell examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Commands can retrieve account data as JSON or download PDF reports.]\n\n## Skill Version(s):\n\n1.2.3 (source: server-resolved release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.2.2: 4 files, 7302 bytes\n\nFiles: references/endpoints.md (7715b), skill-card.md (2109b), SKILL.md (4772b), _meta.json (136b)\n\nFile v1.2.2:SKILL.md\n\n---\nname: myhotlunchbox\ndescription: Read and manage a My Hot Lunchbox school-lunch account from a shell with curl — sign in, list students, read the lunch calendar and cart, check orders, deliveries and payments. Use when you want My Hot Lunchbox data without running the MCP server, in a script, or on a machine where the MCP is not installed.\n---\n\n# My Hot Lunchbox from the shell\n\n`ordernow.myhotlunchbox.com` exposes a plain JSON API behind an OAuth2 password\ngrant. It is reachable server-side — no browser, no extension, no bridge. Two\n`curl` calls get you data: one to sign in, one per read.\n\n## Sign in once per shell\n\nCredentials come from the environment; never paste them into a command line\n(that puts them in shell history).\n\n```sh\nexport MHLB_USER='you@example.com'\nexport MHLB_PASS='…'          # e.g. read -rs MHLB_PASS\nexport MHLB=https://ordernow.myhotlunchbox.com\n\nmhlb_login() {\n  local resp\n  resp=$(curl -sS -X POST \"$MHLB/api/auth/login\" \\\n    -H 'Content-Type: application/x-www-form-urlencoded' \\\n    -H 'Accept: application/json' \\\n    --data-urlencode 'grant_type=password' \\\n    --data-urlencode \"username=$MHLB_USER\" \\\n    --data-urlencode \"password=$MHLB_PASS\" \\\n    --data-urlencode 'scope=openid offline_access email profile roles') || return 1\n  MHLB_TOKEN=$(printf '%s' \"$resp\" | jq -r '.access_token // empty')\n  if [ -z \"$MHLB_TOKEN\" ]; then\n    printf '%s' \"$resp\" | jq -r '.error_description // .error // \"login failed\"' >&2\n    return 1\n  fi\n  export MHLB_TOKEN\n}\n\n# Authenticated GET.  usage: mhlb_get /parent/childrenInfo [curl args…]\nmhlb_get() {\n  local endpoint=$1; shift   # NOT `path`: zsh ties $path to $PATH\n  curl -sS \"$MHLB/api$endpoint\" -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Accept: application/json' \"$@\"\n}\n\nmhlb_login && mhlb_get /auth/userinfo | jq '{name, email, students_count, pending_orders_count, parent_credit_value}'\n```\n\n**A failed sign-in must not be retried.** The server is OpenIddict and counts\nfailed attempts; repeated failures can escalate to a CAPTCHA and remove\nserver-side sign-in for that account entirely. If `invalid_grant` comes back,\nstop and check the credentials.\n\nThe token lasts about an hour. Re-run `mhlb_login` when a call starts returning\n`401`.\n\n## The three reads that answer most questions\n\n```sh\n# Who the students are — the id feeds everything else\nmhlb_get /parent/childrenInfo | jq '.[] | {id, firstName, schoolName, gradeTeacher, isInactive}'\n\n# The lunch calendar for a date range (POST, despite being a read).\n# The fields are `start`/`end`. Using `startDate`/`endDate` returns 200 with an\n# EMPTY events array — a silent wrong answer, not an error.\ncurl -sS -X POST \"$MHLB/api/calendar/studentSchoolData\" \\\n  -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Content-Type: application/json' \\\n  -d '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\"}' | jq '.events[] | {studentId, id, start, className}'\n\n# What is in the cart but not yet paid for\nmhlb_get '/event/shoppingCart' | jq .\n```\n\n`references/endpoints.md` has the rest — deliveries, transactions,\nsubscriptions, gift cards, per-day order detail, and the printable reports.\n\n## Ordering is read-modify-write\n\nThere is no \"add item X\" call. To place or change an order you fetch the model,\nedit it, and post it back whole:\n\n```sh\nmhlb_get '/event/createOrder?eventId=123&studentId=456' > order.json\n# edit quantities in order.json\ncurl -sS -X POST \"$MHLB/api/event/createOrder\" \\\n  -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Content-Type: application/json' \\\n  -d @order.json\n```\n\nAnything missing from the payload is **cleared**, not preserved.\n\n**The write request bodies are unverified** — their paths and verbs were read\nout of the site's own compiled client, but no write has been exercised against a\nlive account. Inspect what you are about to send, and re-read the resource\nafterwards to confirm it landed. A `200` is not proof.\n\n`/payment/checkout` charges a real card. Do not call it speculatively.\n\n## Reading the errors\n\n| Status | Meaning |\n|---|---|\n| `400` + `invalid_grant` | wrong username/password — **do not retry** |\n| `401` on an API call | token expired; run `mhlb_login` again |\n| `403` | the endpoint belongs to the school-admin or vendor role, not a parent |\n| non-JSON `200` | either a `/parentReports/print*` PDF (expected — see references) or the session lapsed into an HTML page |\n| `500` on `/parentReports/printOrders` | usually a caller mistake: empty `studentIds`, or no order matching that date and status |\n\n## Prefer the MCP when it is available\n\n`myhotlunchbox-mcp` wraps all of this with typed tools and a confirmation step\nfor every mutation — a prompt, or a preview plus a single-use `confirmToken`.\nUse this skill when the MCP is not installed, or inside a script.\n\nFile v1.2.2:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"myhotlunchbox-mcp\",\n  \"version\": \"1.2.2\",\n  \"publishedAt\": 1790787412301\n}\n\nFile v1.2.2:references/endpoints.md\n\n# My Hot Lunchbox endpoints — ready-to-run\n\nAll paths are relative to `$MHLB/api`. All need `Authorization: Bearer $MHLB_TOKEN`.\nAssumes the `mhlb_get` helper from `SKILL.md` is defined.\n\n## Account\n\n```sh\n# Account claims: name, role, student count, credit balances, subscription state\nmhlb_get /auth/userinfo | jq .\n```\n\n## Students\n\n```sh\nmhlb_get /parent/childrenInfo | jq '.[] | {id, firstName, schoolName, gradeTeacher, hasOrders, isInactive, isInvited}'\n\n# Editable profile for one student (also the model that POST /parent/editChild takes back)\nmhlb_get '/parent/editChild?childId=456' | jq .\n\n# Blank profile + dropdown options for adding a student\nmhlb_get /parent/createChild | jq .\n```\n\n## Calendar and deliveries\n\n```sh\n# Lunch calendar for a range — a POST that reads\nmhlb_post() {\n  local endpoint=$1; shift   # NOT `path`: zsh ties $path to $PATH\n  curl -sS -X POST \"$MHLB/api$endpoint\" -H \"Authorization: Bearer $MHLB_TOKEN\" \\\n    -H 'Content-Type: application/json' -d \"${1:-{\\}}\"\n}\n\n# Fields are `start`/`end` — `startDate`/`endDate` silently returns zero events.\nmhlb_post /calendar/studentSchoolData '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\"}' | jq .\n\n# Events carry the ids the ordering endpoints need:\nmhlb_post /calendar/studentSchoolData '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\"}' \\\n  | jq '.events[] | {studentId, eventId: .id, orderId, date: .start[0:10], className}'\n\n# What one student has on one day\nmhlb_get '/calendar/studentOrderItems?studentId=456&date=2026-09-14' | jq .\n```\n\n`/deliveryInfo/*` and `/calendar/viewMatchedVendors` look parent-facing in the\nsite's compiled client but return **403** for a parent account — they belong to\nthe school and vendor dashboards. Verified live; don't reach for them.\n\n## Cart and menu\n\n```sh\n# Valid filter values first — periods (semesters) and status tabs\nmhlb_get /event/ShoppingCartBaseData | jq '{periods: [.periods[] | {text, value, selected}]}'\n\n# The cart itself; every filter is optional\nmhlb_get '/event/shoppingCart' | jq .\nmhlb_get '/event/shoppingCart?selectedStudentId=456' | jq .\n\n# The orderable menu for a student on a date — vendor, items, sizes, prices, cutoff\nmhlb_get '/event/orderBaseData?studentId=456&eventDate=2026-09-14' | jq .\n```\n\n## Transactions and subscriptions\n\n```sh\nmhlb_get /event/transactionsList              | jq .\nmhlb_get '/event/transactionDetails?id=999' | jq .   # id comes from transactionsList\nmhlb_get /event/subscription                  | jq .\nmhlb_get '/event/upcomingSubscriptions'       | jq .\n```\n\n## Gift cards and coupons\n\n```sh\nmhlb_get /parent/giftCardDataTables | jq .\nmhlb_get /parent/coupon             | jq .\n```\n\n## Printable reports\n\nThese stream a **binary PDF**, not JSON — pipe to a file, never to `jq`. Their\npayloads are not date ranges.\n\n```sh\nmhlb_pdf() {  # usage: mhlb_pdf <endpoint> <json> <out.pdf>\n  curl -sS -X POST \"$MHLB/api$1\" -H \"Authorization: Bearer $MHLB_TOKEN\" \\\n    -H 'Content-Type: application/json' -d \"$2\" -o \"$3\" && file \"$3\"\n}\n\n# Calendar — needs `middle` (the midpoint date, which titles the PDF) and a\n# NON-EMPTY studentIds. There is no \"all students\" default: an empty or omitted\n# list answers 500, same as printOrders.\nmhlb_pdf /parentReports/printCalendar \\\n  '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\",\"middle\":\"2026-09-15\",\"studentIds\":[111627]}' \\\n  'Lunch Calendar.pdf'\n\n# Orders — ONE date, not a range. studentIds must be non-empty.\n# orderStatus: 0 = Pending, 1 = Paid, 2 = Credited.\nmhlb_pdf /parentReports/printOrders \\\n  '{\"orderStatus\":1,\"eventDate\":\"2026-09-14\",\"studentIds\":[111627]}' \\\n  'Orders Details.pdf'\n\n# One transaction receipt — send the record from transactionDetails.\n# (A transactionsList ROW is a different shape and renders a thinner PDF;\n#  the list is only used here to get the id.)\nID=$(mhlb_get /event/transactionsList | jq -r '.transactions[0].id')\nmhlb_get \"/event/transactionDetails?id=$ID\" | jq -c '. + {isCreditType:false}' > tx.json\nmhlb_pdf /parentReports/printTransactions \"$(cat tx.json)\" 'Transaction.pdf'\n```\n\nBoth `printCalendar` and `printOrders` answer **500** — not a 4xx — when\n`studentIds` is empty, and `printOrders` also 500s when no order matches the\ndate and status. Treat a 500 from either as a bad request, not an outage.\n\n`printTransactions` wants the record from `/event/transactionDetails`, **not** a\nrow from `/event/transactionsList` — both render, but they are different shapes\nand different documents. The list is only used to get the id, as the recipe\nabove does.\n\n## Writes — all UNVERIFIED\n\nPaths and verbs are read out of the site's compiled client and are reliable.\nThe **request bodies** have not been exercised against a live account. Fetch the\nmodel, edit it, post it back whole, then re-read to confirm.\n\n| Action | Read the model | Post it back |\n|---|---|---|\n| Place an order | `GET /event/createOrder?eventId=&studentId=` | `POST /event/createOrder` |\n| Change an order | `GET /event/editOrder?orderId=` | `POST /event/editOrder` |\n| Cancel an order | — | `POST /event/deleteOrder` — body below, **not** the order model |\n| Add a student | `GET /parent/createChild` | `POST /parent/createChild` |\n| Edit a student | `GET /parent/editChild?childId=` | `POST /parent/editChild` |\n| Remove a student | — | `POST /parent/deleteChild?id=` |\n| Apply a gift card | — | `POST /parent/applyGiftCard?giftCardCode=` |\n| Apply a coupon | — | `POST /parent/applyCoupon?couponCode=` |\n| Remove the coupon | — | `POST /parent/removeCoupon` |\n| Toggle subscriptions | `GET /event/subscription` | `POST /parent/changeSubscriptionStatus?isEnableSubscription=` |\n| Stop one subscription | `GET /event/upcomingSubscriptions` | `POST /event/unsubcribeOrder` — same body as deleteOrder |\n| Price the cart | — | `POST /payment/initCheckout` |\n| **Pay** | — | `POST /payment/checkout` |\n\n`POST /event/unsubcribeOrder` is spelled that way upstream — the typo is theirs.\n\nCancelling and unsubscribing take a small identifier payload, **not** the order\nmodel that create/edit round-trip. Captured from the site's own `order-mixin`:\n\n```sh\n# isRepeated: true acts on the whole recurring series, not just this date.\nmhlb_post /event/deleteOrder \\\n  '{\"orderId\":17284377,\"eventDate\":\"2026-08-26\",\"studentId\":111627,\"isRepeated\":false,\"isSubscribed\":false}'\n```\n\nCheckout takes `{orderIds, checkoutType, couponCode, giftCardCode, schoolDonations}`,\nwith the nulls sent explicitly, plus `{availableCredits, idempotencyKey, stripeToken}`\non `/payment/checkout`:\n\n```sh\nmhlb_post /payment/initCheckout \\\n  '{\"orderIds\":[123],\"checkoutType\":null,\"couponCode\":null,\"giftCardCode\":null,\"schoolDonations\":null}'\n```\n\nTwo things about paying:\n\n- **`stripeToken` cannot be produced outside a browser.** The site mints it with\n  Stripe.js, and only when paying by a NEW card. Server-side you can only pay\n  with a card already saved on the account.\n- **`idempotencyKey` is yours to generate** — the site uses\n  `\"$(uuidgen | tr A-Z a-z)-$(date +%s000)\"`. Reuse the SAME key when retrying an\n  ambiguous checkout; a fresh one risks a second charge.\n\n`POST /payment/checkout` charges a real payment method. Price with\n`initCheckout` first, read the total it returns, and confirm that figure before\npaying.\n\n## Endpoints a parent account cannot reach\n\nThe same bundle serves school-admin and vendor roles. These return `403` for a\nparent and are listed only so a `403` is not mistaken for a broken session:\n`/school`, `/schoolManagement`, `/schoolOnboarding`, `/vendor`, `/vendorReports`,\n`/schoolVendorReports`, `/item`, `/adminTasks`, `/quickbooks`, `/docusign`,\n`/interactiveDistributionReport`, `/upload`, `/deliveryInfo`, and\n`/calendar/viewMatchedVendors`.\n\nFile v1.2.2:skill-card.md\n\n## Description:\n\nProvides shell commands to read and manage a My Hot Lunchbox school-lunch account without the MCP server.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nParents and developers use shell commands to check students, menus, orders, and payments or manage lunch orders when the MCP server is unavailable.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Raw authenticated commands can alter orders and account data without enforced safeguards.\n\nMitigation: Inspect full request payloads and require human confirmation before mutations; prefer the MCP's confirmations when available.\n\nRisk: Full-model writes can clear omitted data, and the documented write bodies are unverified.\n\nMitigation: Review the complete payload before sending it and re-read the resource afterward to verify the result.\n\nRisk: Checkout charges a real payment method, and an ambiguous retry with a new idempotency key may duplicate the charge.\n\nMitigation: Price and confirm the total before checkout; reuse the same idempotency key when retrying an uncertain payment.\n\nRisk: Repeated failed sign-ins can restrict account access.\n\nMitigation: Stop after an invalid-grant response and check credentials instead of retrying.\n\n## Reference(s):\n\n- [My Hot Lunchbox endpoints](references/endpoints.md)\n- [ClawHub skill release](https://clawhub.ai/chrischall/skills/myhotlunchbox-mcp)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, Guidance]\n\n**Output Format:** [Markdown with shell code blocks]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Commands can access account data or initiate account changes.]\n\n## Skill Version(s):\n\n1.2.2 (source: ClawHub release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.2.1: 4 files, 7338 bytes\n\nFiles: references/endpoints.md (7715b), skill-card.md (2199b), SKILL.md (4772b), _meta.json (136b)\n\nFile v1.2.1:SKILL.md\n\n---\nname: myhotlunchbox\ndescription: Read and manage a My Hot Lunchbox school-lunch account from a shell with curl — sign in, list students, read the lunch calendar and cart, check orders, deliveries and payments. Use when you want My Hot Lunchbox data without running the MCP server, in a script, or on a machine where the MCP is not installed.\n---\n\n# My Hot Lunchbox from the shell\n\n`ordernow.myhotlunchbox.com` exposes a plain JSON API behind an OAuth2 password\ngrant. It is reachable server-side — no browser, no extension, no bridge. Two\n`curl` calls get you data: one to sign in, one per read.\n\n## Sign in once per shell\n\nCredentials come from the environment; never paste them into a command line\n(that puts them in shell history).\n\n```sh\nexport MHLB_USER='you@example.com'\nexport MHLB_PASS='…'          # e.g. read -rs MHLB_PASS\nexport MHLB=https://ordernow.myhotlunchbox.com\n\nmhlb_login() {\n  local resp\n  resp=$(curl -sS -X POST \"$MHLB/api/auth/login\" \\\n    -H 'Content-Type: application/x-www-form-urlencoded' \\\n    -H 'Accept: application/json' \\\n    --data-urlencode 'grant_type=password' \\\n    --data-urlencode \"username=$MHLB_USER\" \\\n    --data-urlencode \"password=$MHLB_PASS\" \\\n    --data-urlencode 'scope=openid offline_access email profile roles') || return 1\n  MHLB_TOKEN=$(printf '%s' \"$resp\" | jq -r '.access_token // empty')\n  if [ -z \"$MHLB_TOKEN\" ]; then\n    printf '%s' \"$resp\" | jq -r '.error_description // .error // \"login failed\"' >&2\n    return 1\n  fi\n  export MHLB_TOKEN\n}\n\n# Authenticated GET.  usage: mhlb_get /parent/childrenInfo [curl args…]\nmhlb_get() {\n  local endpoint=$1; shift   # NOT `path`: zsh ties $path to $PATH\n  curl -sS \"$MHLB/api$endpoint\" -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Accept: application/json' \"$@\"\n}\n\nmhlb_login && mhlb_get /auth/userinfo | jq '{name, email, students_count, pending_orders_count, parent_credit_value}'\n```\n\n**A failed sign-in must not be retried.** The server is OpenIddict and counts\nfailed attempts; repeated failures can escalate to a CAPTCHA and remove\nserver-side sign-in for that account entirely. If `invalid_grant` comes back,\nstop and check the credentials.\n\nThe token lasts about an hour. Re-run `mhlb_login` when a call starts returning\n`401`.\n\n## The three reads that answer most questions\n\n```sh\n# Who the students are — the id feeds everything else\nmhlb_get /parent/childrenInfo | jq '.[] | {id, firstName, schoolName, gradeTeacher, isInactive}'\n\n# The lunch calendar for a date range (POST, despite being a read).\n# The fields are `start`/`end`. Using `startDate`/`endDate` returns 200 with an\n# EMPTY events array — a silent wrong answer, not an error.\ncurl -sS -X POST \"$MHLB/api/calendar/studentSchoolData\" \\\n  -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Content-Type: application/json' \\\n  -d '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\"}' | jq '.events[] | {studentId, id, start, className}'\n\n# What is in the cart but not yet paid for\nmhlb_get '/event/shoppingCart' | jq .\n```\n\n`references/endpoints.md` has the rest — deliveries, transactions,\nsubscriptions, gift cards, per-day order detail, and the printable reports.\n\n## Ordering is read-modify-write\n\nThere is no \"add item X\" call. To place or change an order you fetch the model,\nedit it, and post it back whole:\n\n```sh\nmhlb_get '/event/createOrder?eventId=123&studentId=456' > order.json\n# edit quantities in order.json\ncurl -sS -X POST \"$MHLB/api/event/createOrder\" \\\n  -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Content-Type: application/json' \\\n  -d @order.json\n```\n\nAnything missing from the payload is **cleared**, not preserved.\n\n**The write request bodies are unverified** — their paths and verbs were read\nout of the site's own compiled client, but no write has been exercised against a\nlive account. Inspect what you are about to send, and re-read the resource\nafterwards to confirm it landed. A `200` is not proof.\n\n`/payment/checkout` charges a real card. Do not call it speculatively.\n\n## Reading the errors\n\n| Status | Meaning |\n|---|---|\n| `400` + `invalid_grant` | wrong username/password — **do not retry** |\n| `401` on an API call | token expired; run `mhlb_login` again |\n| `403` | the endpoint belongs to the school-admin or vendor role, not a parent |\n| non-JSON `200` | either a `/parentReports/print*` PDF (expected — see references) or the session lapsed into an HTML page |\n| `500` on `/parentReports/printOrders` | usually a caller mistake: empty `studentIds`, or no order matching that date and status |\n\n## Prefer the MCP when it is available\n\n`myhotlunchbox-mcp` wraps all of this with typed tools and a confirmation step\nfor every mutation — a prompt, or a preview plus a single-use `confirmToken`.\nUse this skill when the MCP is not installed, or inside a script.\n\nFile v1.2.1:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"myhotlunchbox-mcp\",\n  \"version\": \"1.2.1\",\n  \"publishedAt\": 1790351428908\n}\n\nFile v1.2.1:references/endpoints.md\n\n# My Hot Lunchbox endpoints — ready-to-run\n\nAll paths are relative to `$MHLB/api`. All need `Authorization: Bearer $MHLB_TOKEN`.\nAssumes the `mhlb_get` helper from `SKILL.md` is defined.\n\n## Account\n\n```sh\n# Account claims: name, role, student count, credit balances, subscription state\nmhlb_get /auth/userinfo | jq .\n```\n\n## Students\n\n```sh\nmhlb_get /parent/childrenInfo | jq '.[] | {id, firstName, schoolName, gradeTeacher, hasOrders, isInactive, isInvited}'\n\n# Editable profile for one student (also the model that POST /parent/editChild takes back)\nmhlb_get '/parent/editChild?childId=456' | jq .\n\n# Blank profile + dropdown options for adding a student\nmhlb_get /parent/createChild | jq .\n```\n\n## Calendar and deliveries\n\n```sh\n# Lunch calendar for a range — a POST that reads\nmhlb_post() {\n  local endpoint=$1; shift   # NOT `path`: zsh ties $path to $PATH\n  curl -sS -X POST \"$MHLB/api$endpoint\" -H \"Authorization: Bearer $MHLB_TOKEN\" \\\n    -H 'Content-Type: application/json' -d \"${1:-{\\}}\"\n}\n\n# Fields are `start`/`end` — `startDate`/`endDate` silently returns zero events.\nmhlb_post /calendar/studentSchoolData '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\"}' | jq .\n\n# Events carry the ids the ordering endpoints need:\nmhlb_post /calendar/studentSchoolData '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\"}' \\\n  | jq '.events[] | {studentId, eventId: .id, orderId, date: .start[0:10], className}'\n\n# What one student has on one day\nmhlb_get '/calendar/studentOrderItems?studentId=456&date=2026-09-14' | jq .\n```\n\n`/deliveryInfo/*` and `/calendar/viewMatchedVendors` look parent-facing in the\nsite's compiled client but return **403** for a parent account — they belong to\nthe school and vendor dashboards. Verified live; don't reach for them.\n\n## Cart and menu\n\n```sh\n# Valid filter values first — periods (semesters) and status tabs\nmhlb_get /event/ShoppingCartBaseData | jq '{periods: [.periods[] | {text, value, selected}]}'\n\n# The cart itself; every filter is optional\nmhlb_get '/event/shoppingCart' | jq .\nmhlb_get '/event/shoppingCart?selectedStudentId=456' | jq .\n\n# The orderable menu for a student on a date — vendor, items, sizes, prices, cutoff\nmhlb_get '/event/orderBaseData?studentId=456&eventDate=2026-09-14' | jq .\n```\n\n## Transactions and subscriptions\n\n```sh\nmhlb_get /event/transactionsList              | jq .\nmhlb_get '/event/transactionDetails?id=999' | jq .   # id comes from transactionsList\nmhlb_get /event/subscription                  | jq .\nmhlb_get '/event/upcomingSubscriptions'       | jq .\n```\n\n## Gift cards and coupons\n\n```sh\nmhlb_get /parent/giftCardDataTables | jq .\nmhlb_get /parent/coupon             | jq .\n```\n\n## Printable reports\n\nThese stream a **binary PDF**, not JSON — pipe to a file, never to `jq`. Their\npayloads are not date ranges.\n\n```sh\nmhlb_pdf() {  # usage: mhlb_pdf <endpoint> <json> <out.pdf>\n  curl -sS -X POST \"$MHLB/api$1\" -H \"Authorization: Bearer $MHLB_TOKEN\" \\\n    -H 'Content-Type: application/json' -d \"$2\" -o \"$3\" && file \"$3\"\n}\n\n# Calendar — needs `middle` (the midpoint date, which titles the PDF) and a\n# NON-EMPTY studentIds. There is no \"all students\" default: an empty or omitted\n# list answers 500, same as printOrders.\nmhlb_pdf /parentReports/printCalendar \\\n  '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\",\"middle\":\"2026-09-15\",\"studentIds\":[111627]}' \\\n  'Lunch Calendar.pdf'\n\n# Orders — ONE date, not a range. studentIds must be non-empty.\n# orderStatus: 0 = Pending, 1 = Paid, 2 = Credited.\nmhlb_pdf /parentReports/printOrders \\\n  '{\"orderStatus\":1,\"eventDate\":\"2026-09-14\",\"studentIds\":[111627]}' \\\n  'Orders Details.pdf'\n\n# One transaction receipt — send the record from transactionDetails.\n# (A transactionsList ROW is a different shape and renders a thinner PDF;\n#  the list is only used here to get the id.)\nID=$(mhlb_get /event/transactionsList | jq -r '.transactions[0].id')\nmhlb_get \"/event/transactionDetails?id=$ID\" | jq -c '. + {isCreditType:false}' > tx.json\nmhlb_pdf /parentReports/printTransactions \"$(cat tx.json)\" 'Transaction.pdf'\n```\n\nBoth `printCalendar` and `printOrders` answer **500** — not a 4xx — when\n`studentIds` is empty, and `printOrders` also 500s when no order matches the\ndate and status. Treat a 500 from either as a bad request, not an outage.\n\n`printTransactions` wants the record from `/event/transactionDetails`, **not** a\nrow from `/event/transactionsList` — both render, but they are different shapes\nand different documents. The list is only used to get the id, as the recipe\nabove does.\n\n## Writes — all UNVERIFIED\n\nPaths and verbs are read out of the site's compiled client and are reliable.\nThe **request bodies** have not been exercised against a live account. Fetch the\nmodel, edit it, post it back whole, then re-read to confirm.\n\n| Action | Read the model | Post it back |\n|---|---|---|\n| Place an order | `GET /event/createOrder?eventId=&studentId=` | `POST /event/createOrder` |\n| Change an order | `GET /event/editOrder?orderId=` | `POST /event/editOrder` |\n| Cancel an order | — | `POST /event/deleteOrder` — body below, **not** the order model |\n| Add a student | `GET /parent/createChild` | `POST /parent/createChild` |\n| Edit a student | `GET /parent/editChild?childId=` | `POST /parent/editChild` |\n| Remove a student | — | `POST /parent/deleteChild?id=` |\n| Apply a gift card | — | `POST /parent/applyGiftCard?giftCardCode=` |\n| Apply a coupon | — | `POST /parent/applyCoupon?couponCode=` |\n| Remove the coupon | — | `POST /parent/removeCoupon` |\n| Toggle subscriptions | `GET /event/subscription` | `POST /parent/changeSubscriptionStatus?isEnableSubscription=` |\n| Stop one subscription | `GET /event/upcomingSubscriptions` | `POST /event/unsubcribeOrder` — same body as deleteOrder |\n| Price the cart | — | `POST /payment/initCheckout` |\n| **Pay** | — | `POST /payment/checkout` |\n\n`POST /event/unsubcribeOrder` is spelled that way upstream — the typo is theirs.\n\nCancelling and unsubscribing take a small identifier payload, **not** the order\nmodel that create/edit round-trip. Captured from the site's own `order-mixin`:\n\n```sh\n# isRepeated: true acts on the whole recurring series, not just this date.\nmhlb_post /event/deleteOrder \\\n  '{\"orderId\":17284377,\"eventDate\":\"2026-08-26\",\"studentId\":111627,\"isRepeated\":false,\"isSubscribed\":false}'\n```\n\nCheckout takes `{orderIds, checkoutType, couponCode, giftCardCode, schoolDonations}`,\nwith the nulls sent explicitly, plus `{availableCredits, idempotencyKey, stripeToken}`\non `/payment/checkout`:\n\n```sh\nmhlb_post /payment/initCheckout \\\n  '{\"orderIds\":[123],\"checkoutType\":null,\"couponCode\":null,\"giftCardCode\":null,\"schoolDonations\":null}'\n```\n\nTwo things about paying:\n\n- **`stripeToken` cannot be produced outside a browser.** The site mints it with\n  Stripe.js, and only when paying by a NEW card. Server-side you can only pay\n  with a card already saved on the account.\n- **`idempotencyKey` is yours to generate** — the site uses\n  `\"$(uuidgen | tr A-Z a-z)-$(date +%s000)\"`. Reuse the SAME key when retrying an\n  ambiguous checkout; a fresh one risks a second charge.\n\n`POST /payment/checkout` charges a real payment method. Price with\n`initCheckout` first, read the total it returns, and confirm that figure before\npaying.\n\n## Endpoints a parent account cannot reach\n\nThe same bundle serves school-admin and vendor roles. These return `403` for a\nparent and are listed only so a `403` is not mistaken for a broken session:\n`/school`, `/schoolManagement`, `/schoolOnboarding`, `/vendor`, `/vendorReports`,\n`/schoolVendorReports`, `/item`, `/adminTasks`, `/quickbooks`, `/docusign`,\n`/interactiveDistributionReport`, `/upload`, `/deliveryInfo`, and\n`/calendar/viewMatchedVendors`.\n\nFile v1.2.1:skill-card.md\n\n## Description:\n\nProvides shell-based instructions to sign in to My Hot Lunchbox, read school-lunch account data, and manage orders when the MCP server is unavailable.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nExternal users and developers use shell commands to view students, lunch calendars, carts, orders, and transactions in their My Hot Lunchbox accounts, or to manually manage orders when the MCP server is unavailable.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Shell access exposes account credentials and sensitive student, order, and payment information.\n\nMitigation: Use only in trusted sessions; keep credentials and tokens out of shared logs and command history.\n\nRisk: Raw write commands can change account data or overwrite omitted order fields without built-in confirmation.\n\nMitigation: Prefer the MCP wrapper for mutations; otherwise inspect the full payload, obtain explicit approval, and re-read the resource afterward.\n\nRisk: A checkout command can charge a real card.\n\nMitigation: Treat checkout as manual-only; confirm the order and total price before any payment and never run it speculatively.\n\nRisk: Repeated failed sign-ins can restrict account access.\n\nMitigation: Stop after an invalid-grant response and check credentials rather than retrying.\n\n## Reference(s):\n\n- [ClawHub skill listing](https://clawhub.ai/chrischall/skills/myhotlunchbox-mcp)\n- [My Hot Lunchbox endpoints](references/endpoints.md)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, Guidance]\n\n**Output Format:** [Markdown with shell examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Commands may retrieve account data or change orders; printable reports are PDFs.]\n\n## Skill Version(s):\n\n1.2.1 (source: ClawHub release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.2.0: 4 files, 7454 bytes\n\nFiles: references/endpoints.md (7715b), skill-card.md (2399b), SKILL.md (4772b), _meta.json (136b)\n\nFile v1.2.0:SKILL.md\n\n---\nname: myhotlunchbox\ndescription: Read and manage a My Hot Lunchbox school-lunch account from a shell with curl — sign in, list students, read the lunch calendar and cart, check orders, deliveries and payments. Use when you want My Hot Lunchbox data without running the MCP server, in a script, or on a machine where the MCP is not installed.\n---\n\n# My Hot Lunchbox from the shell\n\n`ordernow.myhotlunchbox.com` exposes a plain JSON API behind an OAuth2 password\ngrant. It is reachable server-side — no browser, no extension, no bridge. Two\n`curl` calls get you data: one to sign in, one per read.\n\n## Sign in once per shell\n\nCredentials come from the environment; never paste them into a command line\n(that puts them in shell history).\n\n```sh\nexport MHLB_USER='you@example.com'\nexport MHLB_PASS='…'          # e.g. read -rs MHLB_PASS\nexport MHLB=https://ordernow.myhotlunchbox.com\n\nmhlb_login() {\n  local resp\n  resp=$(curl -sS -X POST \"$MHLB/api/auth/login\" \\\n    -H 'Content-Type: application/x-www-form-urlencoded' \\\n    -H 'Accept: application/json' \\\n    --data-urlencode 'grant_type=password' \\\n    --data-urlencode \"username=$MHLB_USER\" \\\n    --data-urlencode \"password=$MHLB_PASS\" \\\n    --data-urlencode 'scope=openid offline_access email profile roles') || return 1\n  MHLB_TOKEN=$(printf '%s' \"$resp\" | jq -r '.access_token // empty')\n  if [ -z \"$MHLB_TOKEN\" ]; then\n    printf '%s' \"$resp\" | jq -r '.error_description // .error // \"login failed\"' >&2\n    return 1\n  fi\n  export MHLB_TOKEN\n}\n\n# Authenticated GET.  usage: mhlb_get /parent/childrenInfo [curl args…]\nmhlb_get() {\n  local endpoint=$1; shift   # NOT `path`: zsh ties $path to $PATH\n  curl -sS \"$MHLB/api$endpoint\" -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Accept: application/json' \"$@\"\n}\n\nmhlb_login && mhlb_get /auth/userinfo | jq '{name, email, students_count, pending_orders_count, parent_credit_value}'\n```\n\n**A failed sign-in must not be retried.** The server is OpenIddict and counts\nfailed attempts; repeated failures can escalate to a CAPTCHA and remove\nserver-side sign-in for that account entirely. If `invalid_grant` comes back,\nstop and check the credentials.\n\nThe token lasts about an hour. Re-run `mhlb_login` when a call starts returning\n`401`.\n\n## The three reads that answer most questions\n\n```sh\n# Who the students are — the id feeds everything else\nmhlb_get /parent/childrenInfo | jq '.[] | {id, firstName, schoolName, gradeTeacher, isInactive}'\n\n# The lunch calendar for a date range (POST, despite being a read).\n# The fields are `start`/`end`. Using `startDate`/`endDate` returns 200 with an\n# EMPTY events array — a silent wrong answer, not an error.\ncurl -sS -X POST \"$MHLB/api/calendar/studentSchoolData\" \\\n  -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Content-Type: application/json' \\\n  -d '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\"}' | jq '.events[] | {studentId, id, start, className}'\n\n# What is in the cart but not yet paid for\nmhlb_get '/event/shoppingCart' | jq .\n```\n\n`references/endpoints.md` has the rest — deliveries, transactions,\nsubscriptions, gift cards, per-day order detail, and the printable reports.\n\n## Ordering is read-modify-write\n\nThere is no \"add item X\" call. To place or change an order you fetch the model,\nedit it, and post it back whole:\n\n```sh\nmhlb_get '/event/createOrder?eventId=123&studentId=456' > order.json\n# edit quantities in order.json\ncurl -sS -X POST \"$MHLB/api/event/createOrder\" \\\n  -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Content-Type: application/json' \\\n  -d @order.json\n```\n\nAnything missing from the payload is **cleared**, not preserved.\n\n**The write request bodies are unverified** — their paths and verbs were read\nout of the site's own compiled client, but no write has been exercised against a\nlive account. Inspect what you are about to send, and re-read the resource\nafterwards to confirm it landed. A `200` is not proof.\n\n`/payment/checkout` charges a real card. Do not call it speculatively.\n\n## Reading the errors\n\n| Status | Meaning |\n|---|---|\n| `400` + `invalid_grant` | wrong username/password — **do not retry** |\n| `401` on an API call | token expired; run `mhlb_login` again |\n| `403` | the endpoint belongs to the school-admin or vendor role, not a parent |\n| non-JSON `200` | either a `/parentReports/print*` PDF (expected — see references) or the session lapsed into an HTML page |\n| `500` on `/parentReports/printOrders` | usually a caller mistake: empty `studentIds`, or no order matching that date and status |\n\n## Prefer the MCP when it is available\n\n`myhotlunchbox-mcp` wraps all of this with typed tools and a confirmation step\nfor every mutation — a prompt, or a preview plus a single-use `confirmToken`.\nUse this skill when the MCP is not installed, or inside a script.\n\nFile v1.2.0:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"myhotlunchbox-mcp\",\n  \"version\": \"1.2.0\",\n  \"publishedAt\": 1790262819936\n}\n\nFile v1.2.0:references/endpoints.md\n\n# My Hot Lunchbox endpoints — ready-to-run\n\nAll paths are relative to `$MHLB/api`. All need `Authorization: Bearer $MHLB_TOKEN`.\nAssumes the `mhlb_get` helper from `SKILL.md` is defined.\n\n## Account\n\n```sh\n# Account claims: name, role, student count, credit balances, subscription state\nmhlb_get /auth/userinfo | jq .\n```\n\n## Students\n\n```sh\nmhlb_get /parent/childrenInfo | jq '.[] | {id, firstName, schoolName, gradeTeacher, hasOrders, isInactive, isInvited}'\n\n# Editable profile for one student (also the model that POST /parent/editChild takes back)\nmhlb_get '/parent/editChild?childId=456' | jq .\n\n# Blank profile + dropdown options for adding a student\nmhlb_get /parent/createChild | jq .\n```\n\n## Calendar and deliveries\n\n```sh\n# Lunch calendar for a range — a POST that reads\nmhlb_post() {\n  local endpoint=$1; shift   # NOT `path`: zsh ties $path to $PATH\n  curl -sS -X POST \"$MHLB/api$endpoint\" -H \"Authorization: Bearer $MHLB_TOKEN\" \\\n    -H 'Content-Type: application/json' -d \"${1:-{\\}}\"\n}\n\n# Fields are `start`/`end` — `startDate`/`endDate` silently returns zero events.\nmhlb_post /calendar/studentSchoolData '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\"}' | jq .\n\n# Events carry the ids the ordering endpoints need:\nmhlb_post /calendar/studentSchoolData '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\"}' \\\n  | jq '.events[] | {studentId, eventId: .id, orderId, date: .start[0:10], className}'\n\n# What one student has on one day\nmhlb_get '/calendar/studentOrderItems?studentId=456&date=2026-09-14' | jq .\n```\n\n`/deliveryInfo/*` and `/calendar/viewMatchedVendors` look parent-facing in the\nsite's compiled client but return **403** for a parent account — they belong to\nthe school and vendor dashboards. Verified live; don't reach for them.\n\n## Cart and menu\n\n```sh\n# Valid filter values first — periods (semesters) and status tabs\nmhlb_get /event/ShoppingCartBaseData | jq '{periods: [.periods[] | {text, value, selected}]}'\n\n# The cart itself; every filter is optional\nmhlb_get '/event/shoppingCart' | jq .\nmhlb_get '/event/shoppingCart?selectedStudentId=456' | jq .\n\n# The orderable menu for a student on a date — vendor, items, sizes, prices, cutoff\nmhlb_get '/event/orderBaseData?studentId=456&eventDate=2026-09-14' | jq .\n```\n\n## Transactions and subscriptions\n\n```sh\nmhlb_get /event/transactionsList              | jq .\nmhlb_get '/event/transactionDetails?id=999' | jq .   # id comes from transactionsList\nmhlb_get /event/subscription                  | jq .\nmhlb_get '/event/upcomingSubscriptions'       | jq .\n```\n\n## Gift cards and coupons\n\n```sh\nmhlb_get /parent/giftCardDataTables | jq .\nmhlb_get /parent/coupon             | jq .\n```\n\n## Printable reports\n\nThese stream a **binary PDF**, not JSON — pipe to a file, never to `jq`. Their\npayloads are not date ranges.\n\n```sh\nmhlb_pdf() {  # usage: mhlb_pdf <endpoint> <json> <out.pdf>\n  curl -sS -X POST \"$MHLB/api$1\" -H \"Authorization: Bearer $MHLB_TOKEN\" \\\n    -H 'Content-Type: application/json' -d \"$2\" -o \"$3\" && file \"$3\"\n}\n\n# Calendar — needs `middle` (the midpoint date, which titles the PDF) and a\n# NON-EMPTY studentIds. There is no \"all students\" default: an empty or omitted\n# list answers 500, same as printOrders.\nmhlb_pdf /parentReports/printCalendar \\\n  '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\",\"middle\":\"2026-09-15\",\"studentIds\":[111627]}' \\\n  'Lunch Calendar.pdf'\n\n# Orders — ONE date, not a range. studentIds must be non-empty.\n# orderStatus: 0 = Pending, 1 = Paid, 2 = Credited.\nmhlb_pdf /parentReports/printOrders \\\n  '{\"orderStatus\":1,\"eventDate\":\"2026-09-14\",\"studentIds\":[111627]}' \\\n  'Orders Details.pdf'\n\n# One transaction receipt — send the record from transactionDetails.\n# (A transactionsList ROW is a different shape and renders a thinner PDF;\n#  the list is only used here to get the id.)\nID=$(mhlb_get /event/transactionsList | jq -r '.transactions[0].id')\nmhlb_get \"/event/transactionDetails?id=$ID\" | jq -c '. + {isCreditType:false}' > tx.json\nmhlb_pdf /parentReports/printTransactions \"$(cat tx.json)\" 'Transaction.pdf'\n```\n\nBoth `printCalendar` and `printOrders` answer **500** — not a 4xx — when\n`studentIds` is empty, and `printOrders` also 500s when no order matches the\ndate and status. Treat a 500 from either as a bad request, not an outage.\n\n`printTransactions` wants the record from `/event/transactionDetails`, **not** a\nrow from `/event/transactionsList` — both render, but they are different shapes\nand different documents. The list is only used to get the id, as the recipe\nabove does.\n\n## Writes — all UNVERIFIED\n\nPaths and verbs are read out of the site's compiled client and are reliable.\nThe **request bodies** have not been exercised against a live account. Fetch the\nmodel, edit it, post it back whole, then re-read to confirm.\n\n| Action | Read the model | Post it back |\n|---|---|---|\n| Place an order | `GET /event/createOrder?eventId=&studentId=` | `POST /event/createOrder` |\n| Change an order | `GET /event/editOrder?orderId=` | `POST /event/editOrder` |\n| Cancel an order | — | `POST /event/deleteOrder` — body below, **not** the order model |\n| Add a student | `GET /parent/createChild` | `POST /parent/createChild` |\n| Edit a student | `GET /parent/editChild?childId=` | `POST /parent/editChild` |\n| Remove a student | — | `POST /parent/deleteChild?id=` |\n| Apply a gift card | — | `POST /parent/applyGiftCard?giftCardCode=` |\n| Apply a coupon | — | `POST /parent/applyCoupon?couponCode=` |\n| Remove the coupon | — | `POST /parent/removeCoupon` |\n| Toggle subscriptions | `GET /event/subscription` | `POST /parent/changeSubscriptionStatus?isEnableSubscription=` |\n| Stop one subscription | `GET /event/upcomingSubscriptions` | `POST /event/unsubcribeOrder` — same body as deleteOrder |\n| Price the cart | — | `POST /payment/initCheckout` |\n| **Pay** | — | `POST /payment/checkout` |\n\n`POST /event/unsubcribeOrder` is spelled that way upstream — the typo is theirs.\n\nCancelling and unsubscribing take a small identifier payload, **not** the order\nmodel that create/edit round-trip. Captured from the site's own `order-mixin`:\n\n```sh\n# isRepeated: true acts on the whole recurring series, not just this date.\nmhlb_post /event/deleteOrder \\\n  '{\"orderId\":17284377,\"eventDate\":\"2026-08-26\",\"studentId\":111627,\"isRepeated\":false,\"isSubscribed\":false}'\n```\n\nCheckout takes `{orderIds, checkoutType, couponCode, giftCardCode, schoolDonations}`,\nwith the nulls sent explicitly, plus `{availableCredits, idempotencyKey, stripeToken}`\non `/payment/checkout`:\n\n```sh\nmhlb_post /payment/initCheckout \\\n  '{\"orderIds\":[123],\"checkoutType\":null,\"couponCode\":null,\"giftCardCode\":null,\"schoolDonations\":null}'\n```\n\nTwo things about paying:\n\n- **`stripeToken` cannot be produced outside a browser.** The site mints it with\n  Stripe.js, and only when paying by a NEW card. Server-side you can only pay\n  with a card already saved on the account.\n- **`idempotencyKey` is yours to generate** — the site uses\n  `\"$(uuidgen | tr A-Z a-z)-$(date +%s000)\"`. Reuse the SAME key when retrying an\n  ambiguous checkout; a fresh one risks a second charge.\n\n`POST /payment/checkout` charges a real payment method. Price with\n`initCheckout` first, read the total it returns, and confirm that figure before\npaying.\n\n## Endpoints a parent account cannot reach\n\nThe same bundle serves school-admin and vendor roles. These return `403` for a\nparent and are listed only so a `403` is not mistaken for a broken session:\n`/school`, `/schoolManagement`, `/schoolOnboarding`, `/vendor`, `/vendorReports`,\n`/schoolVendorReports`, `/item`, `/adminTasks`, `/quickbooks`, `/docusign`,\n`/interactiveDistributionReport`, `/upload`, `/deliveryInfo`, and\n`/calendar/viewMatchedVendors`.\n\nFile v1.2.0:skill-card.md\n\n## Description:\n\nProvides shell and curl guidance for reading and managing a My Hot Lunchbox school-lunch account, including sign-in, students, lunch calendar, cart, orders, deliveries, and payments.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nExternal users and developers with a My Hot Lunchbox account use this skill to script account reads and cautiously prepare account changes when the MCP server is unavailable. It is especially suited to shell workflows that need curl examples, endpoint notes, and payload guidance.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Shell/API commands can change lunch-account data or charge a saved payment card.\n\nMitigation: Review the full payload and payment total before any mutation or checkout, and prefer the MCP flow for mutations because it provides confirmation controls.\n\nRisk: Repeated failed password sign-ins can escalate to a CAPTCHA and remove server-side sign-in for the account.\n\nMitigation: Stop after an invalid_grant response and check credentials instead of retrying.\n\nRisk: Write request bodies are documented as unverified, and missing fields in read-modify-write payloads may clear existing account data.\n\nMitigation: Fetch the current model, inspect the edited payload, post it only after review, and re-read the resource afterward to confirm the result.\n\n## Reference(s):\n\n- [My Hot Lunchbox endpoints](references/endpoints.md)\n- [My Hot Lunchbox API host](https://ordernow.myhotlunchbox.com)\n- [ClawHub skill page](https://clawhub.ai/chrischall/skills/myhotlunchbox-mcp)\n\n## Skill Output:\n\n**Output Type(s):** [Text, Markdown, Shell commands, Configuration instructions, Guidance]\n\n**Output Format:** [Markdown with shell command examples and JSON payload examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [May include curl and jq snippets that require user-provided credentials and review before execution.]\n\n## Skill Version(s):\n\n1.2.0 (source: server release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.1.4: 4 files, 7638 bytes\n\nFiles: references/endpoints.md (7715b), skill-card.md (2892b), SKILL.md (4732b), _meta.json (136b)\n\nFile v1.1.4:SKILL.md\n\n---\nname: myhotlunchbox\ndescription: Read and manage a My Hot Lunchbox school-lunch account from a shell with curl — sign in, list students, read the lunch calendar and cart, check orders, deliveries and payments. Use when you want My Hot Lunchbox data without running the MCP server, in a script, or on a machine where the MCP is not installed.\n---\n\n# My Hot Lunchbox from the shell\n\n`ordernow.myhotlunchbox.com` exposes a plain JSON API behind an OAuth2 password\ngrant. It is reachable server-side — no browser, no extension, no bridge. Two\n`curl` calls get you data: one to sign in, one per read.\n\n## Sign in once per shell\n\nCredentials come from the environment; never paste them into a command line\n(that puts them in shell history).\n\n```sh\nexport MHLB_USER='you@example.com'\nexport MHLB_PASS='…'          # e.g. read -rs MHLB_PASS\nexport MHLB=https://ordernow.myhotlunchbox.com\n\nmhlb_login() {\n  local resp\n  resp=$(curl -sS -X POST \"$MHLB/api/auth/login\" \\\n    -H 'Content-Type: application/x-www-form-urlencoded' \\\n    -H 'Accept: application/json' \\\n    --data-urlencode 'grant_type=password' \\\n    --data-urlencode \"username=$MHLB_USER\" \\\n    --data-urlencode \"password=$MHLB_PASS\" \\\n    --data-urlencode 'scope=openid offline_access email profile roles') || return 1\n  MHLB_TOKEN=$(printf '%s' \"$resp\" | jq -r '.access_token // empty')\n  if [ -z \"$MHLB_TOKEN\" ]; then\n    printf '%s' \"$resp\" | jq -r '.error_description // .error // \"login failed\"' >&2\n    return 1\n  fi\n  export MHLB_TOKEN\n}\n\n# Authenticated GET.  usage: mhlb_get /parent/childrenInfo [curl args…]\nmhlb_get() {\n  local endpoint=$1; shift   # NOT `path`: zsh ties $path to $PATH\n  curl -sS \"$MHLB/api$endpoint\" -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Accept: application/json' \"$@\"\n}\n\nmhlb_login && mhlb_get /auth/userinfo | jq '{name, email, students_count, pending_orders_count, parent_credit_value}'\n```\n\n**A failed sign-in must not be retried.** The server is OpenIddict and counts\nfailed attempts; repeated failures can escalate to a CAPTCHA and remove\nserver-side sign-in for that account entirely. If `invalid_grant` comes back,\nstop and check the credentials.\n\nThe token lasts about an hour. Re-run `mhlb_login` when a call starts returning\n`401`.\n\n## The three reads that answer most questions\n\n```sh\n# Who the students are — the id feeds everything else\nmhlb_get /parent/childrenInfo | jq '.[] | {id, firstName, schoolName, gradeTeacher, isInactive}'\n\n# The lunch calendar for a date range (POST, despite being a read).\n# The fields are `start`/`end`. Using `startDate`/`endDate` returns 200 with an\n# EMPTY events array — a silent wrong answer, not an error.\ncurl -sS -X POST \"$MHLB/api/calendar/studentSchoolData\" \\\n  -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Content-Type: application/json' \\\n  -d '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\"}' | jq '.events[] | {studentId, id, start, className}'\n\n# What is in the cart but not yet paid for\nmhlb_get '/event/shoppingCart' | jq .\n```\n\n`references/endpoints.md` has the rest — deliveries, transactions,\nsubscriptions, gift cards, per-day order detail, and the printable reports.\n\n## Ordering is read-modify-write\n\nThere is no \"add item X\" call. To place or change an order you fetch the model,\nedit it, and post it back whole:\n\n```sh\nmhlb_get '/event/createOrder?eventId=123&studentId=456' > order.json\n# edit quantities in order.json\ncurl -sS -X POST \"$MHLB/api/event/createOrder\" \\\n  -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Content-Type: application/json' \\\n  -d @order.json\n```\n\nAnything missing from the payload is **cleared**, not preserved.\n\n**The write request bodies are unverified** — their paths and verbs were read\nout of the site's own compiled client, but no write has been exercised against a\nlive account. Inspect what you are about to send, and re-read the resource\nafterwards to confirm it landed. A `200` is not proof.\n\n`/payment/checkout` charges a real card. Do not call it speculatively.\n\n## Reading the errors\n\n| Status | Meaning |\n|---|---|\n| `400` + `invalid_grant` | wrong username/password — **do not retry** |\n| `401` on an API call | token expired; run `mhlb_login` again |\n| `403` | the endpoint belongs to the school-admin or vendor role, not a parent |\n| non-JSON `200` | either a `/parentReports/print*` PDF (expected — see references) or the session lapsed into an HTML page |\n| `500` on `/parentReports/printOrders` | usually a caller mistake: empty `studentIds`, or no order matching that date and status |\n\n## Prefer the MCP when it is available\n\n`myhotlunchbox-mcp` wraps all of this with typed tools, confirm-gated writes and\na dry-run preview for every mutation. Use this skill when the MCP is not\ninstalled, or inside a script.\n\nFile v1.1.4:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"myhotlunchbox-mcp\",\n  \"version\": \"1.1.4\",\n  \"publishedAt\": 1790199612460\n}\n\nFile v1.1.4:references/endpoints.md\n\n# My Hot Lunchbox endpoints — ready-to-run\n\nAll paths are relative to `$MHLB/api`. All need `Authorization: Bearer $MHLB_TOKEN`.\nAssumes the `mhlb_get` helper from `SKILL.md` is defined.\n\n## Account\n\n```sh\n# Account claims: name, role, student count, credit balances, subscription state\nmhlb_get /auth/userinfo | jq .\n```\n\n## Students\n\n```sh\nmhlb_get /parent/childrenInfo | jq '.[] | {id, firstName, schoolName, gradeTeacher, hasOrders, isInactive, isInvited}'\n\n# Editable profile for one student (also the model that POST /parent/editChild takes back)\nmhlb_get '/parent/editChild?childId=456' | jq .\n\n# Blank profile + dropdown options for adding a student\nmhlb_get /parent/createChild | jq .\n```\n\n## Calendar and deliveries\n\n```sh\n# Lunch calendar for a range — a POST that reads\nmhlb_post() {\n  local endpoint=$1; shift   # NOT `path`: zsh ties $path to $PATH\n  curl -sS -X POST \"$MHLB/api$endpoint\" -H \"Authorization: Bearer $MHLB_TOKEN\" \\\n    -H 'Content-Type: application/json' -d \"${1:-{\\}}\"\n}\n\n# Fields are `start`/`end` — `startDate`/`endDate` silently returns zero events.\nmhlb_post /calendar/studentSchoolData '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\"}' | jq .\n\n# Events carry the ids the ordering endpoints need:\nmhlb_post /calendar/studentSchoolData '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\"}' \\\n  | jq '.events[] | {studentId, eventId: .id, orderId, date: .start[0:10], className}'\n\n# What one student has on one day\nmhlb_get '/calendar/studentOrderItems?studentId=456&date=2026-09-14' | jq .\n```\n\n`/deliveryInfo/*` and `/calendar/viewMatchedVendors` look parent-facing in the\nsite's compiled client but return **403** for a parent account — they belong to\nthe school and vendor dashboards. Verified live; don't reach for them.\n\n## Cart and menu\n\n```sh\n# Valid filter values first — periods (semesters) and status tabs\nmhlb_get /event/ShoppingCartBaseData | jq '{periods: [.periods[] | {text, value, selected}]}'\n\n# The cart itself; every filter is optional\nmhlb_get '/event/shoppingCart' | jq .\nmhlb_get '/event/shoppingCart?selectedStudentId=456' | jq .\n\n# The orderable menu for a student on a date — vendor, items, sizes, prices, cutoff\nmhlb_get '/event/orderBaseData?studentId=456&eventDate=2026-09-14' | jq .\n```\n\n## Transactions and subscriptions\n\n```sh\nmhlb_get /event/transactionsList              | jq .\nmhlb_get '/event/transactionDetails?id=999' | jq .   # id comes from transactionsList\nmhlb_get /event/subscription                  | jq .\nmhlb_get '/event/upcomingSubscriptions'       | jq .\n```\n\n## Gift cards and coupons\n\n```sh\nmhlb_get /parent/giftCardDataTables | jq .\nmhlb_get /parent/coupon             | jq .\n```\n\n## Printable reports\n\nThese stream a **binary PDF**, not JSON — pipe to a file, never to `jq`. Their\npayloads are not date ranges.\n\n```sh\nmhlb_pdf() {  # usage: mhlb_pdf <endpoint> <json> <out.pdf>\n  curl -sS -X POST \"$MHLB/api$1\" -H \"Authorization: Bearer $MHLB_TOKEN\" \\\n    -H 'Content-Type: application/json' -d \"$2\" -o \"$3\" && file \"$3\"\n}\n\n# Calendar — needs `middle` (the midpoint date, which titles the PDF) and a\n# NON-EMPTY studentIds. There is no \"all students\" default: an empty or omitted\n# list answers 500, same as printOrders.\nmhlb_pdf /parentReports/printCalendar \\\n  '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\",\"middle\":\"2026-09-15\",\"studentIds\":[111627]}' \\\n  'Lunch Calendar.pdf'\n\n# Orders — ONE date, not a range. studentIds must be non-empty.\n# orderStatus: 0 = Pending, 1 = Paid, 2 = Credited.\nmhlb_pdf /parentReports/printOrders \\\n  '{\"orderStatus\":1,\"eventDate\":\"2026-09-14\",\"studentIds\":[111627]}' \\\n  'Orders Details.pdf'\n\n# One transaction receipt — send the record from transactionDetails.\n# (A transactionsList ROW is a different shape and renders a thinner PDF;\n#  the list is only used here to get the id.)\nID=$(mhlb_get /event/transactionsList | jq -r '.transactions[0].id')\nmhlb_get \"/event/transactionDetails?id=$ID\" | jq -c '. + {isCreditType:false}' > tx.json\nmhlb_pdf /parentReports/printTransactions \"$(cat tx.json)\" 'Transaction.pdf'\n```\n\nBoth `printCalendar` and `printOrders` answer **500** — not a 4xx — when\n`studentIds` is empty, and `printOrders` also 500s when no order matches the\ndate and status. Treat a 500 from either as a bad request, not an outage.\n\n`printTransactions` wants the record from `/event/transactionDetails`, **not** a\nrow from `/event/transactionsList` — both render, but they are different shapes\nand different documents. The list is only used to get the id, as the recipe\nabove does.\n\n## Writes — all UNVERIFIED\n\nPaths and verbs are read out of the site's compiled client and are reliable.\nThe **request bodies** have not been exercised against a live account. Fetch the\nmodel, edit it, post it back whole, then re-read to confirm.\n\n| Action | Read the model | Post it back |\n|---|---|---|\n| Place an order | `GET /event/createOrder?eventId=&studentId=` | `POST /event/createOrder` |\n| Change an order | `GET /event/editOrder?orderId=` | `POST /event/editOrder` |\n| Cancel an order | — | `POST /event/deleteOrder` — body below, **not** the order model |\n| Add a student | `GET /parent/createChild` | `POST /parent/createChild` |\n| Edit a student | `GET /parent/editChild?childId=` | `POST /parent/editChild` |\n| Remove a student | — | `POST /parent/deleteChild?id=` |\n| Apply a gift card | — | `POST /parent/applyGiftCard?giftCardCode=` |\n| Apply a coupon | — | `POST /parent/applyCoupon?couponCode=` |\n| Remove the coupon | — | `POST /parent/removeCoupon` |\n| Toggle subscriptions | `GET /event/subscription` | `POST /parent/changeSubscriptionStatus?isEnableSubscription=` |\n| Stop one subscription | `GET /event/upcomingSubscriptions` | `POST /event/unsubcribeOrder` — same body as deleteOrder |\n| Price the cart | — | `POST /payment/initCheckout` |\n| **Pay** | — | `POST /payment/checkout` |\n\n`POST /event/unsubcribeOrder` is spelled that way upstream — the typo is theirs.\n\nCancelling and unsubscribing take a small identifier payload, **not** the order\nmodel that create/edit round-trip. Captured from the site's own `order-mixin`:\n\n```sh\n# isRepeated: true acts on the whole recurring series, not just this date.\nmhlb_post /event/deleteOrder \\\n  '{\"orderId\":17284377,\"eventDate\":\"2026-08-26\",\"studentId\":111627,\"isRepeated\":false,\"isSubscribed\":false}'\n```\n\nCheckout takes `{orderIds, checkoutType, couponCode, giftCardCode, schoolDonations}`,\nwith the nulls sent explicitly, plus `{availableCredits, idempotencyKey, stripeToken}`\non `/payment/checkout`:\n\n```sh\nmhlb_post /payment/initCheckout \\\n  '{\"orderIds\":[123],\"checkoutType\":null,\"couponCode\":null,\"giftCardCode\":null,\"schoolDonations\":null}'\n```\n\nTwo things about paying:\n\n- **`stripeToken` cannot be produced outside a browser.** The site mints it with\n  Stripe.js, and only when paying by a NEW card. Server-side you can only pay\n  with a card already saved on the account.\n- **`idempotencyKey` is yours to generate** — the site uses\n  `\"$(uuidgen | tr A-Z a-z)-$(date +%s000)\"`. Reuse the SAME key when retrying an\n  ambiguous checkout; a fresh one risks a second charge.\n\n`POST /payment/checkout` charges a real payment method. Price with\n`initCheckout` first, read the total it returns, and confirm that figure before\npaying.\n\n## Endpoints a parent account cannot reach\n\nThe same bundle serves school-admin and vendor roles. These return `403` for a\nparent and are listed only so a `403` is not mistaken for a broken session:\n`/school`, `/schoolManagement`, `/schoolOnboarding`, `/vendor`, `/vendorReports`,\n`/schoolVendorReports`, `/item`, `/adminTasks`, `/quickbooks`, `/docusign`,\n`/interactiveDistributionReport`, `/upload`, `/deliveryInfo`, and\n`/calendar/viewMatchedVendors`.\n\nFile v1.1.4:skill-card.md\n\n## Description:\n\nRead and manage a My Hot Lunchbox school-lunch account from a shell with curl: sign in, list students, read the lunch calendar and cart, and check orders, deliveries, and payments.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers, operators, and My Hot Lunchbox account users can use this skill to retrieve account, student, calendar, cart, order, transaction, and report data from shell-based workflows when the MCP server is unavailable or not installed. It also documents write and checkout endpoints, which require careful manual review before use.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Raw shell commands can operate against a live My Hot Lunchbox account and may expose credentials or account data if copied into unsafe environments.\n\nMitigation: Load credentials from environment variables or secure prompts, avoid pasting secrets into command history, and inspect commands before execution.\n\nRisk: Write, delete, subscription, coupon, and checkout endpoints can change account state or charge a payment method without built-in safeguards.\n\nMitigation: Treat these operations as manual-only, inspect every payload and price, require explicit confirmation, and prefer the MCP server when available because it provides confirm-gated writes and dry-run previews.\n\nRisk: Unverified write request bodies can clear omitted fields or appear successful without proving the intended account change occurred.\n\nMitigation: Fetch the current model before editing, post complete payloads, and re-read the affected resource after a 200 response to confirm the result.\n\nRisk: Repeated failed sign-in attempts can trigger CAPTCHA or block server-side sign-in for the account.\n\nMitigation: Stop after an invalid_grant response and verify credentials before retrying.\n\n## Reference(s):\n\n- [My Hot Lunchbox endpoints](references/endpoints.md)\n- [My Hot Lunchbox order site](https://ordernow.myhotlunchbox.com)\n- [ClawHub skill page](https://clawhub.ai/chrischall/skills/myhotlunchbox-mcp)\n\n## Skill Output:\n\n**Output Type(s):** [guidance, shell commands, configuration, code]\n\n**Output Format:** [Markdown with inline shell commands and JSON request examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [The skill guides an agent to use curl and jq against live account APIs and to produce command snippets, request payloads, and operational cautions.]\n\n## Skill Version(s):\n\n1.1.4 (source: server release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.1.3: 4 files, 7413 bytes\n\nFiles: references/endpoints.md (7715b), skill-card.md (2369b), SKILL.md (4732b), _meta.json (136b)\n\nFile v1.1.3:SKILL.md\n\n---\nname: myhotlunchbox\ndescription: Read and manage a My Hot Lunchbox school-lunch account from a shell with curl — sign in, list students, read the lunch calendar and cart, check orders, deliveries and payments. Use when you want My Hot Lunchbox data without running the MCP server, in a script, or on a machine where the MCP is not installed.\n---\n\n# My Hot Lunchbox from the shell\n\n`ordernow.myhotlunchbox.com` exposes a plain JSON API behind an OAuth2 password\ngrant. It is reachable server-side — no browser, no extension, no bridge. Two\n`curl` calls get you data: one to sign in, one per read.\n\n## Sign in once per shell\n\nCredentials come from the environment; never paste them into a command line\n(that puts them in shell history).\n\n```sh\nexport MHLB_USER='you@example.com'\nexport MHLB_PASS='…'          # e.g. read -rs MHLB_PASS\nexport MHLB=https://ordernow.myhotlunchbox.com\n\nmhlb_login() {\n  local resp\n  resp=$(curl -sS -X POST \"$MHLB/api/auth/login\" \\\n    -H 'Content-Type: application/x-www-form-urlencoded' \\\n    -H 'Accept: application/json' \\\n    --data-urlencode 'grant_type=password' \\\n    --data-urlencode \"username=$MHLB_USER\" \\\n    --data-urlencode \"password=$MHLB_PASS\" \\\n    --data-urlencode 'scope=openid offline_access email profile roles') || return 1\n  MHLB_TOKEN=$(printf '%s' \"$resp\" | jq -r '.access_token // empty')\n  if [ -z \"$MHLB_TOKEN\" ]; then\n    printf '%s' \"$resp\" | jq -r '.error_description // .error // \"login failed\"' >&2\n    return 1\n  fi\n  export MHLB_TOKEN\n}\n\n# Authenticated GET.  usage: mhlb_get /parent/childrenInfo [curl args…]\nmhlb_get() {\n  local endpoint=$1; shift   # NOT `path`: zsh ties $path to $PATH\n  curl -sS \"$MHLB/api$endpoint\" -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Accept: application/json' \"$@\"\n}\n\nmhlb_login && mhlb_get /auth/userinfo | jq '{name, email, students_count, pending_orders_count, parent_credit_value}'\n```\n\n**A failed sign-in must not be retried.** The server is OpenIddict and counts\nfailed attempts; repeated failures can escalate to a CAPTCHA and remove\nserver-side sign-in for that account entirely. If `invalid_grant` comes back,\nstop and check the credentials.\n\nThe token lasts about an hour. Re-run `mhlb_login` when a call starts returning\n`401`.\n\n## The three reads that answer most questions\n\n```sh\n# Who the students are — the id feeds everything else\nmhlb_get /parent/childrenInfo | jq '.[] | {id, firstName, schoolName, gradeTeacher, isInactive}'\n\n# The lunch calendar for a date range (POST, despite being a read).\n# The fields are `start`/`end`. Using `startDate`/`endDate` returns 200 with an\n# EMPTY events array — a silent wrong answer, not an error.\ncurl -sS -X POST \"$MHLB/api/calendar/studentSchoolData\" \\\n  -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Content-Type: application/json' \\\n  -d '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\"}' | jq '.events[] | {studentId, id, start, className}'\n\n# What is in the cart but not yet paid for\nmhlb_get '/event/shoppingCart' | jq .\n```\n\n`references/endpoints.md` has the rest — deliveries, transactions,\nsubscriptions, gift cards, per-day order detail, and the printable reports.\n\n## Ordering is read-modify-write\n\nThere is no \"add item X\" call. To place or change an order you fetch the model,\nedit it, and post it back whole:\n\n```sh\nmhlb_get '/event/createOrder?eventId=123&studentId=456' > order.json\n# edit quantities in order.json\ncurl -sS -X POST \"$MHLB/api/event/createOrder\" \\\n  -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Content-Type: application/json' \\\n  -d @order.json\n```\n\nAnything missing from the payload is **cleared**, not preserved.\n\n**The write request bodies are unverified** — their paths and verbs were read\nout of the site's own compiled client, but no write has been exercised against a\nlive account. Inspect what you are about to send, and re-read the resource\nafterwards to confirm it landed. A `200` is not proof.\n\n`/payment/checkout` charges a real card. Do not call it speculatively.\n\n## Reading the errors\n\n| Status | Meaning |\n|---|---|\n| `400` + `invalid_grant` | wrong username/password — **do not retry** |\n| `401` on an API call | token expired; run `mhlb_login` again |\n| `403` | the endpoint belongs to the school-admin or vendor role, not a parent |\n| non-JSON `200` | either a `/parentReports/print*` PDF (expected — see references) or the session lapsed into an HTML page |\n| `500` on `/parentReports/printOrders` | usually a caller mistake: empty `studentIds`, or no order matching that date and status |\n\n## Prefer the MCP when it is available\n\n`myhotlunchbox-mcp` wraps all of this with typed tools, confirm-gated writes and\na dry-run preview for every mutation. Use this skill when the MCP is not\ninstalled, or inside a script.\n\nFile v1.1.3:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"myhotlunchbox-mcp\",\n  \"version\": \"1.1.3\",\n  \"publishedAt\": 1790178335147\n}\n\nFile v1.1.3:references/endpoints.md\n\n# My Hot Lunchbox endpoints — ready-to-run\n\nAll paths are relative to `$MHLB/api`. All need `Authorization: Bearer $MHLB_TOKEN`.\nAssumes the `mhlb_get` helper from `SKILL.md` is defined.\n\n## Account\n\n```sh\n# Account claims: name, role, student count, credit balances, subscription state\nmhlb_get /auth/userinfo | jq .\n```\n\n## Students\n\n```sh\nmhlb_get /parent/childrenInfo | jq '.[] | {id, firstName, schoolName, gradeTeacher, hasOrders, isInactive, isInvited}'\n\n# Editable profile for one student (also the model that POST /parent/editChild takes back)\nmhlb_get '/parent/editChild?childId=456' | jq .\n\n# Blank profile + dropdown options for adding a student\nmhlb_get /parent/createChild | jq .\n```\n\n## Calendar and deliveries\n\n```sh\n# Lunch calendar for a range — a POST that reads\nmhlb_post() {\n  local endpoint=$1; shift   # NOT `path`: zsh ties $path to $PATH\n  curl -sS -X POST \"$MHLB/api$endpoint\" -H \"Authorization: Bearer $MHLB_TOKEN\" \\\n    -H 'Content-Type: application/json' -d \"${1:-{\\}}\"\n}\n\n# Fields are `start`/`end` — `startDate`/`endDate` silently returns zero events.\nmhlb_post /calendar/studentSchoolData '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\"}' | jq .\n\n# Events carry the ids the ordering endpoints need:\nmhlb_post /calendar/studentSchoolData '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\"}' \\\n  | jq '.events[] | {studentId, eventId: .id, orderId, date: .start[0:10], className}'\n\n# What one student has on one day\nmhlb_get '/calendar/studentOrderItems?studentId=456&date=2026-09-14' | jq .\n```\n\n`/deliveryInfo/*` and `/calendar/viewMatchedVendors` look parent-facing in the\nsite's compiled client but return **403** for a parent account — they belong to\nthe school and vendor dashboards. Verified live; don't reach for them.\n\n## Cart and menu\n\n```sh\n# Valid filter values first — periods (semesters) and status tabs\nmhlb_get /event/ShoppingCartBaseData | jq '{periods: [.periods[] | {text, value, selected}]}'\n\n# The cart itself; every filter is optional\nmhlb_get '/event/shoppingCart' | jq .\nmhlb_get '/event/shoppingCart?selectedStudentId=456' | jq .\n\n# The orderable menu for a student on a date — vendor, items, sizes, prices, cutoff\nmhlb_get '/event/orderBaseData?studentId=456&eventDate=2026-09-14' | jq .\n```\n\n## Transactions and subscriptions\n\n```sh\nmhlb_get /event/transactionsList              | jq .\nmhlb_get '/event/transactionDetails?id=999' | jq .   # id comes from transactionsList\nmhlb_get /event/subscription                  | jq .\nmhlb_get '/event/upcomingSubscriptions'       | jq .\n```\n\n## Gift cards and coupons\n\n```sh\nmhlb_get /parent/giftCardDataTables | jq .\nmhlb_get /parent/coupon             | jq .\n```\n\n## Printable reports\n\nThese stream a **binary PDF**, not JSON — pipe to a file, never to `jq`. Their\npayloads are not date ranges.\n\n```sh\nmhlb_pdf() {  # usage: mhlb_pdf <endpoint> <json> <out.pdf>\n  curl -sS -X POST \"$MHLB/api$1\" -H \"Authorization: Bearer $MHLB_TOKEN\" \\\n    -H 'Content-Type: application/json' -d \"$2\" -o \"$3\" && file \"$3\"\n}\n\n# Calendar — needs `middle` (the midpoint date, which titles the PDF) and a\n# NON-EMPTY studentIds. There is no \"all students\" default: an empty or omitted\n# list answers 500, same as printOrders.\nmhlb_pdf /parentReports/printCalendar \\\n  '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\",\"middle\":\"2026-09-15\",\"studentIds\":[111627]}' \\\n  'Lunch Calendar.pdf'\n\n# Orders — ONE date, not a range. studentIds must be non-empty.\n# orderStatus: 0 = Pending, 1 = Paid, 2 = Credited.\nmhlb_pdf /parentReports/printOrders \\\n  '{\"orderStatus\":1,\"eventDate\":\"2026-09-14\",\"studentIds\":[111627]}' \\\n  'Orders Details.pdf'\n\n# One transaction receipt — send the record from transactionDetails.\n# (A transactionsList ROW is a different shape and renders a thinner PDF;\n#  the list is only used here to get the id.)\nID=$(mhlb_get /event/transactionsList | jq -r '.transactions[0].id')\nmhlb_get \"/event/transactionDetails?id=$ID\" | jq -c '. + {isCreditType:false}' > tx.json\nmhlb_pdf /parentReports/printTransactions \"$(cat tx.json)\" 'Transaction.pdf'\n```\n\nBoth `printCalendar` and `printOrders` answer **500** — not a 4xx — when\n`studentIds` is empty, and `printOrders` also 500s when no order matches the\ndate and status. Treat a 500 from either as a bad request, not an outage.\n\n`printTransactions` wants the record from `/event/transactionDetails`, **not** a\nrow from `/event/transactionsList` — both render, but they are different shapes\nand different documents. The list is only used to get the id, as the recipe\nabove does.\n\n## Writes — all UNVERIFIED\n\nPaths and verbs are read out of the site's compiled client and are reliable.\nThe **request bodies** have not been exercised against a live account. Fetch the\nmodel, edit it, post it back whole, then re-read to confirm.\n\n| Action | Read the model | Post it back |\n|---|---|---|\n| Place an order | `GET /event/createOrder?eventId=&studentId=` | `POST /event/createOrder` |\n| Change an order | `GET /event/editOrder?orderId=` | `POST /event/editOrder` |\n| Cancel an order | — | `POST /event/deleteOrder` — body below, **not** the order model |\n| Add a student | `GET /parent/createChild` | `POST /parent/createChild` |\n| Edit a student | `GET /parent/editChild?childId=` | `POST /parent/editChild` |\n| Remove a student | — | `POST /parent/deleteChild?id=` |\n| Apply a gift card | — | `POST /parent/applyGiftCard?giftCardCode=` |\n| Apply a coupon | — | `POST /parent/applyCoupon?couponCode=` |\n| Remove the coupon | — | `POST /parent/removeCoupon` |\n| Toggle subscriptions | `GET /event/subscription` | `POST /parent/changeSubscriptionStatus?isEnableSubscription=` |\n| Stop one subscription | `GET /event/upcomingSubscriptions` | `POST /event/unsubcribeOrder` — same body as deleteOrder |\n| Price the cart | — | `POST /payment/initCheckout` |\n| **Pay** | — | `POST /payment/checkout` |\n\n`POST /event/unsubcribeOrder` is spelled that way upstream — the typo is theirs.\n\nCancelling and unsubscribing take a small identifier payload, **not** the order\nmodel that create/edit round-trip. Captured from the site's own `order-mixin`:\n\n```sh\n# isRepeated: true acts on the whole recurring series, not just this date.\nmhlb_post /event/deleteOrder \\\n  '{\"orderId\":17284377,\"eventDate\":\"2026-08-26\",\"studentId\":111627,\"isRepeated\":false,\"isSubscribed\":false}'\n```\n\nCheckout takes `{orderIds, checkoutType, couponCode, giftCardCode, schoolDonations}`,\nwith the nulls sent explicitly, plus `{availableCredits, idempotencyKey, stripeToken}`\non `/payment/checkout`:\n\n```sh\nmhlb_post /payment/initCheckout \\\n  '{\"orderIds\":[123],\"checkoutType\":null,\"couponCode\":null,\"giftCardCode\":null,\"schoolDonations\":null}'\n```\n\nTwo things about paying:\n\n- **`stripeToken` cannot be produced outside a browser.** The site mints it with\n  Stripe.js, and only when paying by a NEW card. Server-side you can only pay\n  with a card already saved on the account.\n- **`idempotencyKey` is yours to generate** — the site uses\n  `\"$(uuidgen | tr A-Z a-z)-$(date +%s000)\"`. Reuse the SAME key when retrying an\n  ambiguous checkout; a fresh one risks a second charge.\n\n`POST /payment/checkout` charges a real payment method. Price with\n`initCheckout` first, read the total it returns, and confirm that figure before\npaying.\n\n## Endpoints a parent account cannot reach\n\nThe same bundle serves school-admin and vendor roles. These return `403` for a\nparent and are listed only so a `403` is not mistaken for a broken session:\n`/school`, `/schoolManagement`, `/schoolOnboarding`, `/vendor`, `/vendorReports`,\n`/schoolVendorReports`, `/item`, `/adminTasks`, `/quickbooks`, `/docusign`,\n`/interactiveDistributionReport`, `/upload`, `/deliveryInfo`, and\n`/calendar/viewMatchedVendors`.\n\nFile v1.1.3:skill-card.md\n\n## Description:\n\nRead and manage a My Hot Lunchbox school-lunch account from a shell with curl, including sign-in, students, lunch calendar, cart, orders, deliveries, and payments.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nExternal users and developers use this skill to let an agent prepare shell-based My Hot Lunchbox account workflows for reading account data and, with explicit approval, managing orders, subscriptions, coupons, credits, and checkout.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Live account-changing and payment-related commands can create, edit, delete, unsubscribe, apply credits or coupons, or charge a saved payment method.\n\nMitigation: Require explicit user approval before any mutation or checkout, and prefer the MCP's confirmation and dry-run behavior for writes when available.\n\nRisk: Unverified write request bodies may clear fields or return a successful response without proving the intended change landed.\n\nMitigation: Inspect the full payload before posting it, price or preview checkout first, and re-read the resource after each write to confirm the result.\n\nRisk: Repeated failed sign-in attempts can escalate account access friction such as CAPTCHA.\n\nMitigation: Stop after an invalid_grant response and verify credentials before retrying.\n\n## Reference(s):\n\n- [My Hot Lunchbox endpoints](references/endpoints.md)\n- [My Hot Lunchbox order site](https://ordernow.myhotlunchbox.com)\n- [ClawHub skill page](https://clawhub.ai/chrischall/skills/myhotlunchbox-mcp)\n\n## Skill Output:\n\n**Output Type(s):** [Text, Markdown, Shell commands, Configuration, Guidance]\n\n**Output Format:** [Markdown with inline shell commands and JSON examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Requires user-provided My Hot Lunchbox credentials; mutation and payment commands require explicit approval before execution.]\n\n## Skill Version(s):\n\n1.1.3 (source: ClawHub release evidence)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.1.2: 4 files, 7497 bytes\n\nFiles: references/endpoints.md (7715b), skill-card.md (2618b), SKILL.md (4732b), _meta.json (136b)\n\nFile v1.1.2:SKILL.md\n\n---\nname: myhotlunchbox\ndescription: Read and manage a My Hot Lunchbox school-lunch account from a shell with curl — sign in, list students, read the lunch calendar and cart, check orders, deliveries and payments. Use when you want My Hot Lunchbox data without running the MCP server, in a script, or on a machine where the MCP is not installed.\n---\n\n# My Hot Lunchbox from the shell\n\n`ordernow.myhotlunchbox.com` exposes a plain JSON API behind an OAuth2 password\ngrant. It is reachable server-side — no browser, no extension, no bridge. Two\n`curl` calls get you data: one to sign in, one per read.\n\n## Sign in once per shell\n\nCredentials come from the environment; never paste them into a command line\n(that puts them in shell history).\n\n```sh\nexport MHLB_USER='you@example.com'\nexport MHLB_PASS='…'          # e.g. read -rs MHLB_PASS\nexport MHLB=https://ordernow.myhotlunchbox.com\n\nmhlb_login() {\n  local resp\n  resp=$(curl -sS -X POST \"$MHLB/api/auth/login\" \\\n    -H 'Content-Type: application/x-www-form-urlencoded' \\\n    -H 'Accept: application/json' \\\n    --data-urlencode 'grant_type=password' \\\n    --data-urlencode \"username=$MHLB_USER\" \\\n    --data-urlencode \"password=$MHLB_PASS\" \\\n    --data-urlencode 'scope=openid offline_access email profile roles') || return 1\n  MHLB_TOKEN=$(printf '%s' \"$resp\" | jq -r '.access_token // empty')\n  if [ -z \"$MHLB_TOKEN\" ]; then\n    printf '%s' \"$resp\" | jq -r '.error_description // .error // \"login failed\"' >&2\n    return 1\n  fi\n  export MHLB_TOKEN\n}\n\n# Authenticated GET.  usage: mhlb_get /parent/childrenInfo [curl args…]\nmhlb_get() {\n  local endpoint=$1; shift   # NOT `path`: zsh ties $path to $PATH\n  curl -sS \"$MHLB/api$endpoint\" -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Accept: application/json' \"$@\"\n}\n\nmhlb_login && mhlb_get /auth/userinfo | jq '{name, email, students_count, pending_orders_count, parent_credit_value}'\n```\n\n**A failed sign-in must not be retried.** The server is OpenIddict and counts\nfailed attempts; repeated failures can escalate to a CAPTCHA and remove\nserver-side sign-in for that account entirely. If `invalid_grant` comes back,\nstop and check the credentials.\n\nThe token lasts about an hour. Re-run `mhlb_login` when a call starts returning\n`401`.\n\n## The three reads that answer most questions\n\n```sh\n# Who the students are — the id feeds everything else\nmhlb_get /parent/childrenInfo | jq '.[] | {id, firstName, schoolName, gradeTeacher, isInactive}'\n\n# The lunch calendar for a date range (POST, despite being a read).\n# The fields are `start`/`end`. Using `startDate`/`endDate` returns 200 with an\n# EMPTY events array — a silent wrong answer, not an error.\ncurl -sS -X POST \"$MHLB/api/calendar/studentSchoolData\" \\\n  -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Content-Type: application/json' \\\n  -d '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\"}' | jq '.events[] | {studentId, id, start, className}'\n\n# What is in the cart but not yet paid for\nmhlb_get '/event/shoppingCart' | jq .\n```\n\n`references/endpoints.md` has the rest — deliveries, transactions,\nsubscriptions, gift cards, per-day order detail, and the printable reports.\n\n## Ordering is read-modify-write\n\nThere is no \"add item X\" call. To place or change an order you fetch the model,\nedit it, and post it back whole:\n\n```sh\nmhlb_get '/event/createOrder?eventId=123&studentId=456' > order.json\n# edit quantities in order.json\ncurl -sS -X POST \"$MHLB/api/event/createOrder\" \\\n  -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Content-Type: application/json' \\\n  -d @order.json\n```\n\nAnything missing from the payload is **cleared**, not preserved.\n\n**The write request bodies are unverified** — their paths and verbs were read\nout of the site's own compiled client, but no write has been exercised against a\nlive account. Inspect what you are about to send, and re-read the resource\nafterwards to confirm it landed. A `200` is not proof.\n\n`/payment/checkout` charges a real card. Do not call it speculatively.\n\n## Reading the errors\n\n| Status | Meaning |\n|---|---|\n| `400` + `invalid_grant` | wrong username/password — **do not retry** |\n| `401` on an API call | token expired; run `mhlb_login` again |\n| `403` | the endpoint belongs to the school-admin or vendor role, not a parent |\n| non-JSON `200` | either a `/parentReports/print*` PDF (expected — see references) or the session lapsed into an HTML page |\n| `500` on `/parentReports/printOrders` | usually a caller mistake: empty `studentIds`, or no order matching that date and status |\n\n## Prefer the MCP when it is available\n\n`myhotlunchbox-mcp` wraps all of this with typed tools, confirm-gated writes and\na dry-run preview for every mutation. Use this skill when the MCP is not\ninstalled, or inside a script.\n\nFile v1.1.2:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"myhotlunchbox-mcp\",\n  \"version\": \"1.1.2\",\n  \"publishedAt\": 1789989024368\n}\n\nFile v1.1.2:references/endpoints.md\n\n# My Hot Lunchbox endpoints — ready-to-run\n\nAll paths are relative to `$MHLB/api`. All need `Authorization: Bearer $MHLB_TOKEN`.\nAssumes the `mhlb_get` helper from `SKILL.md` is defined.\n\n## Account\n\n```sh\n# Account claims: name, role, student count, credit balances, subscription state\nmhlb_get /auth/userinfo | jq .\n```\n\n## Students\n\n```sh\nmhlb_get /parent/childrenInfo | jq '.[] | {id, firstName, schoolName, gradeTeacher, hasOrders, isInactive, isInvited}'\n\n# Editable profile for one student (also the model that POST /parent/editChild takes back)\nmhlb_get '/parent/editChild?childId=456' | jq .\n\n# Blank profile + dropdown options for adding a student\nmhlb_get /parent/createChild | jq .\n```\n\n## Calendar and deliveries\n\n```sh\n# Lunch calendar for a range — a POST that reads\nmhlb_post() {\n  local endpoint=$1; shift   # NOT `path`: zsh ties $path to $PATH\n  curl -sS -X POST \"$MHLB/api$endpoint\" -H \"Authorization: Bearer $MHLB_TOKEN\" \\\n    -H 'Content-Type: application/json' -d \"${1:-{\\}}\"\n}\n\n# Fields are `start`/`end` — `startDate`/`endDate` silently returns zero events.\nmhlb_post /calendar/studentSchoolData '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\"}' | jq .\n\n# Events carry the ids the ordering endpoints need:\nmhlb_post /calendar/studentSchoolData '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\"}' \\\n  | jq '.events[] | {studentId, eventId: .id, orderId, date: .start[0:10], className}'\n\n# What one student has on one day\nmhlb_get '/calendar/studentOrderItems?studentId=456&date=2026-09-14' | jq .\n```\n\n`/deliveryInfo/*` and `/calendar/viewMatchedVendors` look parent-facing in the\nsite's compiled client but return **403** for a parent account — they belong to\nthe school and vendor dashboards. Verified live; don't reach for them.\n\n## Cart and menu\n\n```sh\n# Valid filter values first — periods (semesters) and status tabs\nmhlb","readmeExcerpt":"Skill: myhotlunchbox-mcp Owner: chrischall Summary: Read and manage a My Hot Lunchbox school-lunch account from a shell with curl — sign in, list students, read the lunch calendar and cart, check orders, deliveries and payments. Use when you want My Hot Lunchbox data without running the MCP server, in a script, or on a machine where the MCP is not installed. Tags: latest:1.2.6 Version history: v1.2.6 | 2026-10-09T23:","codeSnippets":[],"executableExamples":[{"language":"sh","snippet":"curl -sS \"$MHLB/api$endpoint\" -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Accept: application/json' \"$@\""},{"language":"sh","snippet":"export MHLB_USER='you@example.com'\nexport MHLB_PASS='…'          # e.g. read -rs MHLB_PASS\nexport MHLB=https://ordernow.myhotlunchbox.com\n\nmhlb_login() {\n  local resp\n  resp=$(curl -sS -X POST \"$MHLB/api/auth/login\" \\\n    -H 'Content-Type: application/x-www-form-urlencoded' \\\n    -H 'Accept: application/json' \\\n    --data-urlencode 'grant_type=password' \\\n    --data-urlencode \"username=$MHLB_USER\" \\\n    --data-urlencode \"password=$MHLB_PASS\" \\\n    --data-urlencode 'scope=openid offline_access email profile roles') || return 1\n  MHLB_TOKEN=$(printf '%s' \"$resp\" | jq -r '.access_token // empty')\n  if [ -z \"$MHLB_TOKEN\" ]; then\n    printf '%s' \"$resp\" | jq -r '.error_description // .error // \"login failed\"' >&2\n    return 1\n  fi\n  export MHLB_TOKEN\n}\n\n# Authenticated GET.  usage: mhlb_get /parent/childrenInfo [curl args…]\nmhlb_get() {\n  local endpoint=$1; shift   # NOT `path`: zsh ties $path to $PATH\n  curl -sS \"$MHLB/api$endpoint\" -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Accept: application/json' \"$@\"\n}\n\nmhlb_login && mhlb_get /auth/userinfo | jq '{name, email, students_count, pending_orders_count, parent_credit_value}'"},{"language":"sh","snippet":"curl -sS -X POST \"$MHLB/api/calendar/studentSchoolData\" \\\n  -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Content-Type: application/json' \\\n  -d '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\"}' | jq '.events[] | {studentId, id, start, className}'"},{"language":"sh","snippet":"# Who the students are — the id feeds everything else\nmhlb_get /parent/childrenInfo | jq '.[] | {id, firstName, schoolName, gradeTeacher, isInactive}'\n\n# The lunch calendar for a date range (POST, despite being a read).\n# The fields are `start`/`end`. Using `startDate`/`endDate` returns 200 with an\n# EMPTY events array — a silent wrong answer, not an error.\ncurl -sS -X POST \"$MHLB/api/calendar/studentSchoolData\" \\\n  -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Content-Type: application/json' \\\n  -d '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\"}' | jq '.events[] | {studentId, id, start, className}'\n\n# What is in the cart but not yet paid for\nmhlb_get '/event/shoppingCart' | jq ."},{"language":"sh","snippet":"curl -sS -X POST \"$MHLB/api/event/createOrder\" \\\n  -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Content-Type: application/json' \\\n  -d @order.json"},{"language":"sh","snippet":"mhlb_get '/event/createOrder?eventId=123&studentId=456' > order.json\n# edit quantities in order.json\ncurl -sS -X POST \"$MHLB/api/event/createOrder\" \\\n  -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Content-Type: application/json' \\\n  -d @order.json"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: myhotlunchbox\ndescription: Read and manage a My Hot Lunchbox school-lunch account from a shell with curl — sign in, list students, read the lunch calendar and cart, check orders, deliveries and payments. Use when you want My Hot Lunchbox data without running the MCP server, in a script, or on a machine where the MCP is not installed.\n---\n\n# My Hot Lunchbox from the shell\n\n`ordernow.myhotlunchbox.com` exposes a plain JSON API behind an OAuth2 password\ngrant. It is reachable server-side — no browser, no extension, no bridge. Two\n`curl` calls get you data: one to sign in, one per read.\n\n## Sign in once per shell\n\nCredentials come from the environment; never paste them into a command line\n(that puts them in shell history).\n\n```sh\nexport MHLB_USER='you@example.com'\nexport MHLB_PASS='…'          # e.g. read -rs MHLB_PASS\nexport MHLB=https://ordernow.myhotlunchbox.com\n\nmhlb_login() {\n  local resp\n  resp=$(curl -sS -X POST \"$MHLB/api/auth/login\" \\\n    -H 'Content-Type: application/x-www-form-urlencoded' \\\n    -H 'Accept: application/json' \\\n    --data-urlencode 'grant_type=password' \\\n    --data-urlencode \"username=$MHLB_USER\" \\\n    --data-urlencode \"password=$MHLB_PASS\" \\\n    --data-urlencode 'scope=openid offline_access email profile roles') || return 1\n  MHLB_TOKEN=$(printf '%s' \"$resp\" | jq -r '.access_token // empty')\n  if [ -z \"$MHLB_TOKEN\" ]; then\n    printf '%s' \"$resp\" | jq -r '.error_description // .error // \"login failed\"' >&2\n    return 1\n  fi\n  export MHLB_TOKEN\n}\n\n# Authenticated GET.  usage: mhlb_get /parent/childrenInfo [curl args…]\nmhlb_get() {\n  local endpoint=$1; shift   # NOT `path`: zsh ties $path to $PATH\n  curl -sS \"$MHLB/api$endpoint\" -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Accept: application/json' \"$@\"\n}\n\nmhlb_login && mhlb_get /auth/userinfo | jq '{name, email, students_count, pending_orders_count, parent_credit_value}'\n```\n\n**A failed sign-in must not be retried.** The server is OpenIddict and counts\nfailed attempts; repeated failures can escalate to a CAPTCHA and remove\nserver-side sign-in for that account entirely. If `invalid_grant` comes back,\nstop and check the credentials.\n\nThe token lasts about an hour. Re-run `mhlb_login` when a call starts returning\n`401`.\n\n## The three reads that answer most questions\n\n```sh\n# Who the students are — the id feeds everything else\nmhlb_get /parent/childrenInfo | jq '.[] | {id, firstName, schoolName, gradeTeacher, isInactive}'\n\n# The lunch calendar for a date range (POST, despite being a read).\n# The fields are `start`/`end`. Using `startDate`/`endDate` returns 200 with an\n# EMPTY events array — a silent wrong answer, not an error.\ncurl -sS -X POST \"$MHLB/api/calendar/studentSchoolData\" \\\n  -H \"Authorization: Bearer $MHLB_TOKEN\" -H 'Content-Type: application/json' \\\n  -d '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\"}' | jq '.events[] | {studentId, id, start, className}'\n\n# What is in the cart but not yet paid for\nmhlb_get '/event/shoppingCart' | jq .\n```\n\n`references/endpoints.m"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"myhotlunchbox-mcp\",\n  \"version\": \"1.2.6\",\n  \"publishedAt\": 1791588421483\n}"},{"path":"references/endpoints.md","content":"# My Hot Lunchbox endpoints — ready-to-run\n\nAll paths are relative to `$MHLB/api`. All need `Authorization: Bearer $MHLB_TOKEN`.\nAssumes the `mhlb_get` helper from `SKILL.md` is defined.\n\n## Account\n\n```sh\n# Account claims: name, role, student count, credit balances, subscription state\nmhlb_get /auth/userinfo | jq .\n```\n\n## Students\n\n```sh\nmhlb_get /parent/childrenInfo | jq '.[] | {id, firstName, schoolName, gradeTeacher, hasOrders, isInactive, isInvited}'\n\n# Editable profile for one student (also the model that POST /parent/editChild takes back)\nmhlb_get '/parent/editChild?childId=456' | jq .\n\n# Blank profile + dropdown options for adding a student\nmhlb_get /parent/createChild | jq .\n```\n\n## Calendar and deliveries\n\n```sh\n# Lunch calendar for a range — a POST that reads\nmhlb_post() {\n  local endpoint=$1; shift   # NOT `path`: zsh ties $path to $PATH\n  curl -sS -X POST \"$MHLB/api$endpoint\" -H \"Authorization: Bearer $MHLB_TOKEN\" \\\n    -H 'Content-Type: application/json' -d \"${1:-{\\}}\"\n}\n\n# Fields are `start`/`end` — `startDate`/`endDate` silently returns zero events.\nmhlb_post /calendar/studentSchoolData '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\"}' | jq .\n\n# Events carry the ids the ordering endpoints need:\nmhlb_post /calendar/studentSchoolData '{\"start\":\"2026-09-01\",\"end\":\"2026-09-30\"}' \\\n  | jq '.events[] | {studentId, eventId: .id, orderId, date: .start[0:10], className}'\n\n# What one student has on one day\nmhlb_get '/calendar/studentOrderItems?studentId=456&date=2026-09-14' | jq .\n```\n\n`/deliveryInfo/*` and `/calendar/viewMatchedVendors` look parent-facing in the\nsite's compiled client but return **403** for a parent account — they belong to\nthe school and vendor dashboards. Verified live; don't reach for them.\n\n## Cart and menu\n\n```sh\n# Valid filter values first — periods (semesters) and status tabs\nmhlb_get /event/ShoppingCartBaseData | jq '{periods: [.periods[] | {text, value, selected}]}'\n\n# The cart itself; every filter is optional\nmhlb_get '/event/shoppingCart' | jq .\nmhlb_get '/event/shoppingCart?selectedStudentId=456' | jq .\n\n# The orderable menu for a student on a date — vendor, items, sizes, prices, cutoff\nmhlb_get '/event/orderBaseData?studentId=456&eventDate=2026-09-14' | jq .\n```\n\n## Transactions and subscriptions\n\n```sh\nmhlb_get /event/transactionsList              | jq .\nmhlb_get '/event/transactionDetails?id=999' | jq .   # id comes from transactionsList\nmhlb_get /event/subscription                  | jq .\nmhlb_get '/event/upcomingSubscriptions'       | jq .\n```\n\n## Gift cards and coupons\n\n```sh\nmhlb_get /parent/giftCardDataTables | jq .\nmhlb_get /parent/coupon             | jq .\n```\n\n## Printable reports\n\nThese stream a **binary PDF**, not JSON — pipe to a file, never to `jq`. Their\npayloads are not date ranges.\n\n```sh\nmhlb_pdf() {  # usage: mhlb_pdf <endpoint> <json> <out.pdf>\n  curl -sS -X POST \"$MHLB/api$1\" -H \"Authorization: Bearer $MHLB_TOKEN\" \\\n    -H 'Content-Type: application/json' -d \"$2\" -o \"$3\" && file \"$3\"\n}\n\n# Calen"},{"path":"skill-card.md","content":"## Description:\n\nHelps agents access and manage a My Hot Lunchbox school-lunch account using shell commands when the MCP server is unavailable.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nParents and their authorized assistants can check students, lunch calendars, carts, orders, deliveries, and payments, or prepare account changes from a shell without the MCP server.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Account credentials and access tokens are handled by an agent or shell script.\n\nMitigation: Use a trusted environment, keep credentials out of command history, and avoid exposing tokens or account data.\n\nRisk: Raw account-changing commands may alter or clear existing orders; write request bodies have not been verified against a live account.\n\nMitigation: Inspect the complete payload before sending it, confirm each mutation, and read the resource again afterward; prefer the MCP wrapper when available.\n\nRisk: Checkout and subscription actions can cause real charges or account changes.\n\nMitigation: Check prices and totals manually, obtain explicit approval, and never call checkout speculatively.\n\n## Reference(s):\n\n- [ClawHub skill release](https://clawhub.ai/chrischall/skills/myhotlunchbox-mcp)\n- [My Hot Lunchbox endpoint reference](artifact/references/endpoints.md)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, Guidance]\n\n**Output Format:** [Markdown with shell command examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Commands can retrieve JSON account data or save PDF reports.]\n\n## Skill Version(s):\n\n1.2.6 (source: ClawHub release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment."}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":"Read and manage a My Hot Lunchbox school-lunch account from a shell with curl — sign in, list students, read the lunch calendar and cart, check orders, deliveries and payments. Use when you want My Hot Lunchbox data without running the MCP server, in a script, or on a machine where the MCP is not installed. Skill: myhotlunchbox-mcp Owner: chrischall Summary: Read and manage a My Hot Lunchbox school-lunch account from a shell with curl — sign in, list students, read the lunch calendar and cart, check orders, deliveries and payments. Use when you want My Hot Lunchbox data without running the MCP server, in a script, or on a machine where the MCP is not installed. Tags: latest:1.2.6 Version history: v1.2.6 | 2026-10-09T23:","editorialQuality":{"score":100,"threshold":65,"status":"ready","wordCount":1155,"uniquenessScore":49,"reasons":[]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-11T00:50:03.445Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-11T00:50:03.445Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-11T03:56:38.043Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}