Agent Skill:vendling-vendor-adapter
给售货机厂商、智能柜 / 冰柜平台、供应商的 Agent 用:把自己的接口对照附录 A.6 的契约做成八个 HTTPS 端点,用自带的检查脚本自检,产出运营者登记用的 JSON。零代码接入,不用改 Vendling。 把整个目录放到 ~/.claude/skills/vendling-vendor-adapter/(或你的 agent 框架的 skills 目录)即可;触发描述见 SKILL.md 的 frontmatter。源码在 vendling-api。
- SKILL.md
- references/http-contract.md
- references/mapping-worksheet.md
- scripts/mock_vendor.py
- scripts/vendling_vendor_check.py
安装:
unzip vendling-vendor-adapter.skill.zip -d ~/.claude/skills/,然后在会话里提到 接入 Vendling / 做适配器 / 字段对照 / VENDLING_HTTP_VENDORS 即可触发。
Vendling vendor adapter · zero-code onboarding#
You are helping a machine platform (runs cabinets / vending machines) or a supplier (sells goods) plug into Vendling, an AI agent that operates real vending machines. Vendling never calls a vendor's native API. It calls a fixed contract — eight JSON-over-HTTPS endpoints — and the vendor serves that contract in front of whatever they already have. Your job: map their data onto the contract, get the endpoints up, prove they conform, and produce the one-line registration the operator needs.
Spec: https://vendling.dev/api/ (appendix A.6 is the HTTP contract, A.1–A.3 the field rules). Machine-readable: https://vendling.dev/api/llms-full.txt.
0. Which role, which endpoints#
| Role | Namespace | Required | Optional (declare as capabilities) |
|---|---|---|---|
machine — runs the machines |
<vendor>-machine |
GET /inventory, GET /ledger |
POST /prices (pricing), POST /restock + GET /restock/{ref} (replenishment.recommend and/or replenishment.order) |
supply — sells goods |
<vendor>-supply |
GET /catalog, POST /orders, GET /orders/{ref} |
— |
One vendor can serve both roles under two namespaces (a platform that also supplies the goods).
<vendor> is a short lowercase slug the operator agrees on; the docs use acme.
1. The rules that break integrations (read before mapping)#
- Money is integer fen.
priceFen: 600is ¥6.00. A float, or a number that is clearly yuan, fails conformance. - Time is epoch milliseconds (
1757400000000),nullwhen unknown. Seconds are wrong by 1000×. - Never look like an empty machine when something is wrong. Errors are
{ "ok": false, "reason": "…" }on any status; auth failures are HTTP401/403. vendorSkuis your own stable product id, unique across all your machines. Vendling prefixes it with the namespace (acme-machine:8837) and never parses it.- Barcodes (EAN) matter: they are the only automatic bridge between what is in a machine and
what a supplier sells. Send
barcodeon inventory items and (viaspec/title) on catalog rows. - A ledger record is one order, lines inside; only lines with
status: "paid"count as sales. Open-door / vision cabinets: sendstate,takenAt,settledAt,updatedAt,finalizedand supportby=updated(seereferences/http-contract.md§Ledger). costFenonly when it is a real cost that differs from the price; otherwisenull.- Customer identity never crosses: no member ids, phone numbers or face ids in any payload.
2. Workflow#
- Map fields. Take the vendor's existing API or field list and fill the worksheet in
references/mapping-worksheet.md. Every "required" row must have a source; every gap is a question back to the vendor, not a guess. - Serve the endpoints. Any stack.
scripts/mock_vendor.pyis a complete reference server (stdlib Python) — run it to see exact request/response shapes, or copy it as a starting point. - Check conformance against the real base URL (read-only by default — it never posts prices,
restocks or orders):
bash python3 scripts/vendling_vendor_check.py --base https://api.acme.example/vendling --token "$VENDOR_TOKEN" \ --namespace acme-machine --location 12345678 --check-auth --supports pricing,replenishment.recommendFix every FAIL; read every WARN (they are the mistakes that cost money later). - Hand over the registration. The checker prints the entry for the operator's
VENDLING_HTTP_VENDORSsecret:json [{ "namespace": "acme-machine", "baseUrl": "https://api.acme.example/vendling", "token": "…", "capabilities": ["pricing", "replenishment.recommend"] }]Send the token out of band. The operator registers it; nothing is deployed. - Verify from the Vendling side (operator, or you with the operator's token):
GET /ucp/v1/namespaceslists the namespace aslive, thenPOST /ucp/v1/catalog/search {"filters":{"namespace":"acme-machine","location":"<machine id>"}}returns your items with prices and barcodes (supply:{"filters":{"namespace":"acme-supply"}}returns your catalog withsale_units). Anamespace_unsupportedanswer means the registration JSON is malformed (namespace must be<vendor>-<role>, baseUrl must be http(s)) or the capability was not declared. Note: the route's own hourly sync and sales ledger follow the operator's default machine namespace; switching a route to a new platform is an operator-side change.
3. Safety#
POST /orders(supply) places a real purchase;POST /priceschanges a real price. The checker never calls them. If you must test them, do it against a staging base URL the vendor provides, never against production with a real machine id.- Tokens: keep them out of URLs, logs and chat transcripts. One token per vendor, revocable.
- Rate: Vendling reads inventory hourly per machine and the ledger every 5 minutes (last 3 hours,
paginated at 100). Size limits and caching are the vendor's call;
page/sizemust be honoured.
4. Files#
| Need | File |
|---|---|
| Exact endpoint shapes, field tables, error rules, registration | references/http-contract.md |
| Worksheet to map an existing API / field list onto the contract | references/mapping-worksheet.md |
| Conformance checker (stdlib Python; read-only) | scripts/vendling_vendor_check.py |
| Reference server implementing all eight endpoints (stdlib Python) | scripts/mock_vendor.py |