> Portal Navigation: > > - Append `.md` to any URL under `https://dev.wix.com/docs/` to get its markdown version. > - Pages are either content pages (article or reference text) or menu pages (a list of links to child pages). > - To get a menu page, truncate any URL to a parent path and append `.md` (e.g. `https://dev.wix.com/docs/sdk.md`, `https://dev.wix.com/docs/sdk/core-modules.md`). > - Top-level index of all portals: https://dev.wix.com/docs/llms.txt > - Full concatenated docs: https://dev.wix.com/docs/llms-full.txt ## Resource: API: Recommendation Tracking ## Article: API: Recommendation Tracking ## Article Link: https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/skills/api-recommendation-tracking.md ## Article Content: # API: Recommendation Tracking Service This service persists recommendations in a database and tracks their lifecycle state. Every recommendation generated by any domain (discounts, shipping, etc.) **MUST** be persisted here before being presented to the merchant. **Service**: `wix.ecom.agentic.recommendations.v1.AgenticRecommendationsService` **Base URL**: `https://manage.wix.com/_api/agentic-recommendations/v1/agentic-recommendations` ## How to call these APIs Use `CallWixSiteAPI` to invoke each endpoint: ``` CallWixSiteAPI( url: "https://manage.wix.com/_api/agentic-recommendations/v1/agentic-recommendations/", method: "POST", body: { ... } ) ``` --- ## Data Model ### Recommendation | Field | Type | Access | Description | |---|---|---|---| | `id` | string (GUID) | readOnly | Auto-generated unique identifier | | `revision` | int64 | readOnly | Optimistic lock — must match current value for state transitions | | `createdDate` | Timestamp | readOnly | When the recommendation was created | | `updatedDate` | Timestamp | readOnly | When the recommendation was last updated | | `title` | string | writable | Short human-readable title (max 200 chars) | | `reasoning` | string | writable | Why this recommendation is being made, citing specific data (max 2000 chars) | | `domain` | string | writable | Business domain: `"shipping"`, `"discounts"`, etc. (max 50 chars) | | `urgency` | enum | writable | `CRITICAL`, `HIGH`, `MEDIUM`, or `LOW` | | `advice` | Advice | writable | The action to take (see below) | | `state` | enum | readOnly | Current lifecycle state (see State Machine) | | `expiresAt` | Timestamp | writable | When the recommendation auto-expires | | `conversationId` | string (GUID) | writable | Links all recommendations in a session | | `decidedBy` | string | readOnly | Who made the last state transition | | `rejectionReason` | string | readOnly | Reason for rejection (max 1000 chars) | | `rejectionPermanent` | boolean | readOnly | If true, this action type is permanently blocked for this site | | `executionResult` | ExecutionResult | readOnly | Result of execution (set on DONE/FAILED) | ### Advice | Field | Type | Description | |---|---|---| | `action` | string | Action identifier (e.g., `"apply_discount"`, `"create_shipping_option"`) (max 100 chars) | | `params` | object | Domain-specific parameters (discount config, shipping option details, etc.) | | `successCriteria` | string | How to verify the action succeeded (max 500 chars) | ### ExecutionResult | Field | Type | Description | |---|---|---| | `status` | enum | `SUCCESS`, `PARTIAL_FAILURE`, or `FAILURE` | | `summary` | string | Description of what happened (max 2000 chars) | | `error` | string | Error message if failed (max 2000 chars) | | `resultPayload` | object | Additional result data | --- ## State Machine ``` PROPOSED → APPROVED → EXECUTING → DONE │ └──→ FAILED ├──→ REJECTED └──→ EXPIRED (scheduler) ``` | From | To | Trigger | API Method | |---|---|---|---| | — | PROPOSED | Recommendation created | BatchCreate / Create | | PROPOSED | APPROVED | Merchant approves | Approve | | PROPOSED | REJECTED | Merchant rejects | Reject | | PROPOSED | EXPIRED | `expiresAt` passed | Automatic (scheduler) | | PROPOSED | PROPOSED | Merchant modifies parameters | Update (state unchanged) | | APPROVED | EXECUTING | Execution begins | MarkExecuting | | EXECUTING | DONE | Execution succeeded | MarkDone | | EXECUTING | FAILED | Execution failed | MarkFailed | --- ## BatchCreate Creates multiple recommendations (1-100) atomically. All start in PROPOSED state. **Use this as the default** — always batch recommendations together. **Endpoint**: `POST https://manage.wix.com/_api/agentic-recommendations/v1/agentic-recommendations/batch-create` **Request**: ```json { "agenticRecommendations": [ { "title": "15% Off Electronics — Orders Over $200", "reasoning": "AOV is $165. Electronics avg margin 42%. $200 threshold incentivizes adding one more item.", "domain": "discounts", "urgency": "HIGH", "advice": { "action": "apply_discount", "params": { "mechanism": "AUTOMATIC", "scope": "CATEGORY", "discountType": "PERCENTAGE", "discount": 15, "conditions": { "minSubTotal": 200 } }, "successCriteria": "15% discount applied to Electronics for orders above $200" } } ], "conversationId": "" } ``` **Response**: ```json { "results": [ { "agenticRecommendation": { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "revision": "1", "state": "PROPOSED", "title": "15% Off Electronics — Orders Over $200", "reasoning": "...", "domain": "discounts", "urgency": "HIGH", "advice": { "..." : "..." }, "conversationId": "...", "createdDate": "2026-05-10T10:00:00Z", "updatedDate": "2026-05-10T10:00:00Z" } } ] } ``` **Important**: Save the `id` and `revision` from each result — you need them for all subsequent state transitions. --- ## Create Creates a single recommendation in PROPOSED state. Prefer BatchCreate for multiple recommendations. **Endpoint**: `POST https://manage.wix.com/_api/agentic-recommendations/v1/agentic-recommendations` **Request**: ```json { "agenticRecommendation": { "title": "Add Free Shipping for Orders Over $75", "reasoning": "No free shipping option. delivery_step_cvr is 48%, below 65% benchmark. AOV is $62.", "domain": "shipping", "urgency": "HIGH", "advice": { "action": "create_shipping_option", "params": { "category": "free_shipping", "ids": ["region-guid"], "rates": [{ "amount": "0", "conditions": [{ "type": "BY_TOTAL_PRICE", "operator": "GTE", "value": "75" }] }] }, "successCriteria": "Free shipping option created for orders above $75" }, "conversationId": "" } } ``` **Response**: Single `agenticRecommendation` object with `id`, `revision`, and `state: "PROPOSED"`. --- ## Query Query recommendations by conversation ID, state, or domain. Returns paginated results. **Endpoint**: `POST https://manage.wix.com/_api/agentic-recommendations/v1/agentic-recommendations/query` **Request**: ```json { "query": { "filter": { "conversationId": "", "state": { "$in": ["PROPOSED", "APPROVED"] } }, "cursorPaging": { "limit": 50 } } } ``` **Filterable fields**: `conversationId`, `state`, `domain`, `urgency`, `id` **Response**: ```json { "agenticRecommendations": [ { "id": "a1b2c3d4-...", "revision": "1", "state": "PROPOSED", "title": "...", "domain": "discounts", "urgency": "HIGH", "advice": { "..." : "..." } } ], "pagingMetadata": { "count": 1, "cursors": {}, "hasNext": false } } ``` --- ## Get Fetch a single recommendation by ID. **Endpoint**: `GET https://manage.wix.com/_api/agentic-recommendations/v1/agentic-recommendations/{agenticRecommendationId}` **Response**: Single `agenticRecommendation` object with all fields. --- ## Count Get recommendation counts grouped by state for the current site. **Endpoint**: `POST https://manage.wix.com/_api/agentic-recommendations/v1/agentic-recommendations/count` **Request**: `{}` **Response**: ```json { "counts": { "PROPOSED": 3, "APPROVED": 1, "EXECUTING": 0, "DONE": 5, "FAILED": 1, "REJECTED": 2 } } ``` --- ## Update Update a PROPOSED recommendation. Only `title`, `reasoning`, `urgency`, `advice`, and `expiresAt` can be updated. State stays PROPOSED. **Endpoint**: `PATCH https://manage.wix.com/_api/agentic-recommendations/v1/agentic-recommendations/{agenticRecommendationId}` **Request**: ```json { "agenticRecommendation": { "id": "a1b2c3d4-...", "revision": "1", "advice": { "action": "apply_discount", "params": { "discount": 20 }, "successCriteria": "20% discount applied" } }, "fieldMask": { "paths": ["advice"] } } ``` **Response**: Updated `agenticRecommendation` with incremented `revision`. **Constraint**: Only works on PROPOSED recommendations. Non-PROPOSED returns INVALID_STATE_TRANSITION. --- ## Approve PROPOSED → APPROVED. Call when the merchant agrees with a recommendation. **Endpoint**: `POST https://manage.wix.com/_api/agentic-recommendations/v1/agentic-recommendations/{agenticRecommendationId}/approve` **Request**: ```json { "revision": "1" } ``` **Response**: Updated `agenticRecommendation` with `state: "APPROVED"` and incremented `revision`. --- ## Reject PROPOSED → REJECTED. Call when the merchant declines. **Endpoint**: `POST https://manage.wix.com/_api/agentic-recommendations/v1/agentic-recommendations/{agenticRecommendationId}/reject` **Request**: ```json { "revision": "1", "reason": "Merchant prefers flat-rate discount instead", "permanent": false } ``` | Field | Type | Required | Description | |---|---|---|---| | `revision` | int64 | Yes | Current revision for optimistic locking | | `reason` | string | No | Why the merchant rejected (max 1000 chars) | | `permanent` | boolean | No | If true, permanently blocks this action type for this site | **Response**: Updated `agenticRecommendation` with `state: "REJECTED"`. --- ## MarkExecuting APPROVED → EXECUTING. Call immediately before applying the recommendation. **Endpoint**: `POST https://manage.wix.com/_api/agentic-recommendations/v1/agentic-recommendations/{agenticRecommendationId}/mark-executing` **Request**: ```json { "revision": "2" } ``` **Response**: Updated `agenticRecommendation` with `state: "EXECUTING"` and incremented `revision`. --- ## MarkDone EXECUTING → DONE. Call after the recommendation was successfully applied. **Endpoint**: `POST https://manage.wix.com/_api/agentic-recommendations/v1/agentic-recommendations/{agenticRecommendationId}/mark-done` **Request**: ```json { "revision": "3", "executionResult": { "status": "SUCCESS", "summary": "Created 15% discount rule for Electronics with $200 minimum" } } ``` **Response**: Updated `agenticRecommendation` with `state: "DONE"` and `executionResult`. --- ## MarkFailed EXECUTING → FAILED. Call when execution fails. **Endpoint**: `POST https://manage.wix.com/_api/agentic-recommendations/v1/agentic-recommendations/{agenticRecommendationId}/mark-failed` **Request**: ```json { "revision": "3", "executionResult": { "status": "FAILURE", "summary": "Failed to create discount rule", "error": "REVISION_MISMATCH: discount rule was modified by another process" } } ``` **Response**: Updated `agenticRecommendation` with `state: "FAILED"` and `executionResult`. --- ## Error Codes | Error | HTTP | Meaning | |---|---|---| | RECOMMENDATION_SUPPRESSED | 400 | Action + site blocked by permanent rejection | | INVALID_STATE_TRANSITION | 400 | Wrong source state for the requested transition | | VERSION_MISMATCH | 400 | Optimistic lock conflict — re-fetch and retry | | RECOMMENDATION_NOT_FOUND | 404 | ID doesn't exist | On VERSION_MISMATCH: Query to get the latest revision, then retry the operation with the updated revision. --- ## Integration pattern for all recommendation flows Every recommendation flow MUST follow this lifecycle: ``` Step 1: Generate recommendations (domain-specific analysis) Step 2: BatchCreate → persist ALL recommendations as PROPOSED (save id + revision for each) Step 3: Present recommendations to merchant (include id + revision) Step 4: On each merchant action: - APPROVE: Approve → MarkExecuting → apply the change → MarkDone or MarkFailed - REJECT: Reject (with reason, permanent flag) - MODIFY: Update (field mask) → stays PROPOSED → re-present ``` **Rules**: - Every recommendation MUST be persisted before presenting to the merchant - Always use the latest `revision` from the previous API response - Track ALL outcomes — both success (MarkDone) and failure (MarkFailed) - On VERSION_MISMATCH: re-fetch with Query, get latest revision, retry - Never skip the EXECUTING state — always call MarkExecuting before applying