openapi: 3.0.3
info:
  title: MINTSHUB API
  version: 1.3.1
  description: Owner-scoped API for ready export items and idempotent external sale notifications.
  license:
    name: MIT
    url: https://opensource.org/license/mit
servers:
  - url: https://api.mintshub.com/v1
security:
  - ApiKey: []
paths:
  /health:
    get:
      operationId: healthCheck
      security: []
      summary: Service health
      responses:
        "200":
          description: Healthy
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Success"
        "429":
          $ref: "#/components/responses/TooManyRequests"
  /sync/prestashop/schema:
    post:
      operationId: readPrestashopSchema
      security: []
      summary: Read PrestaShop categories, features and shared feature values
      description: >
        Used by the sale module. Sends the shop domain and webservice key to
        this server, which reads categories, product features and their shared
        values from that PrestaShop shop. The key is not stored. Not an
        export-items route. Each item in data.features has id, name and values
        (id and name of a shared feature value).
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [base_url, ws_key]
              properties:
                base_url:
                  type: string
                  example: https://skupkamonet.com.ua
                ws_key:
                  type: string
      responses:
        "200":
          description: Shop categories and features
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Success"
        "400":
          $ref: "#/components/responses/BadRequest"
        "429":
          $ref: "#/components/responses/TooManyRequests"
  /export/items:
    get:
      operationId: listExportItems
      summary: List ready export items owned by this API key
      parameters:
        - $ref: "#/components/parameters/Lang"
        - $ref: "#/components/parameters/Cursor"
        - $ref: "#/components/parameters/Limit"
        - name: updated_after
          in: query
          schema:
            type: string
            format: date-time
        - name: status
          in: query
          schema:
            type: string
            enum: [active, inactive]
      responses:
        "200":
          description: Export items
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ExportItemList"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
  /export/items/{item_id}:
    get:
      operationId: getExportItem
      summary: Get one owned export item
      parameters:
        - name: item_id
          in: path
          required: true
          schema:
            type: string
        - $ref: "#/components/parameters/Lang"
      responses:
        "200":
          description: Export item
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/Success"
                  - type: object
                    properties:
                      data:
                        $ref: "#/components/schemas/ExportItem"
        "404":
          $ref: "#/components/responses/NotFound"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
  /export/items/{item_id}/sales/confirm:
    post:
      operationId: confirmExportItemSale
      summary: Confirm an external sale
      description: Requires a platform-bound key with sales:write. The item becomes inactive for every export.
      parameters:
        - $ref: "#/components/parameters/ItemId"
        - $ref: "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SaleWriteRequest"
      responses:
        "200":
          description: Sale confirmed or safely replayed
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SaleWriteResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "409":
          $ref: "#/components/responses/Conflict"
  /export/items/{item_id}/sales/cancel:
    post:
      operationId: cancelExportItemSale
      summary: Cancel an external sale
      description: Only the platform and external order that confirmed the sale can restore the item.
      parameters:
        - $ref: "#/components/parameters/ItemId"
        - $ref: "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SaleWriteRequest"
      responses:
        "200":
          description: Sale canceled or safely replayed
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SaleWriteResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "409":
          $ref: "#/components/responses/Conflict"
components:
  securitySchemes:
    ApiKey:
      type: apiKey
      in: header
      name: X-API-Key
      description: Owner-scoped server-side key. Read keys use export:read; write keys use sales:write and are platform-bound.
  parameters:
    Lang:
      name: lang
      in: query
      schema:
        type: string
        enum: [RUS, UKR, ENG]
        default: ENG
    Cursor:
      name: cursor
      in: query
      schema:
        type: string
    Limit:
      name: limit
      in: query
      schema:
        type: integer
        minimum: 1
        maximum: 100
        default: 25
    ItemId:
      name: item_id
      in: path
      required: true
      schema:
        type: string
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: true
      description: Unique key for this platform operation. Reuse it only to retry the identical request.
      schema:
        type: string
        minLength: 1
        maxLength: 128
  responses:
    BadRequest:
      description: Invalid request body or missing idempotency key
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    Unauthorized:
      description: Missing or invalid API key
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    Forbidden:
      description: API key does not have the required scope
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    Conflict:
      description: Item already sold, idempotency conflict or sale cannot be canceled
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    TooManyRequests:
      description: Rate limit exceeded
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
  schemas:
    Success:
      type: object
      required: [data, meta]
      properties:
        data: {}
        meta:
          $ref: "#/components/schemas/Meta"
    Error:
      type: object
      required: [error, meta]
      properties:
        error:
          type: object
          required: [code, message]
          properties:
            code:
              type: string
            message:
              type: string
        meta:
          $ref: "#/components/schemas/Meta"
    Meta:
      type: object
      required: [request_id]
      properties:
        request_id:
          type: string
        next_cursor:
          type: string
          nullable: true
    Image:
      type: object
      required: [id, url, position, type]
      properties:
        id:
          type: string
        url:
          type: string
          format: uri
        position:
          type: integer
        type:
          type: string
          enum: [obverse, reverse, edge, gallery]
    ExportItem:
      type: object
      required: [id, status, title, currency, stock_quantity, images, characteristics, updated_at]
      properties:
        id:
          type: string
        coin_id:
          type: string
          nullable: true
        status:
          type: string
          enum: [active, inactive]
        title:
          type: string
        description:
          type: string
        price:
          type: number
          nullable: true
        currency:
          type: string
        stock_quantity:
          type: integer
        category:
          type: object
          nullable: true
        characteristics:
          type: object
          additionalProperties: true
        images:
          type: array
          items:
            $ref: "#/components/schemas/Image"
        updated_at:
          type: string
          format: date-time
    SaleWriteRequest:
      type: object
      additionalProperties: false
      required: [external_order_id]
      properties:
        external_order_id:
          type: string
          minLength: 1
          maxLength: 128
        quantity:
          type: integer
          enum: [1]
          default: 1
    SaleWriteResult:
      type: object
      required:
        [item_id, status, stock_quantity, platform_id, external_order_id, idempotent_replay]
      properties:
        item_id:
          type: string
        status:
          type: string
          enum: [active, inactive]
        stock_quantity:
          type: integer
          enum: [0, 1]
        platform_id:
          type: string
        external_order_id:
          type: string
        confirmed_at:
          type: string
          format: date-time
        canceled_at:
          type: string
          format: date-time
        idempotent_replay:
          type: boolean
    SaleWriteResponse:
      allOf:
        - $ref: "#/components/schemas/Success"
        - type: object
          properties:
            data:
              $ref: "#/components/schemas/SaleWriteResult"
    ExportItemList:
      allOf:
        - $ref: "#/components/schemas/Success"
        - type: object
          properties:
            data:
              type: array
              items:
                $ref: "#/components/schemas/ExportItem"
