openapi: 3.1.0
info:
  title: CartBridge API
  version: 0.1.0
  summary: AI checkout control, readiness, fallback, and native Shopify cart API for merchants and approved agents.
servers:
  - url: https://cartbridge.ai
security:
  - agentBearer: []
paths:
  /admin/readiness.json:
    get:
      summary: Read the merchant AI checkout readiness report
      description: Admin-authenticated report covering store connection, reconciliation, agent controls, checkout paths, product-risk scan state, blockers, warnings, and recommended next actions.
      security: []
      responses:
        '200':
          description: AI checkout readiness report
          content:
            application/json:
              schema:
                type: object
                properties:
                  readiness:
                    $ref: '#/components/schemas/ReadinessReport'
  /admin/readiness/scan:
    post:
      summary: Run an advisory AI checkout product-risk scan
      description: Admin-authenticated dashboard action. Samples Storefront products and stores advisory risk signals; it does not block checkout-link fallback.
      security: []
      requestBody:
        required: false
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              properties:
                shop:
                  type: string
                query:
                  type: string
                  default: a
                sampleSize:
                  type: integer
                  minimum: 1
                  maximum: 25
      responses:
        '200':
          description: Dashboard refresh with latest scan result
  /v1/shopify/products/search:
    get:
      summary: Search a merchant's Shopify catalog for buyable products and variants
      parameters:
        - $ref: '#/components/parameters/BuyerIp'
        - $ref: '#/components/parameters/ShopQuery'
        - name: q
          in: query
          required: true
          schema:
            type: string
        - name: country
          in: query
          required: false
          schema:
            type: string
            minLength: 2
            maxLength: 2
        - name: first
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 25
            default: 10
        - name: after
          in: query
          required: false
          schema:
            type: string
        - name: availableOnly
          in: query
          required: false
          schema:
            type: boolean
            default: true
      responses:
        '200':
          description: Product search results with normalized buyable variants
          content:
            application/json:
              schema:
                type: object
                properties:
                  products:
                    type: array
                    items:
                      $ref: '#/components/schemas/ProductResult'
                  pageInfo:
                    type: object
                    additionalProperties: true
  /v1/shopify/products/by-handle/{handle}:
    get:
      summary: Fetch one product by Shopify handle
      parameters:
        - $ref: '#/components/parameters/BuyerIp'
        - $ref: '#/components/parameters/ShopQuery'
        - name: handle
          in: path
          required: true
          schema:
            type: string
        - name: country
          in: query
          required: false
          schema:
            type: string
            minLength: 2
            maxLength: 2
      responses:
        '200':
          description: Product result
          content:
            application/json:
              schema:
                type: object
                properties:
                  product:
                    $ref: '#/components/schemas/ProductResult'
  /v1/shopify/ucp/discovery:
    get:
      summary: Probe a Shopify shop for UCP Checkout MCP and Shop Pay handler availability
      parameters:
        - $ref: '#/components/parameters/ShopQuery'
      responses:
        '200':
          description: Non-mutating UCP discovery result
          content:
            application/json:
              schema:
                type: object
                properties:
                  shop:
                    type: string
                  agentAuth:
                    type: object
                    additionalProperties: true
                  businessProfile:
                    type: object
                    additionalProperties: true
                  checkoutMcp:
                    type: object
                    additionalProperties: true
                  shopPay:
                    type: object
                    properties:
                      possible:
                        type: boolean
                      handlerId:
                        type: string
                      discovery:
                        type:
                          - string
                          - 'null'
                      nextStep:
                        type: string
  /v1/shopify/ucp/checkouts:
    post:
      summary: Try to convert an approved CartBridge cart into a Shopify UCP checkout session
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [cartId, quoteId, approval]
              properties:
                cartId:
                  type: string
                quoteId:
                  type: string
                approval:
                  type: object
                  additionalProperties: true
                buyer:
                  type: object
                  additionalProperties: true
                currency:
                  type: string
      responses:
        '200':
          description: Checkout MCP accepted the create_checkout call
        '424':
          description: Checkout MCP was unreachable, blocked, or returned an error
  /v1/shopify/variants/lookup:
    get:
      summary: Resolve a Shopify ProductVariant ID into current buyability and cart line metadata
      parameters:
        - $ref: '#/components/parameters/BuyerIp'
        - $ref: '#/components/parameters/ShopQuery'
        - name: id
          in: query
          required: true
          schema:
            type: string
        - name: country
          in: query
          required: false
          schema:
            type: string
            minLength: 2
            maxLength: 2
      responses:
        '200':
          description: Variant result
          content:
            application/json:
              schema:
                type: object
                properties:
                  variant:
                    $ref: '#/components/schemas/VariantResult'
  /v1/shopify/carts:
    post:
      summary: Create a native Shopify cart and signed quote
      parameters:
        - $ref: '#/components/parameters/BuyerIp'
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateCartRequest'
      responses:
        '201':
          description: Cart and quote created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateCartResponse'
        '200':
          description: Idempotent replay of a previous create-cart response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateCartResponse'
        '429':
          $ref: '#/components/responses/RateLimited'
  /v1/shopify/carts/{cartId}:
    get:
      summary: Read adapter cart status, latest quote, and linked Shopify orders
      parameters:
        - $ref: '#/components/parameters/CartId'
      responses:
        '200':
          description: Cart status
          content:
            application/json:
              schema:
                type: object
                properties:
                  cart:
                    type: object
                    additionalProperties: true
                  latestQuote:
                    type: object
                    additionalProperties: true
                  latestOrder:
                    type: object
                    additionalProperties: true
                  lifecycle:
                    type: object
                    additionalProperties: true
                  purchaseResult:
                    $ref: '#/components/schemas/PurchaseResult'
                  orders:
                    type: array
                    items:
                      type: object
                      additionalProperties: true
  /v1/shopify/carts/{cartId}/items:
    post:
      summary: Add line items to an existing native Shopify cart
      parameters:
        - $ref: '#/components/parameters/CartId'
        - $ref: '#/components/parameters/BuyerIp'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [lines]
              properties:
                lines:
                  type: array
                  items:
                    $ref: '#/components/schemas/CartLineInput'
      responses:
        '200':
          description: Cart updated and requoted
  /v1/shopify/carts/{cartId}/purchase-result:
    get:
      summary: Read the LLM-ready purchase result for a cart
      description: Returns the current buyer-facing state after quote, checkout handoff, or Shopify order webhook sync.
      parameters:
        - $ref: '#/components/parameters/CartId'
      responses:
        '200':
          description: Purchase result
          content:
            application/json:
              schema:
                type: object
                properties:
                  purchaseResult:
                    $ref: '#/components/schemas/PurchaseResult'
                  lifecycle:
                    type: object
                    additionalProperties: true
                  latestOrder:
                    type: object
                    additionalProperties: true
  /v1/shopify/carts/{cartId}/quote:
    post:
      summary: Refresh a signed quote from live Shopify cart state
      parameters:
        - $ref: '#/components/parameters/CartId'
        - $ref: '#/components/parameters/BuyerIp'
      responses:
        '200':
          description: Quote refreshed
  /v1/shopify/carts/{cartId}/checkout-session:
    post:
      summary: Approve a quote and return the native Shopify checkout URL
      parameters:
        - $ref: '#/components/parameters/CartId'
        - $ref: '#/components/parameters/BuyerIp'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [quoteId]
              properties:
                quoteId:
                  type: string
                approval:
                  type: object
                  additionalProperties: true
      responses:
        '200':
          description: Checkout handoff approved
          content:
            application/json:
              schema:
                type: object
                properties:
                  checkoutUrl:
                    type: string
                    format: uri
                  quoteId:
                    type: string
  /v1/shopify/orders/{orderId}:
    get:
      summary: Look up a Shopify order for reconciliation
      parameters:
        - name: orderId
          in: path
          required: true
          schema:
            type: string
        - name: shop
          in: query
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Order lookup result
components:
  responses:
    RateLimited:
      description: Agent API rate limit exceeded. Retry with backoff.
      content:
        application/json:
          schema:
            type: object
            properties:
              error:
                type: object
                properties:
                  code:
                    const: rate_limited
                  message:
                    type: string
                  details:
                    type: object
                    properties:
                      retryAfterSeconds:
                        type: integer
                      limit:
                        type: integer
                      windowMs:
                        type: integer
              requestId:
                type: string
  securitySchemes:
    agentBearer:
      type: http
      scheme: bearer
  parameters:
    BuyerIp:
      name: X-Buyer-IP
      in: header
      required: true
      schema:
        type: string
      description: Original buyer IP required for server-side Shopify Storefront calls.
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: false
      schema:
        type: string
      description: Stable retry key for cart creation.
    ShopQuery:
      name: shop
      in: query
      required: true
      schema:
        type: string
      description: Installed merchant myshopify.com domain. Omit only when using a merchant-bound agent key.
    CartId:
      name: cartId
      in: path
      required: true
      schema:
        type: string
  schemas:
    CreateCartRequest:
      type: object
      required: [shop, userAuthority, lines]
      properties:
        shop:
          type: string
          examples: [example.myshopify.com]
        userRequest:
          type: string
        agentIntent:
          type: object
          additionalProperties: true
        agentId:
          type: string
        agentSessionId:
          type: string
        userAuthority:
          $ref: '#/components/schemas/UserAuthority'
        buyerIdentity:
          type: object
          additionalProperties: true
        discountCodes:
          type: array
          items:
            type: string
        lines:
          type: array
          items:
            $ref: '#/components/schemas/CartLineInput'
    CartLineInput:
      type: object
      required: [merchandiseId]
      properties:
        merchandiseId:
          type: string
          examples: [gid://shopify/ProductVariant/123]
        quantity:
          type: integer
          minimum: 1
          default: 1
        agentReason:
          type: string
        productType:
          type: string
    ProductResult:
      type: object
      properties:
        id:
          type: string
        title:
          type: string
        handle:
          type: string
        description:
          type: string
        productType:
          type: string
        vendor:
          type: string
        availableForSale:
          type: boolean
        featuredImage:
          $ref: '#/components/schemas/Image'
        priceRange:
          type: object
          additionalProperties: true
        variants:
          type: array
          items:
            $ref: '#/components/schemas/VariantResult'
        buyableVariants:
          type: array
          items:
            $ref: '#/components/schemas/VariantResult'
        defaultVariant:
          $ref: '#/components/schemas/VariantResult'
    VariantResult:
      type: object
      properties:
        merchandiseId:
          type: string
        id:
          type: string
        title:
          type: string
        sku:
          type: string
        availableForSale:
          type: boolean
        quantityAvailable:
          type: integer
          nullable: true
        currentlyNotInStock:
          type: boolean
        requiresShipping:
          type: boolean
        selectedOptions:
          type: array
          items:
            type: object
            additionalProperties: true
        price:
          type: object
          additionalProperties: true
        compareAtPrice:
          type: object
          additionalProperties: true
          nullable: true
        image:
          $ref: '#/components/schemas/Image'
        product:
          type: object
          additionalProperties: true
        cartLine:
          $ref: '#/components/schemas/CartLineInput'
    Image:
      type: object
      properties:
        url:
          type: string
          format: uri
        altText:
          type: string
    UserAuthority:
      type: object
      required: [id]
      properties:
        id:
          type: string
        approvalRequired:
          type: boolean
        maxTotal:
          type: number
        allowedShops:
          type: array
          items:
            type: string
    CreateCartResponse:
      type: object
      properties:
        cart:
          type: object
          additionalProperties: true
        quote:
          type: object
          additionalProperties: true
        checkoutUrl:
          type: string
          format: uri
        idempotentReplay:
          type: boolean
    PurchaseResult:
      type: object
      properties:
        state:
          type: string
        nextAction:
          type: string
        checkoutPath:
          $ref: '#/components/schemas/CheckoutPathDecision'
        confirmation:
          type:
            - object
            - 'null'
          additionalProperties: true
        purchase:
          type: object
          additionalProperties: true
        checkoutUrl:
          type:
            - string
            - 'null'
          format: uri
    CheckoutPathDecision:
      type: object
      properties:
        mode:
          type: string
          enum: [shopify_checkout_url, ucp_checkout]
        reason:
          type: string
        fallbackAvailable:
          type: boolean
    ReadinessReport:
      type: object
      properties:
        shop:
          type:
            - string
            - 'null'
        status:
          type: string
          enum: [Ready, Needs attention, Blocked]
        groups:
          type: array
          items:
            type: object
            additionalProperties: true
        blockers:
          type: array
          items:
            type: object
            additionalProperties: true
        warnings:
          type: array
          items:
            type: object
            additionalProperties: true
        recommendedNextActions:
          type: array
          items:
            type: object
            additionalProperties: true
        checkoutFallbackReady:
          type: boolean
        directCheckoutPossible:
          type: boolean
        checkoutPathDecision:
          $ref: '#/components/schemas/CheckoutPathDecision'
        latestScan:
          type:
            - object
            - 'null'
          additionalProperties: true
