← Files WixARCHIVED FILE
skills/wix-manage/references/ecommerce/api-recommendation-tracking.md
12.3 KB · Oct 4, 2026 · 12:02 UTC
---
name: "API: Recommendation Tracking"
description: CRUD API for persisting and managing the lifecycle of AI-generated recommendations. Tracks state transitions from PROPOSED through APPROVED, EXECUTING, to DONE/FAILED/REJECTED. Every recommendation must be persisted here before presenting to the merchant.
layer: config
---
# 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/<endpoint>",
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": "<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": "<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": "<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
SHA-256: 15286069e163bf12aeec4d74a468d7d2243a71500792fc23dea7be0b2124016e