ApparelHub Skill
ApparelHub is a multi-channel ecommerce platform for custom merchandise. Use
this skill when the user wants to:
- Design AI-generated apparel (tees, hoodies, embroidered apparel,
water bottles, pillows, doormats, luggage tags)
- Generate product mockups on physical garments
- Create products and sync them to sales channels
(Shopify, Etsy, WooCommerce, Wix)
- Manage orders and fulfillment via Printful / Printify
- Browse the catalog of garments available for printing
When you drive the platform over raw HTTP (the fallback path — see the
callout just below), you talk to ApparelHub via its Agent API at
https://api.apparelhub.ai/agents/v1/. That's the only host this skill
ever sends an API key to.
This document is host-agnostic — any AI agent capable of making HTTP
requests can drive the platform from this skill alone. If you're a
specific kind of agent (Claude Code, a ChatGPT Custom GPT, a Gemini
tool-calling agent, or a bare-HTTP runtime), there's a porting guide
tailored to you under porting-guides/ in the same repo.
This SKILL.md is the router. Detailed playbooks live in references/
and end-to-end walkthroughs in examples/. Load them on demand. Don't
try to memorize the entire skill upfront.
0. First — if the ApparelHub connector is attached, use its tools
If this session already has the ApparelHub MCP connector available — i.e.
you can see ApparelHub tools such as design_apparel, ship_product,
generate_image, create_product, process_transparency,
verify_design_quality, get_garment_details, or sync_to_fulfillment —
then call those tools directly and treat the rest of this skill as reference
knowledge only. The connector takes precedence over the raw-HTTP pipeline
documented below. It is the execution surface; this skill is the knowledge
layer plus the no-connector fallback.
In connector mode:
- Build with the high-level workflow tools first.
design_apparel makes a
print-ready design; ship_product goes from a design to a finished,
store-mapped product in ONE call (mockup → create → variants → associate →
fulfillment sync). Reach for the atomic tools (generate_image,
process_transparency, add_variants, sync_to_fulfillment,
sync_to_channel, …) only for partial or interactive flows.
- Do NOT re-implement the local pipeline this skill documents below. No
ah_curl / raw curl calls, no make_transparent.py chroma-keying, no
ah_poll_mockup polling, no fetching mockup images yourself. The connector
runs transparency processing, mockup rendering, variant resolution, face
layouts, and image hosting server-side. Redoing that work by hand is what
strips leaves out of a design, clips lettering, and dead-ends on blocked
image CDNs — the exact failures the manual path keeps hitting.
- Use the reference files (
references/, examples/) for the WHY, not the
HOW — garment quirks, design rules, pricing, catalog facts, error decoding.
The connector already encodes how to make the calls; the references explain
what a good result looks like. When a connector tool returns a structured
error code, decode it with references/error-handling.md.
Everything from "## 1. Authentication" onward is the raw Agent API
fallback — for runtimes that have only an APPARELHUB_API_KEY and no
connector (bare HTTP, some Claude Code setups, ChatGPT / Gemini via the
porting guides). If you have the connector, you don't need any of it.
1. Authentication
Every API call needs the header:
x-api-key: <your API key>
How the agent sources that key depends on the runtime:
- The recommended pattern is that the agent reads
APPARELHUB_API_KEY from its runtime environment (os.environ,
process.env, etc.) at call time. The skill does NOT ask you to
persist the key to disk and does NOT read it from any config file.
- For tool-calling agents (ChatGPT Custom GPT with Actions, Gemini
function calling): hide the key inside the function-call
implementation so the agent never sees it. See
../porting-guides/chatgpt-gemini.md for the pattern.
- For Claude Code (and similar shell-based agents): use whatever
mechanism you normally use for development secrets — direnv, shell
rc, macOS Keychain, etc.
If your runtime prompts the first time it reads this environment
variable or makes a network call, that is correct behavior. Approve
the prompt in context if the call is one you intended. The skill no
longer ships wrappers whose purpose is to dodge those prompts (see
../SECURITY.md).
Sanity-check the key before a multi-step workflow
scripts/ah_check (optional, Claude Code convenience) verifies that
APPARELHUB_API_KEY is set AND accepted by the platform, then prints a
masked confirmation:
ah_check
Exit codes: 0 valid, 2 not set, 3 rejected by the platform or
network failure. Equivalent plain HTTP probe:
curl -sS -o /dev/null -w "%{http_code}\n" \
https://api.apparelhub.ai/agents/v1/store \
-H "x-api-key: $APPARELHUB_API_KEY"
200 means the key works. Anything else, fix the key before continuing.
Local key hygiene on shared machines: -H "x-api-key: ..." puts the
key value in the process argv, where ps (and other local users) can read
it for the request's duration. On a multi-user box, pass the header via a
curl config on stdin instead, so the key never reaches argv:
curl -sS https://api.apparelhub.ai/agents/v1/store --config - <<CFG
header = "x-api-key: $APPARELHUB_API_KEY"
CFG
The plain -H form is fine on a single-user machine. scripts/ah_check
already uses the stdin-config form.
The canonical OpenAPI spec
GET https://api.apparelhub.ai/agents/v1/openapi.json
Authoritative reference for every endpoint and field. When you're
unsure about a field name or response shape, fetch the spec.
2. The product-creation pipeline at a glance
Going from "user wants a saguaro tee" to a finished, sellable product
takes these phases. Execute IN ORDER:
- Generate the design image.
POST /images/generate with a prompt (slow models, including the Nano Banana default, return 202 + image_uuid and must be polled with ah_poll_generation; fast models return 200 + url)
- LOCAL transparency processing (your compute, NOT an API call). For
standard apparel only; SKIP for all-over print
- Generate the mockup.
POST /merchandise/product/preview. A finished
product should show a garment MOCKUP, not the bare design — never skip this
for a product you're presenting as done.
- Pick
display_image + build gallery_images from preview rows
- Create the product.
POST /product/create
- Add variants (one at a time, no batch endpoint). Read the garment's
ACTUAL colors/sizes from
get_garment_details first — do NOT assume
S/M/L/XL/2XL. Caps, beanies, phone cases, bottles, bags etc. are often
one-size or use different labels; assuming apparel sizes yields 0 variants.
- Map the product to the user's store + sync to fulfillment
(Printful/Printify). This is what "map / add to store" and "store
availability" mean — the product is associated with the store and
manufacturable. This is the normal end of the pipeline.
- (ONLY if the user explicitly asked to list / publish / sell it on a
storefront) sync to the sales channel (Shopify/WooCommerce/Wix), as a
DRAFT unless they said go live. Separate, opt-in step — see the ⚠️ below.
⚠️ "Map / add to a store" is NOT "publish to a sales channel" — don't
conflate them. An ApparelHub store holds a fulfillment provider
(Printful/Printify) and, optionally, connected sales channels
(Shopify/WooCommerce/Wix). Mapping a product to a store (Phase 7) makes
it manufacturable and lists it under the store in ApparelHub; it does NOT
create a storefront listing. Only push to a sales channel (Phase 8 —
sync_to_channel / ?target=ecommerce) when the user EXPLICITLY asks to
list, publish, or sell it on that storefront. If they said "map it to the
store" / "add it to my store" / "put it in the store," STOP at Phase 7 —
do not invent a channel sync. (This is a real regression that shipped in an
automated task: "map to the store" was wrongly extended to a WooCommerce sync.)
Fastest correct path (especially for automated / scheduled runs): the
ship_product MCP tool does Phases 3–7 in ONE call (mockup → create →
variants → associate → fulfillment sync) with the ordering guaranteed, and
only touches a sales channel if you pass sync_to_channels. Prefer it over
chaining the split primitives yourself.
Full pipeline detail (every call, every field, every gotcha) lives in
references/product-creation-pipeline.md. Read it before executing
any phase you haven't done in this session.
The four field-name gotchas that silently break products are
documented there and worth memorizing:
- Phase 3 preview endpoint uses
merchandise_provider_uuid +
provider_product_ref_id
- Phase 5 create endpoint uses
provider_uuid + product_ref_id
- Same data, FLIPPED names. Don't copy field names between phases.
- Use
price, not retail_price.
3. Decision tree: which reference file to load
Before executing a workflow, scan this tree. Loading the right
reference up front saves you from shipping a broken product.
| If the task involves… |
Read FIRST |
| Talking to the Agent API at all |
references/api-contract.md covers the HTTP contract — base URL, auth header, every endpoint, every status code |
| Generating ANY design image |
references/design-rules.md covers AI prompt anti-patterns, transparency, vision-verification of text |
| The merchant already OWNS the artwork (a client logo, a brand mark, a cleared cover, "here are their assets", "do not redraw our mark") |
references/byo-artwork.md. Upload the file, do NOT generate a lookalike. Three routes: a public source_url, a presigned URL you PUT to yourself (cheapest — nothing enters your context), or inline base64 for small files. The returned uuid is a design uuid and works everywhere one does. SVG is accepted and preferred — it is rendered at print resolution, so it stays crisp at any size (text must be outlined, linked images embedded). Pass upscale: "pixel" for a hard-edge RASTER mark so a small file is not smoothed. Uploads cost no image generations. |
| Editing / iterating on an existing design (user says "make the cat smug", "redo this in landscape", "use this as a starting point") |
references/design-rules.md section 5b explains how POST /images/generate doubles as the img2img endpoint via source_image_uuid or multipart images=@.... Only Nano Banana and OpenAI support edit; Replicate-backed sources 422. |
| Aspect ratio / matching the print area (a design's shape doesn't fit the product — square design on a tall phone case / poster / wide banner) |
references/design-rules.md section 5c: generate at the matching size (1024x1024 square / 1024x1792 tall / 1792x1024 wide), or reshape an EXISTING design with POST /images/generated/<uuid>/fit-aspect (pad keeps everything / crop trims; quota-free — no image generation spent). Per-product mapping in references/all-over-print.md §12. |
| Retiring / cleaning up designs (archive or delete a design, find orphan designs nothing is using, tidy a gallery) |
references/design-rules.md section 5d. Designs CAN be archived and deleted — do not conclude otherwise. Archive is PATCH /images/generated/<uuid> with {"archived": true} (reversible, safe, the default choice); delete is DELETE on the same path and is refused with 409 image_in_use while a live product uses it. Find orphans with GET /images/generated?on_products=false. |
| Listing images on a product that already exists — attaching a merchant photo, reordering the gallery, changing the cover image, or "why is my listing showing the flat artwork?" |
references/product-imagery.md. ⛔ A print file (what gets PRINTED) is not a listing image (what a shopper sees); pushing artwork as listing photography is a known quality failure on at least one major channel. ⛔ gallery_images REPLACES the gallery, so read images first and send the whole list back — sending only the new URL deletes the rest. Ordering is functional: channels cap listing images (TikTok Shop 9, Wix 15) and truncate in gallery order, so position decides what actually ships. Generated imagery is constrained to EDITING the product's real mockup — a from-scratch product photo invents a product that does not exist. Declare ai_generated truthfully; the platform cannot detect it. |
| "Is my product actually live?" / a listing vanished from a storefront / checking on a synced listing |
references/product-creation-pipeline.md Phase 9. A sales channel can remove or deactivate a listing at any time without asking, so a successful sync is a fact about the PAST. Read health (what the channel last said), not just sync_status (what we believe we published) — and treat an absent health as "never checked", which is not the same as healthy. ⛔ Do not re-sync a Removed listing unchanged; the channel removed it for a reason and churn is itself a risk. |
| Standard apparel (tees, hoodies, tanks, sweatshirts) |
references/product-creation-pipeline.md |
| Embroidered apparel (Champion Anorak, polos, jackets — and headwear only once you have CONFIRMED that garment is embroidered) |
references/embroidery.md covers the 15-color thread palette + the thread_colors_<placement> option-placement trap. Skipping this guarantees a 400 from the provider. Do not assume headwear is embroidered: it spans both families, and assuming is what makes a printable cap invisible. |
| A garment can't take this design (embroidery vs print, photoreal artwork refused, "no is possible") |
references/provider-selection.md. Capability limits are almost always scoped to ONE provider, not to the category. Enumerate providers with find_garments BEFORE reporting that something cannot be built. |
| All-over print (pillows, doormats, area rugs, luggage tags, AOP tees, phone cases, mugs) |
references/all-over-print.md covers edge-to-edge background rules, product-specific gotchas, the "don't name the product in the AI prompt" trap |
| Channel-defined listing fields (product attributes, item specifics, category metafields — "set the material", "fill in the compliance answers", "the channel says the listing is incomplete") |
references/listing-attributes.md. Call describe_listing_attributes FIRST — field names and allowed values are defined by the channel per category, so they cannot be guessed and a mismatch is refused. Setting a value does NOT reach the channel until a sync. ⛔ Compliance answers are LEGAL ATTESTATIONS: relay what the merchant tells you, never choose one, and leave it unset if they have not answered. Size charts live here too: apparel is graded down without one, so when a listing is flagged, import_size_measurements then set size_chart_measurements — never type in measurements you were not given. |
| Variant IDs, pricing, color limit, BC 3001 vs Comfort Colors trade-off |
references/garment-catalog.md |
| Costs & margin pricing — reading per-variant cost, setting prices to a target margin, pricing floors |
references/pricing.md: per-variant cost lives on the store-products list (GET /store/<store>/products → variants[].cost), NOT on product-detail; it is resolved when the variant is created (for Printify that needs a mockup first, which the normal build order already does); catalog cost carries cost_source = live/cached/unavailable — never compare providers without reading it; price each variant to cost / (1 - margin) |
| Listing/inspecting orders, payment status, fulfillment status |
references/orders-and-fulfillment.md includes the payment-authority rule (sales channel wins for storefront orders) |
| Managing orders — approving/confirming/holding, the per-store fulfillment workflow (auto / confirm / review), smart guardrails, the agent approval queue, the opt-in signed callback |
references/orders-and-fulfillment.md sections 8–10. Note the TWO distinct holds (ApparelHub approval vs Printful design hold). |
| A 4xx / 5xx response, sync that didn't take, "Failed to fetch" UX |
references/error-handling.md |
| A delivered item arrived wrong (doesn't match the mockup, damaged, wrong or missing item, bad print) — reporting it, bridging the claim to Printful/Printify, replacement orders |
references/fulfillment-issues.md covers the /agents/v1/orders/.../issues endpoints, the 30-day report window, eligibility warnings (change-of-mind is not claimable), evidence upload caps, the provider-ready summary + dashboard deep-link handoff, and zero-charge replacement orders |
| Enterprise / agency account (multiple workspaces; a list looks like it's "missing" stores/products/designs, or you need to target a specific client workspace) |
references/workspaces.md covers the GET /agents/v1/workspaces discovery route, the ?workspace= param, the workspaces visibility field, 403/404 handling, and workspace-scoped keys |
| Analytics / reporting — sales KPIs, trends, top sellers, channel mix, margins, ops health, CSV export, or an agency's per-client portfolio |
references/analytics.md covers the six read-only /agents/v1/analytics/* endpoints, the advanced_analytics tier gate (Professional+), currency segmentation, and the margin_coverage caveat |
| Channel performance — which listings people SEE but do not buy, why a listing is underperforming, what is safe to archive, or whether a channel reports views at all |
references/channel-performance.md covers the /agents/v1/analytics/channel/* endpoints, the shop-level verdict to read before any listing state, the seven listing states and the fix each implies, the rule that a missing metric is never a zero, and /agents/v1/analytics/interventions — whether the last change you made actually worked |
When the user asks for an end-to-end flow ("build me a saguaro tee and
sync it"), the examples/ directory has working walkthroughs you can
adapt:
| If the user wants… |
Read |
| A front-print tee end-to-end |
examples/front-print-tee.md |
| An all-over-print pillow / doormat / luggage tag |
examples/all-over-pillow.md |
| An embroidered chest crest on a jacket / polo |
examples/embroidered-anorak.md |
| Reviewing + approving a held order as an agent (workflow config → poll the queue → approve/hold) |
examples/order-management.md |
| A garment can't take the design — the constraint is one provider's, not the category's; enumerate and build elsewhere |
examples/blocked-garment-find-alternative.md |
| Attaching a photo to an EXISTING listing + ordering the gallery for a capped channel |
examples/product-imagery-attach-and-order.md |
4. Top-level safety rails
These apply across every workflow. Don't override without explicit user
instruction.
4a. Default to DRAFT, never live
When syncing to a sales channel that supports a draft state (Etsy,
Shopify), push as DRAFT first. The user reviews the listing on the
channel's admin before customers see it. Only push as active when
the user EXPLICITLY says "make it live" or "publish it." The cost of a
too-eager publish (typo'd title in front of real customers) is much
higher than the cost of one extra click.
Tell the merchant:
"I've synced as drafts so you can review on your storefront before
going live. To publish, flip the listing in your channel admin or
re-run sync with ?listing_state=active."
4b. Verify the design before creating the product
Always visually inspect the design after Phase 1 AND the mockup
after Phase 3. Never ship a broken design or mockup downstream because
manufacturing follows the mockup.
Specifically: if the design contains TEXT, verify spelling with vision
tools BEFORE generating the mockup. AI image models routinely misspell.
4c. Respect pricing floors
The merchant loses money on negative-margin products. Never go below
the recommended retail prices in references/garment-catalog.md
without the user explicitly accepting the math.
4d. Color discipline: max 4 colors per design
More than 4 color variants creates SKU sprawl that hurts conversion.
Pick the 4 best colors for the design and stop.
4e. Embroidery is stitched, not printed — on any provider
Embroidery reproduces a design in thread, so gradients, photorealism
and fine detail will NOT translate, and the colors must come from a
fixed 15-color thread palette. That is a fact about embroidery, not
about any one provider. See references/embroidery.md.
Before dropping an item for this reason, check whether a PRINTED
version of the same garment exists. Call find_garments with
accepts_photoreal: true across all providers. Headwear especially
spans both families: one provider may carry only embroidered caps while
another carries DTF-printed caps that take a photograph as-is.
4f. Ask the user before syncing anywhere
Create the product, add variants, add to the store. STOP. Tell the
user what's ready and ask whether to sync to fulfillment and/or to
which sales channels. Sync is a state-changing operation that costs the
merchant time to undo if you got it wrong.
4g. Never state a capability limit you have only checked on one provider
Say "this provider's hats are embroidery-only", not "hats are
embroidery-only". The first is true and points somewhere; the second is
a claim about the whole catalog that you have not tested, and a user who
believes it stops asking.
Before you tell a user something cannot be made:
- Call
find_garments with the capability you need. It searches every
provider on the account by default.
- If it returns nothing, say what you searched — the response gives you
providers_searched — and that connecting another provider may change
the answer. "I did not find one on Printful, Printify or Gelato" is
honest. "It is not possible" is not.
accepts_photoreal: null on a garment means nobody could tell, not
that the garment cannot take the design. Treat it as "verify this", never
as a reason to drop the item.
This rail exists because an agent once found one provider's headwear was
embroidery-only, reported that no hat was possible, and closed the item —
while the same account had printed caps available the whole time.
5. Working with the user's existing data
GET https://api.apparelhub.ai/agents/v1/store
GET https://api.apparelhub.ai/agents/v1/store/<store_uuid>/products?fields=uuid,name,price,status,thumbnail_url,fulfillment_status,ecommerce_statuses
GET https://api.apparelhub.ai/agents/v1/images/generated?limit=20&sort=newest
GET https://api.apparelhub.ai/agents/v1/orders?limit=10
GET https://api.apparelhub.ai/agents/v1/orders/<uuid>
For order data interpretation (payment status, fulfillment status, who
actually charged the card), see references/orders-and-fulfillment.md.
The store-products list above carries each product's variants array,
and each variant has both price (retail) and cost (provider production
cost, resolved when the variant is created). That's the place to read cost
for margin pricing — product-detail (GET /product/<uuid>) omits variants.
See references/pricing.md.
On an Enterprise (agency) account, every list/get above is scoped to one
active workspace (the Default workspace unless you pass ?workspace=<uuid>).
If a list looks like it's missing stores/products/designs, you're probably
scoped to a different workspace, not missing data. See section 6.
6. Workspaces (enterprise accounts)
Most accounts have a single workspace and can ignore this. On Enterprise
(agency) accounts the account is split into isolated client / brand
workspaces, and every Agent API call acts within ONE of them.
- Discover them.
GET /agents/v1/workspaces lists the workspaces this key
can act in (uuid + name + is_default), the active workspace, and whether
the key is pinned. Use it to turn a workspace name the user mentions into the
uuid you scope with — do this first whenever the user names a workspace.
- Default scope. With no
?workspace= param, calls act in the account's
Default workspace.
- Target a workspace. Add
?workspace=<workspace_uuid> to any list / get /
create call (combines with ?limit=, ?fields=, etc.).
- A bad workspace fails the whole call (no silent fallback): an unknown
uuid returns
404 workspace_not_found; a real-but-inaccessible workspace
returns 403 workspace_forbidden.
- Don't misread a subset as missing data. A scoped list shows that
workspace's assets, not the whole account. Products and generated images
carry a
workspaces array (every workspace they belong to); stores carry
workspace_uuid / workspace_name. Check those before reporting "nothing
there," then re-issue with the right ?workspace=.
- Workspace-scoped keys. An API key can be scoped to one OR MORE workspaces
(each with a role) in the web UI. It rejects any
?workspace= outside that set
with 403 workspace_forbidden, and a role lacking design-generation gets 403 forbidden (capability: design.generate) on POST /images/generate.
GET /agents/v1/workspaces returns the key's scope in
key_scope.workspaces ([{workspace_uuid, role}]).
Full contract (param, error bodies, Model A visibility, scoped keys, worked
curls) is in references/workspaces.md. Single-workspace and
non-Enterprise accounts are unaffected.
7. When NOT to use this skill
- The user wants to BUY a finished product. ApparelHub is for
merchants designing + selling, not end-shoppers. Direct them to the
merchant's storefront.
- Generic image generation unrelated to apparel. Use OpenAI /
Stability directly; ApparelHub charges against the user's image quota.
- Platform admin operations (register your Etsy webhook URLs,
rotate your Shopify secret). These are done in the apparelhub.ai web
UI, not via the agent API.
- Bulk operations beyond ~50 products at once. The agent API
enforces rate limits; for true bulk migrations (1000+ products), the
user should contact ApparelHub support.
8. Reporting back to the user
After completing a workflow, give a tight summary:
- What you generated (design URL)
- The mockup link (so they can verify visually)
- The product page URL:
https://apparelhub.ai/merchandise/my-products
- Which channels you synced to + sync status (draft vs live)
- Anything that didn't succeed and why
Don't dump raw JSON. Users want outcomes, not API responses.
Quick links
- Product manager:
https://apparelhub.ai/merchandise/my-products
- Generated designs:
https://apparelhub.ai/images/gallery
- Stores:
https://apparelhub.ai/stores
- Orders:
https://apparelhub.ai/orders
- API keys:
https://apparelhub.ai/developer/api-keys
- Live API docs (browser):
https://apparelhub.ai/developer/api-docs
- Live API spec (JSON, authed):
https://api.apparelhub.ai/agents/v1/openapi.json
- Pricing tiers:
https://apparelhub.ai/pricing
Security and trust model
See ../SECURITY.md for the trust model, non-goals (we don't bypass
your platform's permission prompts; we don't persist your API key to
disk; we never send the key anywhere but https://api.apparelhub.ai),
and the threat model.
1---2name: apparelhub3description: <!--4---56<!--7This YAML frontmatter is for Claude Code's skill-discovery layer. Other8agents (ChatGPT, Gemini, bare-HTTP) can ignore it — the rest of this9document is host-neutral.10-->1112# ApparelHub Skill1314ApparelHub is a multi-channel ecommerce platform for custom merchandise. Use15this skill when the user wants to:1617- Design AI-generated apparel (tees, hoodies, embroidered apparel,18 water bottles, pillows, doormats, luggage tags)19- Generate product mockups on physical garments20- Create products and sync them to sales channels21 (Shopify, Etsy, WooCommerce, Wix)22- Manage orders and fulfillment via Printful / Printify23- Browse the catalog of garments available for printing2425When you drive the platform over raw HTTP (the fallback path — see the26callout just below), you talk to ApparelHub via its Agent API at27`https://api.apparelhub.ai/agents/v1/`. That's the only host this skill28ever sends an API key to.2930This document is host-agnostic — any AI agent capable of making HTTP31requests can drive the platform from this skill alone. If you're a32specific kind of agent (Claude Code, a ChatGPT Custom GPT, a Gemini33tool-calling agent, or a bare-HTTP runtime), there's a porting guide34tailored to you under `porting-guides/` in the same repo.3536This SKILL.md is the router. Detailed playbooks live in `references/`37and end-to-end walkthroughs in `examples/`. Load them on demand. Don't38try to memorize the entire skill upfront.3940---4142## 0. First — if the ApparelHub connector is attached, use its tools4344**If this session already has the ApparelHub MCP connector available — i.e.45you can see ApparelHub tools such as `design_apparel`, `ship_product`,46`generate_image`, `create_product`, `process_transparency`,47`verify_design_quality`, `get_garment_details`, or `sync_to_fulfillment` —48then call those tools directly and treat the rest of this skill as reference49knowledge only.** The connector takes precedence over the raw-HTTP pipeline50documented below. It is the execution surface; this skill is the knowledge51layer plus the no-connector fallback.5253In connector mode:5455- **Build with the high-level workflow tools first.** `design_apparel` makes a56 print-ready design; `ship_product` goes from a design to a finished,57 store-mapped product in ONE call (mockup → create → variants → associate →58 fulfillment sync). Reach for the atomic tools (`generate_image`,59 `process_transparency`, `add_variants`, `sync_to_fulfillment`,60 `sync_to_channel`, …) only for partial or interactive flows.61- **Do NOT re-implement the local pipeline this skill documents below.** No62 `ah_curl` / raw `curl` calls, no `make_transparent.py` chroma-keying, no63 `ah_poll_mockup` polling, no fetching mockup images yourself. The connector64 runs transparency processing, mockup rendering, variant resolution, face65 layouts, and image hosting **server-side**. Redoing that work by hand is what66 strips leaves out of a design, clips lettering, and dead-ends on blocked67 image CDNs — the exact failures the manual path keeps hitting.68- **Use the reference files (`references/`, `examples/`) for the WHY, not the69 HOW** — garment quirks, design rules, pricing, catalog facts, error decoding.70 The connector already encodes how to make the calls; the references explain71 what a good result looks like. When a connector tool returns a structured72 error code, decode it with `references/error-handling.md`.7374**Everything from "## 1. Authentication" onward is the raw Agent API75fallback** — for runtimes that have only an `APPARELHUB_API_KEY` and no76connector (bare HTTP, some Claude Code setups, ChatGPT / Gemini via the77porting guides). If you have the connector, you don't need any of it.7879---8081## 1. Authentication8283Every API call needs the header:8485```86x-api-key: <your API key>87```8889How the agent sources that key depends on the runtime:9091- **The recommended pattern** is that the agent reads92 `APPARELHUB_API_KEY` from its runtime environment (`os.environ`,93 `process.env`, etc.) at call time. The skill does NOT ask you to94 persist the key to disk and does NOT read it from any config file.95- **For tool-calling agents** (ChatGPT Custom GPT with Actions, Gemini96 function calling): hide the key inside the function-call97 implementation so the agent never sees it. See98 `../porting-guides/chatgpt-gemini.md` for the pattern.99- **For Claude Code** (and similar shell-based agents): use whatever100 mechanism you normally use for development secrets — direnv, shell101 rc, macOS Keychain, etc.102103**If your runtime prompts the first time it reads this environment104variable or makes a network call, that is correct behavior.** Approve105the prompt in context if the call is one you intended. The skill no106longer ships wrappers whose purpose is to dodge those prompts (see107`../SECURITY.md`).108109### Sanity-check the key before a multi-step workflow110111`scripts/ah_check` (optional, Claude Code convenience) verifies that112`APPARELHUB_API_KEY` is set AND accepted by the platform, then prints a113masked confirmation:114115```116ah_check117```118119Exit codes: `0` valid, `2` not set, `3` rejected by the platform or120network failure. Equivalent plain HTTP probe:121122```123curl -sS -o /dev/null -w "%{http_code}\n" \124 https://api.apparelhub.ai/agents/v1/store \125 -H "x-api-key: $APPARELHUB_API_KEY"126```127128`200` means the key works. Anything else, fix the key before continuing.129130**Local key hygiene on shared machines:** `-H "x-api-key: ..."` puts the131key value in the process argv, where `ps` (and other local users) can read132it for the request's duration. On a multi-user box, pass the header via a133curl config on stdin instead, so the key never reaches argv:134135```136curl -sS https://api.apparelhub.ai/agents/v1/store --config - <<CFG137header = "x-api-key: $APPARELHUB_API_KEY"138CFG139```140141The plain `-H` form is fine on a single-user machine. `scripts/ah_check`142already uses the stdin-config form.143144### The canonical OpenAPI spec145146```147GET https://api.apparelhub.ai/agents/v1/openapi.json148```149150Authoritative reference for every endpoint and field. When you're151unsure about a field name or response shape, fetch the spec.152153---154155## 2. The product-creation pipeline at a glance156157Going from "user wants a saguaro tee" to a finished, sellable product158takes these phases. Execute IN ORDER:1591601. **Generate the design image.** `POST /images/generate` with a prompt (slow models, including the Nano Banana default, return **202 + `image_uuid`** and must be polled with `ah_poll_generation`; fast models return 200 + `url`)1612. **LOCAL transparency processing** (your compute, NOT an API call). For162 standard apparel only; SKIP for all-over print1633. **Generate the mockup.** `POST /merchandise/product/preview`. A finished164 product should show a garment MOCKUP, not the bare design — never skip this165 for a product you're presenting as done.1664. **Pick `display_image` + build `gallery_images` from preview rows**1675. **Create the product.** `POST /product/create`1686. **Add variants** (one at a time, no batch endpoint). Read the garment's169 ACTUAL colors/sizes from `get_garment_details` first — do NOT assume170 S/M/L/XL/2XL. Caps, beanies, phone cases, bottles, bags etc. are often171 one-size or use different labels; assuming apparel sizes yields 0 variants.1727. **Map the product to the user's store + sync to fulfillment173 (Printful/Printify).** This is what "map / add to store" and "store174 availability" mean — the product is associated with the store and175 manufacturable. **This is the normal end of the pipeline.**1768. **(ONLY if the user explicitly asked to list / publish / sell it on a177 storefront) sync to the sales channel** (Shopify/WooCommerce/Wix), as a178 DRAFT unless they said go live. Separate, opt-in step — see the ⚠️ below.179180> ⚠️ **"Map / add to a store" is NOT "publish to a sales channel" — don't181> conflate them.** An ApparelHub *store* holds a fulfillment provider182> (Printful/Printify) and, optionally, connected sales channels183> (Shopify/WooCommerce/Wix). **Mapping** a product to a store (Phase 7) makes184> it manufacturable and lists it under the store in ApparelHub; it does NOT185> create a storefront listing. Only push to a **sales channel** (Phase 8 —186> `sync_to_channel` / `?target=ecommerce`) when the user EXPLICITLY asks to187> list, publish, or sell it on that storefront. If they said "map it to the188> store" / "add it to my store" / "put it in the store," STOP at Phase 7 —189> do not invent a channel sync. (This is a real regression that shipped in an190> automated task: "map to the store" was wrongly extended to a WooCommerce sync.)191192**Fastest correct path (especially for automated / scheduled runs): the193`ship_product` MCP tool does Phases 3–7 in ONE call** (mockup → create →194variants → associate → fulfillment sync) with the ordering guaranteed, and195only touches a sales channel if you pass `sync_to_channels`. Prefer it over196chaining the split primitives yourself.197198**Full pipeline detail (every call, every field, every gotcha) lives in199`references/product-creation-pipeline.md`.** Read it before executing200any phase you haven't done in this session.201202**The four field-name gotchas that silently break products** are203documented there and worth memorizing:204205- Phase 3 preview endpoint uses `merchandise_provider_uuid` +206 `provider_product_ref_id`207- Phase 5 create endpoint uses `provider_uuid` + `product_ref_id`208- Same data, FLIPPED names. Don't copy field names between phases.209- Use `price`, not `retail_price`.210211---212213## 3. Decision tree: which reference file to load214215Before executing a workflow, scan this tree. Loading the right216reference up front saves you from shipping a broken product.217218| If the task involves… | Read FIRST |219|---|---|220| Talking to the Agent API at all | `references/api-contract.md` covers the HTTP contract — base URL, auth header, every endpoint, every status code |221| Generating ANY design image | `references/design-rules.md` covers AI prompt anti-patterns, transparency, vision-verification of text |222| **The merchant already OWNS the artwork** (a client logo, a brand mark, a cleared cover, "here are their assets", "do not redraw our mark") | `references/byo-artwork.md`. Upload the file, do NOT generate a lookalike. Three routes: a public `source_url`, a presigned URL you PUT to yourself (cheapest — nothing enters your context), or inline base64 for small files. The returned uuid is a design uuid and works everywhere one does. **SVG is accepted and preferred** — it is rendered at print resolution, so it stays crisp at any size (text must be outlined, linked images embedded). Pass `upscale: "pixel"` for a hard-edge RASTER mark so a small file is not smoothed. Uploads cost no image generations. |223| **Editing / iterating on an existing design** (user says "make the cat smug", "redo this in landscape", "use this as a starting point") | `references/design-rules.md` section 5b explains how `POST /images/generate` doubles as the img2img endpoint via `source_image_uuid` or multipart `images=@...`. Only Nano Banana and OpenAI support edit; Replicate-backed sources 422. |224| **Aspect ratio / matching the print area** (a design's shape doesn't fit the product — square design on a tall phone case / poster / wide banner) | `references/design-rules.md` section 5c: generate at the matching `size` (`1024x1024` square / `1024x1792` tall / `1792x1024` wide), or reshape an EXISTING design with `POST /images/generated/<uuid>/fit-aspect` (`pad` keeps everything / `crop` trims; **quota-free** — no image generation spent). Per-product mapping in `references/all-over-print.md` §12. |225| **Retiring / cleaning up designs** (archive or delete a design, find orphan designs nothing is using, tidy a gallery) | `references/design-rules.md` section 5d. Designs CAN be archived and deleted — do not conclude otherwise. Archive is `PATCH /images/generated/<uuid>` with `{"archived": true}` (reversible, safe, the default choice); delete is `DELETE` on the same path and is refused with `409 image_in_use` while a live product uses it. Find orphans with `GET /images/generated?on_products=false`. |226| **Listing images on a product that already exists** — attaching a merchant photo, reordering the gallery, changing the cover image, or "why is my listing showing the flat artwork?" | `references/product-imagery.md`. ⛔ A **print file** (what gets PRINTED) is not a **listing image** (what a shopper sees); pushing artwork as listing photography is a known quality failure on at least one major channel. ⛔ `gallery_images` **REPLACES** the gallery, so read `images` first and send the whole list back — sending only the new URL deletes the rest. **Ordering is functional**: channels cap listing images (TikTok Shop 9, Wix 15) and truncate in gallery order, so position decides what actually ships. Generated imagery is constrained to EDITING the product's real mockup — a from-scratch product photo invents a product that does not exist. Declare `ai_generated` truthfully; the platform cannot detect it. |227| **"Is my product actually live?" / a listing vanished from a storefront / checking on a synced listing** | `references/product-creation-pipeline.md` **Phase 9**. A sales channel can remove or deactivate a listing at any time without asking, so a successful sync is a fact about the PAST. Read `health` (what the channel last said), not just `sync_status` (what we believe we published) — and treat an absent `health` as "never checked", which is not the same as healthy. ⛔ Do not re-sync a `Removed` listing unchanged; the channel removed it for a reason and churn is itself a risk. |228| Standard apparel (tees, hoodies, tanks, sweatshirts) | `references/product-creation-pipeline.md` |229| **Embroidered apparel** (Champion Anorak, polos, jackets — and headwear only once you have CONFIRMED that garment is embroidered) | `references/embroidery.md` covers the 15-color thread palette + the `thread_colors_<placement>` option-placement trap. Skipping this guarantees a 400 from the provider. Do not assume headwear is embroidered: it spans both families, and assuming is what makes a printable cap invisible. |230| **A garment can't take this design** (embroidery vs print, photoreal artwork refused, "no <item> is possible") | `references/provider-selection.md`. Capability limits are almost always scoped to ONE provider, not to the category. Enumerate providers with `find_garments` BEFORE reporting that something cannot be built. |231| All-over print (pillows, doormats, area rugs, luggage tags, AOP tees, phone cases, mugs) | `references/all-over-print.md` covers edge-to-edge background rules, product-specific gotchas, the "don't name the product in the AI prompt" trap |232| **Channel-defined listing fields** (product attributes, item specifics, category metafields — "set the material", "fill in the compliance answers", "the channel says the listing is incomplete") | `references/listing-attributes.md`. Call `describe_listing_attributes` FIRST — field names and allowed values are defined by the channel per category, so they cannot be guessed and a mismatch is refused. Setting a value does NOT reach the channel until a sync. ⛔ Compliance answers are LEGAL ATTESTATIONS: relay what the merchant tells you, never choose one, and leave it unset if they have not answered. **Size charts** live here too: apparel is graded down without one, so when a listing is flagged, `import_size_measurements` then set `size_chart_measurements` — never type in measurements you were not given. |233| Variant IDs, pricing, color limit, BC 3001 vs Comfort Colors trade-off | `references/garment-catalog.md` |234| **Costs & margin pricing** — reading per-variant cost, setting prices to a target margin, pricing floors | `references/pricing.md`: per-variant `cost` lives on the **store-products list** (`GET /store/<store>/products` → `variants[].cost`), NOT on product-detail; it is resolved when the variant is created (for Printify that needs a mockup first, which the normal build order already does); catalog cost carries `cost_source` = `live`/`cached`/`unavailable` — never compare providers without reading it; price each variant to `cost / (1 - margin)` |235| Listing/inspecting orders, payment status, fulfillment status | `references/orders-and-fulfillment.md` includes the payment-authority rule (sales channel wins for storefront orders) |236| **Managing orders** — approving/confirming/holding, the per-store fulfillment workflow (auto / confirm / review), smart guardrails, the agent approval queue, the opt-in signed callback | `references/orders-and-fulfillment.md` sections 8–10. Note the TWO distinct holds (ApparelHub approval vs Printful design hold). |237| A 4xx / 5xx response, sync that didn't take, "Failed to fetch" UX | `references/error-handling.md` |238| **A delivered item arrived wrong** (doesn't match the mockup, damaged, wrong or missing item, bad print) — reporting it, bridging the claim to Printful/Printify, replacement orders | `references/fulfillment-issues.md` covers the `/agents/v1/orders/.../issues` endpoints, the 30-day report window, eligibility warnings (change-of-mind is not claimable), evidence upload caps, the provider-ready summary + dashboard deep-link handoff, and zero-charge replacement orders |239| **Enterprise / agency account** (multiple workspaces; a list looks like it's "missing" stores/products/designs, or you need to target a specific client workspace) | `references/workspaces.md` covers the `GET /agents/v1/workspaces` discovery route, the `?workspace=` param, the `workspaces` visibility field, 403/404 handling, and workspace-scoped keys |240| **Analytics / reporting** — sales KPIs, trends, top sellers, channel mix, margins, ops health, CSV export, or an agency's per-client portfolio | `references/analytics.md` covers the six read-only `/agents/v1/analytics/*` endpoints, the `advanced_analytics` tier gate (Professional+), currency segmentation, and the `margin_coverage` caveat |241| **Channel performance** — which listings people SEE but do not buy, why a listing is underperforming, what is safe to archive, or whether a channel reports views at all | `references/channel-performance.md` covers the `/agents/v1/analytics/channel/*` endpoints, the shop-level verdict to read *before* any listing state, the seven listing states and the fix each implies, the rule that a missing metric is never a zero, and `/agents/v1/analytics/interventions` — whether the last change you made actually worked |242243When the user asks for an end-to-end flow ("build me a saguaro tee and244sync it"), the `examples/` directory has working walkthroughs you can245adapt:246247| If the user wants… | Read |248|---|---|249| A front-print tee end-to-end | `examples/front-print-tee.md` |250| An all-over-print pillow / doormat / luggage tag | `examples/all-over-pillow.md` |251| An embroidered chest crest on a jacket / polo | `examples/embroidered-anorak.md` |252| Reviewing + approving a held order as an agent (workflow config → poll the queue → approve/hold) | `examples/order-management.md` |253| **A garment can't take the design** — the constraint is one provider's, not the category's; enumerate and build elsewhere | `examples/blocked-garment-find-alternative.md` |254| Attaching a photo to an EXISTING listing + ordering the gallery for a capped channel | `examples/product-imagery-attach-and-order.md` |255256---257258## 4. Top-level safety rails259260These apply across every workflow. Don't override without explicit user261instruction.262263### 4a. Default to DRAFT, never live264265When syncing to a sales channel that supports a draft state (Etsy,266Shopify), push as DRAFT first. The user reviews the listing on the267channel's admin before customers see it. Only push as `active` when268the user EXPLICITLY says "make it live" or "publish it." The cost of a269too-eager publish (typo'd title in front of real customers) is much270higher than the cost of one extra click.271272Tell the merchant:273274> "I've synced as drafts so you can review on your storefront before275> going live. To publish, flip the listing in your channel admin or276> re-run sync with `?listing_state=active`."277278### 4b. Verify the design before creating the product279280**Always** visually inspect the design after Phase 1 AND the mockup281after Phase 3. Never ship a broken design or mockup downstream because282manufacturing follows the mockup.283284Specifically: if the design contains TEXT, verify spelling with vision285tools BEFORE generating the mockup. AI image models routinely misspell.286287### 4c. Respect pricing floors288289The merchant loses money on negative-margin products. Never go below290the recommended retail prices in `references/garment-catalog.md`291without the user explicitly accepting the math.292293### 4d. Color discipline: max 4 colors per design294295More than 4 color variants creates SKU sprawl that hurts conversion.296Pick the 4 best colors for the design and stop.297298### 4e. Embroidery is stitched, not printed — on any provider299300Embroidery reproduces a design in thread, so gradients, photorealism301and fine detail will NOT translate, and the colors must come from a302fixed 15-color thread palette. That is a fact about embroidery, not303about any one provider. See `references/embroidery.md`.304305**Before dropping an item for this reason, check whether a PRINTED306version of the same garment exists.** Call `find_garments` with307`accepts_photoreal: true` across all providers. Headwear especially308spans both families: one provider may carry only embroidered caps while309another carries DTF-printed caps that take a photograph as-is.310311### 4f. Ask the user before syncing anywhere312313Create the product, add variants, add to the store. STOP. Tell the314user what's ready and ask whether to sync to fulfillment and/or to315which sales channels. Sync is a state-changing operation that costs the316merchant time to undo if you got it wrong.317318### 4g. Never state a capability limit you have only checked on one provider319320Say "this provider's hats are embroidery-only", not "hats are321embroidery-only". The first is true and points somewhere; the second is322a claim about the whole catalog that you have not tested, and a user who323believes it stops asking.324325Before you tell a user something cannot be made:3263271. Call `find_garments` with the capability you need. It searches every328 provider on the account by default.3292. If it returns nothing, say what you searched — the response gives you330 `providers_searched` — and that connecting another provider may change331 the answer. "I did not find one on Printful, Printify or Gelato" is332 honest. "It is not possible" is not.333334`accepts_photoreal: null` on a garment means **nobody could tell**, not335that the garment cannot take the design. Treat it as "verify this", never336as a reason to drop the item.337338This rail exists because an agent once found one provider's headwear was339embroidery-only, reported that no hat was possible, and closed the item —340while the same account had printed caps available the whole time.341342---343344## 5. Working with the user's existing data345346```347GET https://api.apparelhub.ai/agents/v1/store348GET https://api.apparelhub.ai/agents/v1/store/<store_uuid>/products?fields=uuid,name,price,status,thumbnail_url,fulfillment_status,ecommerce_statuses349GET https://api.apparelhub.ai/agents/v1/images/generated?limit=20&sort=newest350GET https://api.apparelhub.ai/agents/v1/orders?limit=10351GET https://api.apparelhub.ai/agents/v1/orders/<uuid>352```353354For order data interpretation (payment status, fulfillment status, who355actually charged the card), see `references/orders-and-fulfillment.md`.356357The **store-products list** above carries each product's `variants` array,358and each variant has both `price` (retail) and `cost` (provider production359cost, resolved when the variant is created). That's the place to read cost360for margin pricing — product-detail (`GET /product/<uuid>`) omits variants.361See `references/pricing.md`.362363On an **Enterprise (agency) account**, every list/get above is scoped to one364**active workspace** (the Default workspace unless you pass `?workspace=<uuid>`).365If a list looks like it's missing stores/products/designs, you're probably366scoped to a different workspace, not missing data. See section 6.367368---369370## 6. Workspaces (enterprise accounts)371372Most accounts have a single workspace and can ignore this. On **Enterprise373(agency) accounts** the account is split into isolated client / brand374**workspaces**, and every Agent API call acts within ONE of them.375376- **Discover them.** `GET /agents/v1/workspaces` lists the workspaces this key377 can act in (`uuid` + `name` + `is_default`), the active workspace, and whether378 the key is pinned. Use it to turn a workspace name the user mentions into the379 `uuid` you scope with — do this first whenever the user names a workspace.380- **Default scope.** With no `?workspace=` param, calls act in the account's381 **Default** workspace.382- **Target a workspace.** Add `?workspace=<workspace_uuid>` to any list / get /383 create call (combines with `?limit=`, `?fields=`, etc.).384- **A bad workspace fails the whole call** (no silent fallback): an unknown385 uuid returns `404 workspace_not_found`; a real-but-inaccessible workspace386 returns `403 workspace_forbidden`.387- **Don't misread a subset as missing data.** A scoped list shows that388 workspace's assets, not the whole account. Products and generated images389 carry a `workspaces` array (every workspace they belong to); stores carry390 `workspace_uuid` / `workspace_name`. Check those before reporting "nothing391 there," then re-issue with the right `?workspace=`.392- **Workspace-scoped keys.** An API key can be scoped to one OR MORE workspaces393 (each with a role) in the web UI. It rejects any `?workspace=` outside that set394 with `403 workspace_forbidden`, and a role lacking design-generation gets `403395 forbidden` (`capability: design.generate`) on `POST /images/generate`.396 `GET /agents/v1/workspaces` returns the key's scope in397 `key_scope.workspaces` (`[{workspace_uuid, role}]`).398399Full contract (param, error bodies, Model A visibility, scoped keys, worked400curls) is in **`references/workspaces.md`**. Single-workspace and401non-Enterprise accounts are unaffected.402403---404405## 7. When NOT to use this skill406407- **The user wants to BUY a finished product.** ApparelHub is for408 merchants designing + selling, not end-shoppers. Direct them to the409 merchant's storefront.410- **Generic image generation unrelated to apparel.** Use OpenAI /411 Stability directly; ApparelHub charges against the user's image quota.412- **Platform admin operations** (register your Etsy webhook URLs,413 rotate your Shopify secret). These are done in the apparelhub.ai web414 UI, not via the agent API.415- **Bulk operations beyond ~50 products at once.** The agent API416 enforces rate limits; for true bulk migrations (1000+ products), the417 user should contact ApparelHub support.418419---420421## 8. Reporting back to the user422423After completing a workflow, give a tight summary:424425- What you generated (design URL)426- The mockup link (so they can verify visually)427- The product page URL: `https://apparelhub.ai/merchandise/my-products`428- Which channels you synced to + sync status (draft vs live)429- Anything that didn't succeed and why430431Don't dump raw JSON. Users want outcomes, not API responses.432433---434435## Quick links436437- Product manager: `https://apparelhub.ai/merchandise/my-products`438- Generated designs: `https://apparelhub.ai/images/gallery`439- Stores: `https://apparelhub.ai/stores`440- Orders: `https://apparelhub.ai/orders`441- API keys: `https://apparelhub.ai/developer/api-keys`442- Live API docs (browser): `https://apparelhub.ai/developer/api-docs`443- Live API spec (JSON, authed): `https://api.apparelhub.ai/agents/v1/openapi.json`444- Pricing tiers: `https://apparelhub.ai/pricing`445446---447448## Security and trust model449450See `../SECURITY.md` for the trust model, non-goals (we don't bypass451your platform's permission prompts; we don't persist your API key to452disk; we never send the key anywhere but `https://api.apparelhub.ai`),453and the threat model.