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.

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.` | No | Custom attribute value. Free-form string, single value per cell. The `` 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 description: The brand the artifact is associated with, derived from the `domain` header. example: 691df5949676c8e0b1d7b6b3 created_at: type: string format: date-time description: Upload timestamp in UTC. example: '2026-05-15T10:30:00Z' ArtifactInput: type: object required: - artifact_id properties: artifact_id: type: string description: Identifier returned by `POST /v2/optimize/artifacts`. example: art_95c650ded4824dc79bb6df16427e4a10 errorResponse: description: Error response properties: errors: description: Errors items: $ref: '#/components/schemas/errorResponse' type: array message: description: Error message example: Bad request type: string type: description: Error type example: CLIENT_ERROR type: string type: object HTTPValidationError: type: object description: Validation error response body returned with HTTP 422. properties: detail: type: array items: $ref: '#/components/schemas/ValidationError' parameters: DomainHeader: name: domain in: header required: true schema: type: string example: vessel.com description: The brand domain name (for example, `vessel.com` or `containerstore.com`) used to scope the request to a specific brand's data and configuration. The authenticated principal must be authorized for the specified brand. securitySchemes: bearerAuth: type: http scheme: bearer bearerFormat: JWT description: 'This is the authorization token used to authenticate the request. You must pass the access token generated from the system app. For more information, see the [Making your first API request](/v3/api-reference/getting-started/getting-started-with-fabric-apis#procedure) section. '