> ## Documentation Index
> Fetch the complete documentation index at: https://www.twicecommerce.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Set inventory rules for a catalog item

> Sets the rules that connect a listing to physical inventory — this is what makes it bookable. A catalog item holds no stock itself; without at least one rule whose conditions match real inventory, the listing resolves to zero availability. This replaces the full rule set for the item in one call (array upsert): include a rule/condition `id` to update it, omit the `id` to create.



## OpenAPI

````yaml https://server.twicecommerce.com/api/admin/openapi-mintlify.json put /v1/admin/catalog/{id}/rules
openapi: 3.0.2
info:
  title: TWICE Admin API
  description: "The TWICE Admin API is the merchant-facing API of the Twice platform. It is currently in alpha: endpoints and schemas may change without notice.\n\n## Webhooks\n\nWebhooks notify your systems when resources change in Twice. A webhook subscription pairs one event type with one HTTPS endpoint of yours; whenever a matching event occurs, we POST the event to that endpoint. Subscriptions and their delivery logs are managed in the Twice admin under **Account → Integrations**.\n\n### Event types\n\n- `order.created`\n- `order.deleted`\n- `order.updated`\n\n### Payload\n\nEvery delivery is an HTTP POST with a JSON body sharing a common envelope. The typed payload of each event type is documented in the **Webhooks** section of the sidebar.\n\n```json\n{\n\t\"eventId\": \"5f2eb3a6-6cbd-4a2e-9350-6e0d1e2f9a11\",\n\t\"eventType\": \"order.created\",\n\t\"eventTime\": \"2026-08-06T12:34:56.789Z\",\n\t\"resource\": \"order\",\n\t\"resourceId\": \"0d9e0a7c-3fd1-4c8f-9c0d-2b7c6f7f2a55\",\n\t\"apiVersion\": \"2025-06\",\n\t\"data\": { \"…\": \"the API representation of the resource, or null for deletes\" }\n}\n```\n\n`data` carries the resource in the same shape the REST API returns it, as of the API version in `apiVersion`. Each subscription is pinned to the API version that was the latest when the subscription was created, so a new API version never changes the payload shape you receive — moving to a newer version is an explicit update of the subscription.\n\n### Acknowledging deliveries\n\nRespond with any **2xx** status to acknowledge a delivery. Any other status — or a timeout — counts as a failed attempt. Respond as quickly as possible and do heavy processing asynchronously after acknowledging.\n\n### Delivery semantics\n\nDeliveries are **at-least-once**: the same event can occasionally be delivered more than once, so deduplicate on the `X-Twice-Event-Id` header (or the equal `eventId` body field). Ordering is not guaranteed — when it matters, use `eventTime` or re-fetch the current state of the resource via the API.\n\n### Retries\n\nFailed deliveries are retried up to 3 times (4 attempts in total) with growing backoff — roughly 10 s, 20 s, 40 s after the preceding attempt — giving up 10 minutes after the first attempt. After 3 consecutive events fail all their attempts, the subscription is automatically disabled (`disabledReason: TOO_MANY_FAILED_DELIVERY_ATTEMPTS`) and must be re-enabled manually in the admin. Individual deliveries can also be redelivered manually from the delivery log.\n\n### Verifying signatures\n\nEach subscription has a signing secret (prefixed `whsec_`), available in the admin. Deliveries carry an HMAC-SHA256 signature of the exact raw request body in the `X-Twice-Signature` header, formatted `sha256=<hex>`. Verify it against the raw body bytes — parse the JSON only after the signature checks out:\n\n```js\nimport { createHmac, timingSafeEqual } from 'node:crypto';\n\nconst expected = 'sha256=' + createHmac('sha256', secret).update(rawBody, 'utf8').digest('hex');\nconst signature = req.headers['x-twice-signature'];\nconst isValid =\n\ttypeof signature === 'string' &&\n\tsignature.length === expected.length &&\n\ttimingSafeEqual(Buffer.from(signature), Buffer.from(expected));\n```"
  version: 2025-06
