openapi: 3.1.0
info:
  title: PIM Customer API
  version: 1.0.0
  description: |
    Read-only catalog API for authenticated B2B customers and webhook subscription management.

    Webhook payloads are signed with HMAC-SHA256. Verify the `X-Webhook-Signature` header against the raw JSON body using your subscription secret.
servers:
  - url: /api/v1
    description: Customer API v1
security:
  - bearerAuth: []
paths:
  /products:
    get:
      summary: List published products
      operationId: listProducts
      tags: [Products]
      parameters:
        - name: page
          in: query
          schema:
            type: integer
            minimum: 1
            default: 1
        - name: per_page
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
        - name: search
          in: query
          description: Filter by product name or SKU
          schema:
            type: string
        - name: category_id
          in: query
          schema:
            type: integer
        - name: updated_since
          in: query
          description: ISO 8601 timestamp; return products updated on or after this time
          schema:
            type: string
            format: date-time
      responses:
        '200':
          description: Paginated product list
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Product'
                  links:
                    $ref: '#/components/schemas/PaginationLinks'
                  meta:
                    $ref: '#/components/schemas/PaginationMeta'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /products/{product}:
    get:
      summary: Get a product by ID
      operationId: getProduct
      tags: [Products]
      parameters:
        - name: product
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Product details
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/Product'
        '404':
          $ref: '#/components/responses/NotFound'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /products/sku/{sku}:
    get:
      summary: Get a product by SKU
      operationId: getProductBySku
      tags: [Products]
      parameters:
        - name: sku
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Product details
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/Product'
        '404':
          $ref: '#/components/responses/NotFound'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /categories:
    get:
      summary: List categories
      operationId: listCategories
      tags: [Categories]
      responses:
        '200':
          description: Category list
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Category'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /webhooks:
    get:
      summary: List webhook subscriptions
      operationId: listWebhooks
      tags: [Webhooks]
      responses:
        '200':
          description: Webhook subscriptions for the authenticated customer
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/WebhookSubscription'
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      summary: Create a webhook subscription
      operationId: createWebhook
      tags: [Webhooks]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookSubscriptionCreate'
      responses:
        '201':
          description: Created subscription; secret is returned once in the top-level `secret` field
          content:
            application/json:
              schema:
                allOf:
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/WebhookSubscription'
                      secret:
                        type: string
                        description: HMAC signing secret (shown only on create)
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/ValidationError'
  /webhooks/{webhook}:
    put:
      summary: Update a webhook subscription
      operationId: updateWebhook
      tags: [Webhooks]
      parameters:
        - name: webhook
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookSubscriptionUpdate'
      responses:
        '200':
          description: Updated subscription
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/WebhookSubscription'
        '404':
          $ref: '#/components/responses/NotFound'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/ValidationError'
    delete:
      summary: Delete a webhook subscription
      operationId: deleteWebhook
      tags: [Webhooks]
      parameters:
        - name: webhook
          in: path
          required: true
          schema:
            type: integer
      responses:
        '204':
          description: Deleted
        '404':
          $ref: '#/components/responses/NotFound'
        '401':
          $ref: '#/components/responses/Unauthorized'
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: Sanctum
  schemas:
    Product:
      type: object
      properties:
        id:
          type: integer
        sku:
          type: string
        name:
          type: string
        slug:
          type: string
        description:
          type: string
          nullable: true
        base_price:
          type: string
        price:
          type: string
          description: Effective price for the authenticated customer's price list
        stock_quantity:
          type: integer
        category:
          type: object
          nullable: true
          properties:
            id:
              type: integer
            name:
              type: string
            path:
              type: string
              description: Full category path (e.g. "Electronics > Cables")
        updated_at:
          type: string
          format: date-time
          nullable: true
    Category:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        slug:
          type: string
        parent_id:
          type: integer
          nullable: true
        sort_order:
          type: integer
        path:
          type: string
          description: Full category path (e.g. "Electronics > Cables")
    WebhookSubscription:
      type: object
      properties:
        id:
          type: integer
        url:
          type: string
          format: uri
        events:
          type: array
          items:
            type: string
            enum: [product.published, product.updated]
        is_active:
          type: boolean
        created_at:
          type: string
          format: date-time
          nullable: true
        updated_at:
          type: string
          format: date-time
          nullable: true
    WebhookSubscriptionCreate:
      type: object
      required: [url, events]
      properties:
        url:
          type: string
          format: uri
        events:
          type: array
          minItems: 1
          items:
            type: string
            enum: [product.published, product.updated]
        is_active:
          type: boolean
          default: true
    WebhookSubscriptionUpdate:
      type: object
      properties:
        url:
          type: string
          format: uri
        events:
          type: array
          minItems: 1
          items:
            type: string
            enum: [product.published, product.updated]
        is_active:
          type: boolean
    PaginationLinks:
      type: object
    PaginationMeta:
      type: object
  responses:
    Unauthorized:
      description: Missing or invalid bearer token
    NotFound:
      description: Resource not found
    ValidationError:
      description: Validation failed
