openapi: 3.0.1
info:
title: Cart Actions Endpoints Optimize API
description: fabric's **Cart API** lets you add, update, and remove items from your Storefront cart, either as a guest user or as a logged-in user. It also provides functionality to merge carts when you switch from guest user to logged-in user, and apply coupons and other attributes (for example, gift wrapping) to the line items. Additionally, the API supports more advanced tasks such as using multiple carts within a B2B organization, sharing carts, and supporting a unified cart experience for multi-region and multi-brand businesses.<p>The Cart API provides high performance, scalability, multi-tenancy, and configurability to the end-to-end order processing actions that start from the item being added to the cart; through the pre-checkout stage that includes billing, shipping, and payment details; to the checkout stage where the order is processed and confirmed by fabric's Order Management System (OMS)
contact:
name: Cart Support
email: support.cnc@fabric.inc
license:
name: fabric API License
url: https://fabric.inc/api-license
version: 3.0.0
servers:
- url: https://api.fabric.inc/v3
security:
- bearerAuth: []
tags:
- name: Optimize
paths:
/v2/optimize/artifacts:
post:
summary: Upload a Catalog Artifact
description: 'Uploads a catalog CSV as multipart form data and returns an `artifact_id` for use when starting an optimization workflow.
The HTTP client must set the `Content-Type: multipart/form-data` header with the appropriate boundary; the header should not be set manually. The `domain` header is required and must be a brand domain (for example, `vessel.com`) that the authenticated principal is authorized to access.
Each request creates a new artifact, even when the file content is identical to a previously uploaded file. Retain the returned `artifact_id` for the workflow that will reference it.
For catalogs larger than approximately 100 MB, contact fabric support to enable the presigned-URL upload flow.
### Catalog CSV format
The uploaded file must be UTF-8 encoded, comma-delimited, and include a header row. The supported columns are:
| Column | Required | Description |
| :------------------- | :---------- | :---------- |
| `title` | Yes | Product display name as shown on the product detail page. |
| `sku` | Yes | Unique product identifier within the brand catalog. |
| `description` | Yes | Full product description from the product detail page. |
| `category_id` | Conditional | The brand''s category identifier. Each row must provide either `category_id` or `breadcrumb`. |
| `breadcrumb` | Conditional | Full category hierarchy separated by ` > ` (for example, `Mens > Clothing > Pants`). Each row must provide either `breadcrumb` or `category_id`. |
| `category` | No | Free-text category label. Used as a hint when neither `category_id` nor `breadcrumb` resolves to a known category. |
| `product_group_id` | No | Identifier shared by product variants that belong to the same family. |
| `price` | No | Numeric price value for the product. |
| `currency` | No | Currency code corresponding to `price`. |
| `url` | No | Canonical product detail page URL. |
| `images` | No | One or more image URLs separated by the pipe character (`\|`). |
| `attribute.<name>` | No | Custom attribute value. Free-form string, single value per cell. The `<name>` segment must match an attribute key configured for the brand. |
For a worked end-to-end example including auth and workflow creation, see the [Product Import Developer Guide](/product-agent/developer-guides/postman-import-csv-guide).
'
operationId: uploadOptimizeArtifact
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/DomainHeader'
requestBody:
required: true
content:
multipart/form-data:
schema:
$ref: '#/components/schemas/UploadArtifactRequest'
responses:
'201':
description: Artifact uploaded
content:
application/json:
schema:
$ref: '#/components/schemas/ArtifactResponse'
example:
artifact_id: art_95c650ded4824dc79bb6df16427e4a10
kind: csv
source: upload
bytes: 45678
sha256: 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08
content_type: text/csv
uri: s3://product-agent-data-prod-ue2/optimize-artifacts/svc_yourClientId/art_95c650ded4824dc79bb6df16427e4a10/catalog.csv
original_filename: catalog.csv
brand_id: 691df5949676c8e0b1d7b6b3
created_at: '2026-05-15T10:30:00Z'
'401':
description: Unauthorized. The access token is missing or has expired.
content:
application/json:
schema:
$ref: '#/components/schemas/errorResponse'
'403':
description: Forbidden. The caller is not authorized for the brand specified in the `domain` header.
content:
application/json:
schema:
$ref: '#/components/schemas/errorResponse'
'422':
description: Validation error
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
'500':
description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/errorResponse'
tags:
- Optimize
/v2/optimize/artifacts/{artifact_id}:
get:
summary: Retrieve Artifact Metadata and Download URL
description: 'Returns metadata for a previously uploaded artifact along with a short-lived signed `download_url` for retrieving the original file contents. This endpoint supports inspection, auditing, and re-download of an artifact prior to starting a workflow.
The `download_url` is a presigned URL that remains valid until `download_url_expires_at`. After expiry, call this endpoint again to obtain a new URL.
'
operationId: getOptimizeArtifact
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/DomainHeader'
- name: artifact_id
in: path
required: true
description: Artifact identifier returned by `POST /v2/optimize/artifacts`.
schema:
type: string
example: art_95c650ded4824dc79bb6df16427e4a10
- name: expires_seconds
in: query
required: false
description: Lifetime of the signed `download_url` in seconds. Minimum 60, maximum 3600, default 900.
schema:
type: integer
minimum: 60
maximum: 3600
default: 900
example: 900
responses:
'200':
description: Artifact metadata and signed download URL
content:
application/json:
schema:
$ref: '#/components/schemas/ArtifactReadResponse'
example:
artifact_id: art_95c650ded4824dc79bb6df16427e4a10
kind: csv
source: upload
bytes: 45678
sha256: 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08
content_type: text/csv
uri: s3://product-agent-data-prod-ue2/optimize-artifacts/svc_yourClientId/art_95c650ded4824dc79bb6df16427e4a10/catalog.csv
original_filename: catalog.csv
brand_id: 691df5949676c8e0b1d7b6b3
created_at: '2026-05-15T10:30:00Z'
download_url: https://product-agent-data-prod-ue2.s3.amazonaws.com/optimize-artifacts/svc_yourClientId/art_95c650ded4824dc79bb6df16427e4a10/catalog.csv?X-Amz-Signature=...
download_url_expires_at: '2026-05-15T10:45:00Z'
'401':
description: Unauthorized. The access token is missing or has expired.
content:
application/json:
schema:
$ref: '#/components/schemas/errorResponse'
'403':
description: Forbidden. The artifact belongs to a different brand.
content:
application/json:
schema:
$ref: '#/components/schemas/errorResponse'
'404':
description: Artifact not found
content:
application/json:
schema:
$ref: '#/components/schemas/errorResponse'
'422':
description: Validation error
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
'500':
description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/errorResponse'
tags:
- Optimize
/v2/optimize/workflows:
post:
summary: Create an Optimization Workflow
description: 'Creates an optimization workflow that processes a previously uploaded artifact. Provide the `artifact_id` returned by `POST /v2/optimize/artifacts` as `input.artifact.artifact_id`.
Workflows run in supervised mode by default. The workflow pauses at human-in-the-loop review gates that allow reviewers to approve taxonomy mappings, sample enrichments, and the final publish step.
**Review gates are approved in the CommerceOS web application, not through the API.** When a workflow reaches `status: REVIEW_PENDING`, direct a reviewer to [CommerceOS](https://commerceos.fabric.inc) to evaluate and approve the active gate. Once the reviewer acts in the UI, the workflow resumes automatically and the next poll of `GET /v2/optimize/workflows/{workflow_id}` reflects the new state.
'
operationId: createOptimizeWorkflow
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/DomainHeader'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateWorkflowRequest'
example:
input:
artifact:
artifact_id: art_95c650ded4824dc79bb6df16427e4a10
name: Spring 2026 catalog enrichment
origin: API
tags: []
responses:
'201':
description: Workflow created
content:
application/json:
schema:
$ref: '#/components/schemas/OptimizeWorkflowResponse'
example:
id: 9349773c-27fe-4d4f-a093-a5793dff8702
brand_id: 691df5949676c8e0b1d7b6b3
type: OPTIMIZE
origin: API
workflow_type: null
status: PENDING
current_step: null
current_hitl_gate: null
name: Spring 2026 catalog enrichment
tags: []
started_at: null
completed_at: null
last_error: null
retry_count: 0
workflow_metadata: null
progress: null
review_summary:
total_categories: 0
decided_categories: 0
pending_categories: 0
rerunning_categories: 0
rejected_categories: 0
ready_for_publish_categories: 0
published_categories: 0
reviewer_summary: []
created_by:
id: user_xyz
type: user
name: Integration Bot
email: integration@acme.com
updated_by:
id: user_xyz
type: user
name: Integration Bot
email: integration@acme.com
created_at: '2026-05-15T10:35:00Z'
updated_at: '2026-05-15T10:35:00Z'
'400':
description: Bad request. The `input` field is missing or specifies more than one source.
content:
application/json:
schema:
$ref: '#/components/schemas/errorResponse'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/errorResponse'
'403':
description: Forbidden. The caller is not authorized for the brand specified in the `domain` header, or the referenced artifact belongs to a different brand.
content:
application/json:
schema:
$ref: '#/components/schemas/errorResponse'
'404':
description: Referenced artifact not found
content:
application/json:
schema:
$ref: '#/components/schemas/errorResponse'
'422':
description: Validation error
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
'500':
description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/errorResponse'
tags:
- Optimize
/v2/optimize/workflows/{workflow_id}:
get:
summary: Retrieve Optimization Workflow Status
description: 'Returns the current state of an optimization workflow, including `status`, `current_step`, `current_hitl_gate` (when the workflow is paused at a review gate), per-phase progress, and aggregated review and reviewer summaries.
Poll this endpoint to track a workflow through its lifecycle. A `401` response indicates that the access token has expired; re-authenticate and retry the request.
The `status` value progresses through `PENDING`, then `RUNNING` or `IN_PROGRESS`, then `REVIEW_PENDING` when paused at a human-in-the-loop gate, and ultimately `COMPLETED`. `FAILED` and `CANCELLED` are terminal alternatives.
**When `status` is `REVIEW_PENDING`**, the value of `current_hitl_gate` identifies the active gate. Gate approval is performed in the [CommerceOS](https://commerceos.fabric.inc) web application — direct the assigned reviewer to CommerceOS to evaluate and approve the gate. Once the reviewer acts, the workflow resumes and subsequent polls reflect the new state.
'
operationId: getOptimizeWorkflowStatus
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/DomainHeader'
- name: workflow_id
in: path
required: true
description: Workflow identifier returned by `POST /v2/optimize/workflows`.
schema:
type: string
example: 9349773c-27fe-4d4f-a093-a5793dff8702
responses:
'200':
description: Workflow state
content:
application/json:
schema:
$ref: '#/components/schemas/OptimizeWorkflowResponse'
example:
id: 9349773c-27fe-4d4f-a093-a5793dff8702
brand_id: 691df5949676c8e0b1d7b6b3
type: OPTIMIZE
origin: API
workflow_type: null
status: REVIEW_PENDING
current_step: TAXONOMY_MAP
current_hitl_gate: TAXONOMY_REVIEW
name: Spring 2026 catalog enrichment
tags: []
started_at: '2026-05-15T10:35:12Z'
completed_at: null
last_error: null
retry_count: 0
workflow_metadata: null
progress:
current_phase: taxonomy
current_step: TAXONOMY_MAP
current_gate: TAXONOMY_REVIEW
phases:
validation:
status: COMPLETED
taxonomy:
status: REVIEW_PENDING
enrichment:
status: NOT_STARTED
publish:
status: NOT_STARTED
review_summary:
total_categories: 12
decided_categories: 3
pending_categories: 9
rerunning_categories: 0
rejected_categories: 0
ready_for_publish_categories: 0
published_categories: 0
reviewer_summary:
- reviewer_user_id: user_xyz
name: Alex Reviewer
email: alex@acme.com
first_name: Alex
last_name: Reviewer
category_ids:
- cat_apparel
- cat_outerwear
categories_at_open_gate: 2
current_gate: TAXONOMY_REVIEW
created_by:
id: user_xyz
type: user
name: Integration Bot
email: integration@acme.com
updated_by:
id: user_xyz
type: user
name: Integration Bot
email: integration@acme.com
created_at: '2026-05-15T10:35:00Z'
updated_at: '2026-05-15T10:42:08Z'
'401':
description: Unauthorized. The access token is missing or has expired.
content:
application/json:
schema:
$ref: '#/components/schemas/errorResponse'
'403':
description: Forbidden. The workflow belongs to a different brand.
content:
application/json:
schema:
$ref: '#/components/schemas/errorResponse'
'404':
description: Workflow not found
content:
application/json:
schema:
$ref: '#/components/schemas/errorResponse'
'500':
description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/errorResponse'
tags:
- Optimize
components:
schemas:
WorkflowReviewSummary:
type: object
description: 'Aggregate counts across categories at the current enrichment-side review gate. This summary supports diagnosing which categories are blocking progression. For non-enrichment gates (taxonomy, validation, publish) the counts are typically zero, because those gates are workflow-level rather than per-category.
'
properties:
total_categories:
type: integer
default: 0
decided_categories:
type: integer
default: 0
pending_categories:
type: integer
default: 0
rerunning_categories:
type: integer
default: 0
rejected_categories:
type: integer
default: 0
ready_for_publish_categories:
type: integer
default: 0
published_categories:
type: integer
default: 0
WorkflowProgress:
type: object
description: 'Phase-keyed progress for the workflow, computed at read time. The `phases` object contains one key per phase (`validation`, `taxonomy`, `enrichment`, `publish`), each carrying a phase-specific structure.
'
properties:
current_phase:
type: string
nullable: true
example: taxonomy
current_step:
type: string
nullable: true
example: TAXONOMY_MAP
current_gate:
type: string
nullable: true
example: TAXONOMY_REVIEW
phases:
type: object
additionalProperties: true
description: Phase-keyed progress map. Keys are `validation`, `taxonomy`, `enrichment`, `publish`; each value is a phase-specific progress object.
UploadArtifactRequest:
type: object
required:
- file
properties:
file:
type: string
format: binary
description: The catalog file to upload. The file must be a CSV.
kind:
allOf:
- $ref: '#/components/schemas/ArtifactKind'
nullable: true
description: Optional. When omitted, the server infers the kind from the filename extension or content type. The supported value is `csv`.
OptimizeWorkflowResponse:
type: object
required:
- id
- brand_id
- status
- created_at
- updated_at
description: 'Workflow state envelope returned by `POST /v2/optimize/workflows` and `GET /v2/optimize/workflows/{workflow_id}`. The `status` value progresses through `PENDING`, then `RUNNING` or `IN_PROGRESS`, then `REVIEW_PENDING`, and ultimately `COMPLETED`. `FAILED` and `CANCELLED` are terminal alternatives.
'
properties:
id:
type: string
description: Workflow identifier. Use this value to poll for status and to construct deep links into the Commerce OS UI.
example: 9349773c-27fe-4d4f-a093-a5793dff8702
brand_id:
type: string
example: 691df5949676c8e0b1d7b6b3
type:
type: string
nullable: true
example: OPTIMIZE
origin:
type: string
nullable: true
enum:
- COMMERCEOS
- API
example: API
workflow_type:
type: string
nullable: true
example: null
status:
type: string
description: Current lifecycle state.
enum:
- PENDING
- RUNNING
- IN_PROGRESS
- REVIEW_PENDING
- COMPLETED
- FAILED
- CANCELLED
example: REVIEW_PENDING
current_step:
type: string
nullable: true
description: 'Current step in the workflow. One of `VALIDATE` / `VALIDATION`, `TAXONOMY_MAP` / `TAXONOMY`, `ENRICH` / `ENRICHMENT`, or `PUBLISH` / `PUBLISHED`.
'
example: TAXONOMY_MAP
current_hitl_gate:
type: string
nullable: true
description: 'Active human-in-the-loop review gate. Populated when `status` is `REVIEW_PENDING`. One of `VALIDATION_REVIEW`, `TAXONOMY_REVIEW`, `SAMPLE_REVIEW`, `ENRICHMENT_SAMPLE_REVIEW`, `FULL_ENRICHMENT_REVIEW`, `ENRICHMENT_FULL_REVIEW`, or `PUBLISH_APPROVAL`.
'
example: TAXONOMY_REVIEW
name:
type: string
nullable: true
example: Spring 2026 catalog enrichment
tags:
type: array
items: {}
example: []
started_at:
type: string
format: date-time
nullable: true
example: '2026-05-15T10:35:12Z'
completed_at:
type: string
format: date-time
nullable: true
example: null
last_error:
type: string
nullable: true
description: Most recent error message. Populated when `status` is `FAILED`.
example: null
retry_count:
type: integer
default: 0
example: 0
workflow_metadata:
type: object
nullable: true
additionalProperties: true
progress:
allOf:
- $ref: '#/components/schemas/WorkflowProgress'
nullable: true
review_summary:
$ref: '#/components/schemas/WorkflowReviewSummary'
reviewer_summary:
type: array
items:
$ref: '#/components/schemas/WorkflowReviewerSummaryResponse'
created_by:
allOf:
- $ref: '#/components/schemas/AuditPrincipal'
nullable: true
updated_by:
allOf:
- $ref: '#/components/schemas/AuditPrincipal'
nullable: true
created_at:
type: string
format: date-time
example: '2026-05-15T10:35:00Z'
updated_at:
type: string
format: date-time
example: '2026-05-15T10:42:08Z'
WorkflowReviewerSummaryResponse:
type: object
required:
- reviewer_user_id
description: Per-reviewer summary included in the workflow response. The `name` and `email` fields are resolved from `auth_users` at read time.
properties:
reviewer_user_id:
type: string
example: user_xyz
name:
type: string
nullable: true
example: Alex Reviewer
email:
type: string
nullable: true
example: alex@acme.com
first_name:
type: string
nullable: true
example: Alex
last_name:
type: string
nullable: true
example: Reviewer
category_ids:
type: array
items:
type: string
example:
- cat_apparel
- cat_outerwear
categories_at_open_gate:
type: integer
default: 0
example: 2
current_gate:
type: string
nullable: true
example: TAXONOMY_REVIEW
ArtifactSource:
type: string
enum:
- upload
- presigned
- uri
- generated
description: 'Indicates how the artifact was ingested. `upload` denotes a direct multipart upload, `presigned` denotes the presigned-URL flow used for large files, `uri` denotes a server-side fetch from an external URI, and `generated` denotes a system-produced artifact.
'
ArtifactKind:
type: string
enum:
- csv
description: Artifact file format. The supported value is `csv`.
CreateWorkflowRequest:
type: object
required:
- input
description: Request body for creating an optimization workflow. Customer integrations should set `origin` to `API`. Supervised review gating is applied automatically.
properties:
input:
$ref: '#/components/schemas/WorkflowInput'
name:
type: string
nullable: true
description: Human-readable name displayed in the Commerce OS UI.
example: Spring 2026 catalog enrichment
tags:
type: array
nullable: true
items:
type: string
example: []
origin:
type: string
nullable: true
enum:
- COMMERCEOS
- API
default: API
description: Set to `API` for customer integrations. Defaults to `API` when omitted.
metadata:
type: object
nullable: true
additionalProperties: true
description: Arbitrary JSON object stored on the workflow for caller use.
AuditPrincipal:
type: object
required:
- id
- type
description: 'Resolved reference for the `created_by` and `updated_by` audit fields. A `type` of `unknown` is returned when the referenced identifier can no longer be resolved (for example, when a user has been hard-deleted).
'
properties:
id:
type: string
description: Either `auth_users.id` or `auth_service_clients.client_id`.
example: user_xyz
type:
type: string
enum:
- user
- service
- unknown
description: 'Indicates the principal type: `user` for end-user actors, `service` for machine clients, and `unknown` when the principal cannot be resolved.'
name:
type: string
nullable: true
description: Display name. Null when `type` is `unknown`.
example: Alex Reviewer
email:
type: string
nullable: true
description: Email address. Null when `type` is `service` or `unknown`.
example: alex@acme.com
ValidationError:
type: object
required:
- loc
- msg
- type
properties:
loc:
type: array
items:
oneOf:
- type: string
- type: integer
msg:
type: string
type:
type: string
WorkflowInput:
type: object
required:
- artifact
description: Specifies the source of the workflow's input data. Provide `artifact.artifact_id` from a prior call to `POST /v2/optimize/artifacts`.
properties:
artifact:
$ref: '#/components/schemas/ArtifactInput'
ArtifactReadResponse:
type: object
required:
- artifact_id
- kind
- source
- content_type
- uri
- brand_id
- created_at
- download_url
- download_url_expires_at
description: Artifact metadata plus a short-lived signed URL for downloading the original file contents.
properties:
artifact_id:
type: string
example: art_95c650ded4824dc79bb6df16427e4a10
kind:
$ref: '#/components/schemas/ArtifactKind'
source:
$ref: '#/components/schemas/ArtifactSource'
bytes:
type: integer
nullable: true
example: 45678
sha256:
type: string
nullable: true
example: 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08
content_type:
type: string
example: text/csv
uri:
type: string
example: s3://product-agent-data-prod-ue2/optimize-artifacts/svc_yourClientId/art_95c650ded4824dc79bb6df16427e4a10/catalog.csv
original_filename:
type: string
nullable: true
example: catalog.csv
brand_id:
type: string
example: 691df5949676c8e0b1d7b6b3
created_at:
type: string
format: date-time
example: '2026-05-15T10:30:00Z'
download_url:
type: string
description: Short-lived presigned URL for downloading the original file contents. The URL is valid until `download_url_expires_at`.
example: https://product-agent-data-prod-ue2.s3.amazonaws.com/optimize-artifacts/svc_yourClientId/art_95c650ded4824dc79bb6df16427e4a10/catalog.csv?X-Amz-Signature=...
download_url_expires_at:
type: string
format: date-time
description: Expiry timestamp in UTC for `download_url`. After this time, call `GET /v2/optimize/artifacts/{artifact_id}` again to obtain a new URL.
example: '2026-05-15T10:45:00Z'
ArtifactResponse:
type: object
required:
- artifact_id
- kind
- source
- content_type
- uri
- brand_id
- created_at
properties:
artifact_id:
type: string
description: Stable identifier for the artifact. Reference this value when creating a workflow.
example: art_95c650ded4824dc79bb6df16427e4a10
kind:
$ref: '#/components/schemas/ArtifactKind'
source:
$ref: '#/components/schemas/ArtifactSource'
bytes:
type: integer
nullable: true
description: File size in bytes.
example: 45678
sha256:
type: string
nullable: true
description: Hex-encoded SHA-256 checksum of the file contents.
example: 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08
content_type:
type: string
description: MIME type as detected by the server.
example: text/csv
uri:
type: string
description: Internal storage URI for the artifact. Informational only.
example: s3://product-agent-data-prod-ue2/optimize-artifacts/svc_yourClientId/art_95c650ded4824dc79bb6df16427e4a10/catalog.csv
original_filename:
type: string
nullable: true
description: The filename submitted with the multipart upload.
example: catalog.csv
brand_id:
type: string
# --- truncated at 32 KB (34 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/fabric-com/refs/heads/main/openapi/fabric-com-optimize-api-openapi.yml