Encode the recovered per-leaf title/short-description rule and the Call 2 input set into the point of record. - REQUIREMENTS.md: METADATA-55 now produces the description only; METADATA-60 carries the ruled input set; METADATA-80 is the deterministic title; new METADATA-81 is the deterministic spec-line short description; METADATA-85 selects the patterns; REVIEW-15 declares the primary before Call 2; PUBLISH-55 carries an explicit name+SKU slug. - CONTENT-WOO.md: per-leaf title and short-description catalog, slot order, dimension placement, and the Cook Woods provenance. - PROMPTS.md: Call 2 inputs and output; the deterministic patterns are cited, not restated. - CREATE.md, WOO-API.md, MILESTONES.md, task_breakdown.md updated to match. Modeled on Cook Woods product-title form; the seven per-leaf prose templates and Specialty cuts are parked in the M3 breakdown.
6.1 KiB
WooCommerce API contract
Status: SPEC · 2026-09-18 · external dependency: WooCommerce REST API v3. Source: official WooCommerce REST API v3 documentation (https://woocommerce.github.io/woocommerce-rest-api-docs/).
This contract pins the exact WooCommerce surface the app codes against.
docs/contracts/CONTENT-WOO.md owns the listing copy and payload intent; this file owns the wire
shape and the external constraints.
Requirements impact
| Requirement | Impact on this design |
|---|---|
| SETTINGS-5, SETTINGS-10, SETTINGS-15 | base URL, HTTPS, app-password auth |
| SETTINGS-35, SETTINGS-50, SETTINGS-51, SETTINGS-65 | pricing, taxonomy sync, tag scope, create status |
| METADATA-5, METADATA-10, METADATA-15, METADATA-30 | categories, attributes, tags shapes |
| REVIEW-10, REVIEW-25, REVIEW-45, REVIEW-50 | name, price, SKU, field limits |
| PUBLISH-5, PUBLISH-10, PUBLISH-15, PUBLISH-20, PUBLISH-25, PUBLISH-30, PUBLISH-35 | create sequence, draft rule, errors |
| PUBLISH-40, PUBLISH-45, PUBLISH-55, PUBLISH-60 | images, payload fields, sold-individually |
| APP-35, APP-50 | error envelope mapping |
1. Transport and auth
- Base path:
${WOO_BASE_URL}/wp-json/wc/v3. WOO_BASE_URLis HTTPS only and injected from env.- Auth: WordPress application password over HTTP Basic. The consumer-key example in the Woo docs is not used.
- Content type
application/json. Dates ISO8601 (YYYY-MM-DDTHH:MM:SS). Monetary values are strings with two decimals.
2. Endpoints used
| Purpose | Method and path |
|---|---|
| Sync categories | GET /products/categories?per_page=100&page=N |
| Sync tags | GET /products/tags?per_page=100&page=N |
| Sync attributes | GET /products/attributes?per_page=100 |
| Sync attribute terms | GET /products/attributes/{id}/terms?per_page=100 |
| SKU lookup | GET /products?sku={sku} |
| Create product | POST /products |
| Upload media | POST /wp-json/wp/v2/media (WordPress core) |
3. Product create field alignment
| Our value | Woo field | Woo type | Enum / constraint |
|---|---|---|---|
| title | name |
string | none documented |
| — | type |
string | simple (default) |
| create status | status |
string | draft, pending, private, publish; default publish |
| sku | sku |
string | unique; no documented format |
| slug (name + SKU) | slug |
string | sanitized; WordPress dedupes on collision |
| price | regular_price |
string | monetary string, 2 decimals |
| description | description |
string | none documented |
| short_description | short_description |
string | none documented |
| species + wood categories | categories |
array of {id: integer} |
leaf ids |
| fig-* / feat-* tags | tags |
array of {id: integer} |
tag ids |
| uploaded PNGs | images |
array of {id: integer} |
attachment ids, lineup order |
| five locked attributes | attributes |
array of attribute elements | see §4 |
| — | virtual |
boolean | default false |
| — | downloadable |
boolean | default false |
| — | catalog_visibility |
string | visible, catalog, search, hidden; default visible |
| — | sold_individually |
boolean | default false; set true |
sold_individually: true is the Woo mechanism that enforces "one slab is one unit."
4. attributes element shape
Global attributes are referenced by id (synced from Woo), never created by name. Each element:
{
"id": 8,
"position": 0,
"visible": true,
"variation": false,
"options": ["Live Edge"]
}
| Attribute | options |
|---|---|
| Edge Type | [term name] |
| Figure | [term name, ...] |
| Grade | [term name] |
| Thickness | [term name] |
| Moisture | [term name] |
options carries term names, not ids. visible is true; variation is false.
5. Categories, tags, images shapes
categories:[{"id": 9}, {"id": 14}]tags:[{"id": 34}]images:[{"id": 42}, {"id": 793}], in photos-ready lineup order.- Media upload:
POST /wp-json/wp/v2/mediaasmultipart/form-datawith the PNG bytes; the responseidis the attachment id used inimages. Keep alpha; PNG only.
6. Error shape
{ "code": "woocommerce_rest_term_invalid", "message": "Resource doesn't exist.", "data": { "status": 404 } }
401 auth, 400 bad request, 404 missing, 500 server. These map into the app's uniform
envelope and never reach the owner raw.
7. Pagination
per_page max 100, page 1-based. Read X-WP-Total and X-WP-TotalPages; follow pages until
exhausted. Taxonomy lists return in full to the client.
8. No documented maximum lengths
The Woo v3 docs state no maximum length for name, description, short_description, sku, or
regular_price. Do not invent caps. The app enforces non-empty required fields and its own local
formats.
9. Field length limits
Hard limits are verified from WordPress/WooCommerce source; the display caps are conventions (Google states no numeric limit).
| Field | Storage | Hard limit | Recommended display cap | Rationale |
|---|---|---|---|---|
name |
wp_posts.post_title (text) |
65,535 | 60 | on-screen title-tag width |
short_description |
wp_posts.post_excerpt (text) |
65,535 | 160 | search snippet / meta description width |
description |
wp_posts.post_content (longtext) |
~16.7M | none | no word-count target; write for the page |
sku |
wc_product_meta_lookup.sku (varchar(100), index sku(50)) |
100 | 50 | index prefix length |
slug |
wp_posts.post_name (varchar(200)) |
200 | 200 | WordPress wp_unique_post_slug truncates the base near 200 |
Sources: WordPress schema.php, WooCommerce class-wc-install.php,
class-wc-product-data-store-cpt.php, and Google Search Central (title links, snippets, SEO
starter guide).
10. Media size
The store exposes its upload cap read-only as max_upload_size on system status. Validate the
processed PNG against it before upload and surface a plain, actionable error if exceeded.
11. Versioning
Woo wc/v3 requires WooCommerce 3.5+ and WordPress 4.4+ with pretty permalinks. Breaking Woo API
changes are handled by the app's own /api/v1 version, not by pinning the store.