servers:
  - url: https://server.twicecommerce.com
security:
  - ApiKeyAuth: []
paths:
  /v1/admin/catalog/{id}/rules:
    put:
      tags:
        - catalog
      summary: Set inventory rules for a catalog item
      description: >-
        Sets the rules that connect a listing to physical inventory — this is
        what makes it bookable. A catalog item holds no stock itself; without at
        least one rule whose conditions match real inventory, the listing
        resolves to zero availability. This replaces the full rule set for the
        item in one call (array upsert): include a rule/condition `id` to update
        it, omit the `id` to create.
      operationId: admin.catalog.upsertRules
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      requestBody:
        description: Body
        content:
          application/json:
            schema:
              type: object
              properties:
                id:
                  type: string
                label:
                  type: string
                conditions:
                  type: object
                  properties:
                    id:
                      type: string
                    label:
                      type: string
                    filters:
                      nullable: true
                      type: object
                      properties:
                        attributeId:
                          type: string
                        key:
                          type: string
                          enum:
                            - attribute
                            - item_code
                            - sku_code
                            - item_name
                            - sku_name
                        operator:
                          type: string
                          enum:
                            - startsWith
                            - endsWith
                            - contains
                            - doesNotContain
                            - eq
                            - ne
                            - gt
                            - gte
                            - lt
                            - lte
                            - inArray
                            - notInArray
                            - between
                            - notBetween
                            - isEmpty
                            - isNotEmpty
                        values:
                          type: array
                          items:
                            anyOf:
                              - type: string
                              - type: number
                              - type: boolean
                      required:
                        - key
                        - operator
                        - values
                    quantity:
                      type: number
                  required:
                    - label
                    - filters
                    - quantity
                quantity:
                  type: number
                isVisible:
                  type: boolean
                variantRules:
                  type: object
                  properties:
                    id:
                      type: string
                    variantValueId:
                      type: string
                    baseRuleId:
                      type: string
                    conditions:
                      type: object
                      properties:
                        id:
                          type: string
                        label:
                          type: string
                        filters:
                          nullable: true
                          type: object
                          properties:
                            attributeId:
                              type: string
                            key:
                              type: string
                              enum:
                                - attribute
                                - item_code
                                - sku_code
                                - item_name
                                - sku_name
                            operator:
                              type: string
                              enum:
                                - startsWith
                                - endsWith
                                - contains
                                - doesNotContain
                                - eq
                                - ne
                                - gt
                                - gte
                                - lt
                                - lte
                                - inArray
                                - notInArray
                                - between
                                - notBetween
                                - isEmpty
                                - isNotEmpty
                            values:
                              type: array
                              items:
                                anyOf:
                                  - type: string
                                  - type: number
                                  - type: boolean
                          required:
                            - key
                            - operator
                            - values
                        quantity:
                          type: number
                        createdAt:
                          type: string
                          format: date-time
                          pattern: >-
                            ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z))$
                      required:
                        - id
                        - label
                        - filters
                        - quantity
                        - createdAt
                    quantity:
                      type: number
                    createdAt:
                      type: string
                      format: date-time
                      pattern: >-
                        ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z))$
                  required:
                    - id
                    - variantValueId
                    - baseRuleId
                    - conditions
                    - quantity
                    - createdAt
                revenueSplitRate:
                  nullable: true
                  type: number
              required:
                - label
                - conditions
                - quantity
                - isVisible
      responses:
        '200':
          description: '200'
          content:
            application/json:
              schema:
                type: boolean
        '400':
          description: '400'
        '401':
          description: '401'
        '403':
          description: '403'
        '404':
          description: '404'
        '429':
          description: '429'
        '500':
          description: '500'
components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      name: X-API-KEY
      in: header
      description: API key for the Twice API

````