⛔ Routing gate — Recommend: eCommerce Strategy must be loaded before this file.
This is the GIFT_CARDS domain sub-step, not a direct entry point. If you have not yet loaded the orchestrator in this conversation, stop and load it now. It owns domain activation (its Step 4), the recommendation-history check that stops you re-pitching a rejected gift card (its Step 2), and the 5-recommendation cap. This file owns what's specific to gift cards: the existing-product gate, eligibility, denomination sizing, expiry policy, persistence of this recommendation (Step 5), and the create-call mapping.
Goal ID: SELL_GIFT_CARDS
Produces at most one recommendation — create a gift card product on a site that doesn't sell one yet — carrying the full product design: name, description, preset denominations, custom amount range, expiration policy. Amounts are calibrated from the site's own AOV and catalog price distribution.
The orchestrator activates this domain on "should I sell gift cards", "add a gift card", "which amounts should my gift card offer", gift-card denominations, a gifting-season prompt where a gift card is the lever, or an open "boost my sales" prompt on a site that sells no gift card yet with a gifting occasion near.
Not this goal: issuing / redeeming / voiding / emailing an individual gift card is the Gift Cards API — a direct operation, not a recommendation. Changing denominations on a product that already exists is Update Gift Card Product.
reasoning must come from an API response. Name the call it came from.BatchCreate (Step 5) before the merchant sees it, unless they said SKIP_TRACKING.MANDATORY HARD GATE — a site supports a maximum of 1 gift card product. Skipping this produces a recommendation that can only fail with GIFT_CARD_PRODUCT_ALREADY_EXISTS (409) at creation time.
Endpoint: POST https://www.wixapis.com/gift-cards/v1/gift-card-products/query
Response (amounts are in the site's currency; formattedAmount carries the site's own symbol — use it when displaying):
| Outcome | Action |
|---|---|
giftCardProducts is empty | Continue to Step 2. |
| One or more products returned | Drop the GIFT_CARDS domain — no create recommendation, nothing persisted, and the orchestrator reuses the freed slot. Then answer with the existing-product review below rather than a bare stop. |
Call fails with 403 / app-not-installed | Wix Gift Cards is not available on this site. Report the blocker verbatim; do not recommend around it. |
| Call fails for any other reason | Report the exact error and drop the domain. Do not assume "no product exists" — a false negative here produces a guaranteed-to-fail recommendation. |
A merchant asking "should I sell gift cards / which amounts?" who already has a product wants their current setup assessed. Never emit a create recommendation, never persist anything, and never propose a second product — a site supports one. Instead, read the design rules in Step 3 and report:
name, the preset amounts and custom range from the Query response (use formattedAmount), and the expiry stance read from expirationType: NONE → "these never expire, which is the safer default"; RELATIVE / FIXED → state the period or date and flag that gift card expiry is regulated and varies by market, so it's worth confirming it's permitted where they sell.PATCH, needs the current revision), and the dashboard link at the end of Step 5. Updating replaces the whole presetVariants list; individual presets can't be patched.Expiry gets stated in this path too — reading it off the existing product, per Step 3d. A gift-card answer that never mentions expiry is incomplete regardless of which branch you took.
Site data comes from the orchestrator's context load (eCommerce: Load Context) — siteData.currency, language, country, industry, aov, orders30d, visitors30d, catalogAnalytics, hasCatalog. Do not re-fetch any of it.
| Condition | Decision |
|---|---|
siteData.hasCatalog === false (0 products) | Drop the domain. "Gift cards need something to spend them on. Add products to your catalog first." |
aov is available (site has orders) | Continue — aov alone is enough to size denominations. Missing or empty catalogAnalytics is not a blocker; you simply skip the catalog clamps in Step 3b. |
aov unavailable but catalogAnalytics has price data | Continue — anchor on the catalog median instead. |
Both missing — no aov and no usable catalog price data | Drop the domain. "Cannot size gift card denominations — this site has no order or catalog price data to base amounts on." Do not fall back to a stock 25/50/100 ladder, and do not invent product names or prices. Saying you can't size it yet is the correct answer here; offer to proceed if the merchant names a typical order value. |
orders30d === 0 and visitors30d < 100 | Continue, but urgency is LOW and reasoning must say the store has little traffic to convert yet. |
| Everything else | Continue. |
Gift cards are the classic last-minute gift, so the product must be live ≥ 21 days before the occasion to catch the buying window — that lead time is the whole reason urgency matters here.
Using current_date and siteData.country, resolve the nearest gifting occasion within 75 days for that country. Do not assume a US calendar — the same occasion moves, and some don't exist locally:
Other occasions worth resolving per country rather than assuming: Valentine's Day, Father's Day, graduation season, Black Friday, Boxing Day, Lunar New Year, Diwali, Eid al-Fitr, Hanukkah.
If nothing lands within 75 days, do not drop the domain — recommend the evergreen case (birthdays, last-minute gifts, indecisive buyers) at lower urgency.
| Condition | urgency |
|---|---|
| Gifting occasion 21–75 days out | HIGH |
| Gifting occasion under 21 days out | MEDIUM — the product can still go live, but say the buying window is already open and part of it is lost |
No occasion in window, but a gifting-heavy industry (fashion, beauty, jewelry, food & drink, wellness/spa, art, home decor, toys, books) or orders30d >= 10 | MEDIUM |
| Anything else | LOW |
Never use CRITICAL. Gift cards are a revenue opportunity, never a blocker — the orchestrator reserves CRITICAL for broken configuration (no shipping coverage, no payment method).
All amounts are decimal strings in siteData.currency. The numbers in the examples below are bare on purpose — no currency symbol belongs in the params.
| Available data | anchor |
|---|---|
orders30d >= 1 and aov > 0 | aov (= gpv30d / orders30d) — what customers actually spend. Preferred, and sufficient on its own. |
No aov, but catalogAnalytics has prices | p50 — the median price from the "All Products" group |
aov comes from the metasite profile fields the orchestrator already loaded, not from the catalog — so a failed or empty GetCatalogAnalytics does not stop you sizing denominations. Only both sources missing does (Step 2a).
When catalogAnalytics is available, also read priceMin (min(price)), priceMax (max(price)), and p90 from the "All Products" group — they only tune the clamps in Step 3b. Ignore every other categoryName: category-level stats do not size a store-wide gift card.
Candidates: anchor × 0.5, anchor × 1, anchor × 2, anchor × 4.
Round each to a "nice" number:
| Raw amount | Round to nearest multiple of |
|---|---|
| < 50 | 5 |
| 50 – 199 | 10 |
| 200 – 499 | 25 |
| ≥ 500 | 50 |
Floor every value at 10. Drop duplicates. Sort ascending.
If priceMin is known and the lowest preset falls below it, raise it to priceMin rounded up with the table — a card that can't buy the cheapest item is dead weight. Skip this step when catalog stats are unavailable.
If priceMax is known, cap the highest preset at priceMax × 2 rounded with the table. Skip when unavailable.
Keep 3–5 presets. Fewer than 3 after dedupe ⇒ add anchor × 3 (rounded) until you have 3.
Worked example — aov = 62, priceMin = 18, priceMax = 210, all in the site's currency:
31 → 30, 62 → 60, 124 → 120, 248 → 250; cap check 210 × 2 = 420 → no change ⇒ ["30", "60", "120", "250"].
The rounding table is currency-agnostic: it operates on the site's own currency units, whatever they are. Do not convert to another currency first, and do not re-tune the thresholds per currency.
Always include one — it captures buyers whose budget sits between presets.
minValue = min(lowest preset ÷ 2, priceMin), rounded with the table, floored at 10.maxValue = highest preset × 2, rounded with the table.minValue must be strictly less than maxValue — otherwise creation fails with CANNOT_CREATE_GIFT_CARD_PRODUCT_WITH_INVALID_CUSTOM_AMOUNTS_RANGE.Continuing the example: minValue = "15", maxValue = "500".
Default: no expiration. Leave expirationMonths unset. Two reasons, both worth stating in reasoning:
Only if the merchant explicitly asked for an expiry: propose expirationMonths: 60 (5 years), and add to reasoning: "Expiry set at the merchant's request. Gift card expiry is regulated in many jurisdictions — confirm 5 years is permitted where you sell." Never propose fewer than 60 months. Never volunteer an expiry the merchant didn't ask for.
State the expiry stance explicitly, every time — in every branch. When you're recommending a new product it must appear in all three of reasoning, successCriteria, and the prose you show the merchant; when a product already exists, report that product's expirationType instead (Step 1). Concretely, for a new product — "these cards never expire, which is also the safer default because expiry is regulated and varies by market", or the 5-year version with its caveat. A recommendation that silently omits expiry is incomplete: expiry is a decision the merchant is accountable for, not a default to leave unmentioned.
Customer-facing copy — write both in siteData.language, not English.
| Field | Rules |
|---|---|
name | Max 55 chars (hard API limit). 2–4 words. "eGift Card" is the safe default; add one vertical word when the industry is obvious ("Spa eGift Card", "Bookshop Gift Card"). No amounts — the variants carry those. No store name unless the merchant gave one. |
description | Max 3000 chars, but write 1–3 sentences (~200–400 chars). Cover: any amount works, it's delivered by email, and — only when expirationMonths is unset — that it never expires. Never claim a delivery method or expiry the params don't back. |
Run every check before handing the recommendation back to the orchestrator. A failure here is a recommendation that cannot be executed.
| # | Check |
|---|---|
| 1 | No existing gift card product (Step 1 returned empty) |
| 2 | No PROPOSED / DONE gift-card recommendation, and no permanent rejection, in the orchestrator's history load (its Step 2) |
| 3 | name non-empty and ≤ 55 chars |
| 4 | description ≤ 3000 chars |
| 5 | At least one preset variant or a custom variant — both empty fails with CANNOT_CREATE_GIFT_CARD_PRODUCT_WITHOUT_VARIANTS. This goal always emits both. |
| 6 | 3–5 presets, ascending, no duplicates, every value ≥ 10 |
| 7 | customVariant.minValue < customVariant.maxValue |
| 8 | Every amount is a decimal string ("60", not 60), scale ≤ 4, in siteData.currency, with no currency symbol baked into the value |
| 9 | expirationMonths either unset or ≥ 60, and set only because the merchant asked |
| 10 | name / description in siteData.language; title / reasoning in English |
| 11 | reasoning cites the actual numbers and names the call each came from |
| 12 | The expiry stance is stated in reasoning, successCriteria, and the prose shown to the merchant |
| 13 | BatchCreate returned an id (or the merchant said SKIP_TRACKING, or you are reporting that tracking failed) |
| 14 | At most one gift-card recommendation in the orchestrator's set |
⛔ You have not finished this goal until BatchCreate has returned an id. Do not present the recommendation to the merchant before that. Skip only if the merchant said SKIP_TRACKING or "don't track". See API: Recommendation Tracking for the lifecycle.
Endpoint: POST https://manage.wix.com/_api/agentic-recommendations/v1/agentic-recommendations/batch-create
If the orchestrator activated other domains too, this recommendation goes into that same batch — one BatchCreate for all domains, not a second call. If gift cards is the only active domain, make the call here yourself.
Save the returned id and revision — they are what the merchant approves against, and Step 6 needs them. If BatchCreate fails, present the recommendation anyway, without an id, and say that tracking failed.
The recommendation object — domain: "gift_cards", action: "create_gift_card_product":
Omit giftCardProduct.expirationMonths entirely when there's no expiry. Do not send null.
expiresAt = the earlier of (gifting occasion − 7 days) and (current_date + 30 days); current_date + 30 days when there's no occasion in window. Past that the data is stale and the window is gone.
In the orchestrator's output, echo the id and revision BatchCreate returned for this recommendation — they're required for Approve / MarkExecuting / MarkDone. When presenting, format the denominations in the site's currency and include this dashboard link (from Stores Dashboard Navigation):
https://manage.wix.com/dashboard/{siteId}/ecom-platform/gift-cards
| Field | Rule |
|---|---|
id / revision | From the BatchCreate result. Omit only if tracking was skipped or failed. |
title | Max 200 chars, English. Lead with the outcome and the denominations. |
params.shortTitle | Max 50 chars, ~5 words — headline for dashboards and notifications. English. |
reasoning | Max 2000 chars, English. Must name the source call for every number (QueryGiftCardProducts, metasite profile fields, GetCatalogAnalytics). |
domain | Always "gift_cards". |
urgency | HIGH, MEDIUM, or LOW — per Step 2c. Never CRITICAL. |
name, description | Customer-facing — in siteData.language. |
| All amounts | Decimal strings in siteData.currency, no symbol in the value. Format with the currency only when displaying to the merchant. |
successCriteria | Concrete and checkable: product name, exact denominations, custom range, expiry. |
Only after the merchant approves the persisted recommendation, follow the tracking transitions in API: Recommendation Tracking — Approve → MarkExecuting → create → MarkDone / MarkFailed — and call Create Gift Card Product:
POST https://www.wixapis.com/gift-cards/v1/gift-card-products
params do not map 1
params.giftCardProduct | Create Gift Card Product field | Notes |
|---|---|---|
name | giftCardProduct.name | Required. |
description | giftCardProduct.description | Optional. |
presetVariants[].value | presetVariants[].price.amount and presetVariants[].value.amount | Both required. Set them to the same amount — price is what the buyer pays, value is the balance loaded. They differ only for promotional pricing (pay 45, get 50), which this goal never proposes. |
customVariant.minValue / maxValue | customVariant.minValue.amount / customVariant.maxValue.amount | Decimal strings. |
expirationMonths unset | expirationType: "NONE" | The default. |
expirationMonths: 60 | expirationType: "RELATIVE", relativeExpirationDate: { "value": 60, "period": "MONTHS" } | period ∈ DAYS/WEEKS/MONTHS/YEARS. FIXED + fixedExpirationDate is the other option — this goal never uses it. |
| — | image | Not part of the recommendation. Optional at creation; Wix Media Manager images only (id, width, height required). Upload first if the merchant wants one. |
Currency comes from the site's default — the request carries bare amounts, not a currency field. On success, call MarkDone with the new giftCardProduct.id in executionResult.resultPayload and hand back the dashboard link.
| Error | Cause | Fix |
|---|---|---|
GIFT_CARD_PRODUCT_ALREADY_EXISTS (409) | A product exists — Step 1 was skipped or raced | Drop the domain; route to Update Gift Card Product |
CANNOT_CREATE_GIFT_CARD_PRODUCT_WITHOUT_VARIANTS (428) | No presets and no custom variant | Validation check 5 |
CANNOT_CREATE_GIFT_CARD_PRODUCT_WITH_INVALID_CUSTOM_AMOUNTS_RANGE (400) | minValue >= maxValue | Validation check 7 |
CANNOT_CREATE_GIFT_CARD_PRODUCT_WITH_PAST_EXPIRATION_DATE (428) | A FIXED expiry date in the past | This goal never uses FIXED — use RELATIVE |
403 / app not installed on QueryGiftCardProducts | Wix Gift Cards unavailable on the site | Report the blocker; do not work around it |
RECOMMENDATION_SUPPRESSED (400) | create_gift_card_product permanently rejected for this site | Never re-propose; tell the merchant it's suppressed |
VERSION_MISMATCH (400) | Stale revision on a state transition | Query for the latest revision, then retry |
| Missing catalog and order data | New/empty site | Drop the domain — do not invent denominations |
presetVariants[].price and .value are always equal — promotional gift-card pricing is out of scope.BatchCreate before presenting (Step 5), unless SKIP_TRACKING.Last updated: 3 August 2026