openapi: 3.1.0
info:
  title: Baltaji Al-Ezz Gold & Metals API
  version: 1.0.0
  description: واجهة تكامل مؤسسية للمخزون والأسعار والمتجر والأجهزة مع رموز محددة الصلاحيات وWebhooks موقعة.
servers:
  - url: /api/v1
security:
  - bearerAuth: []
paths:
  /organizations/{organization}/catalog:
    get:
      security: []
      summary: Public synchronized catalog
      parameters:
        - $ref: '#/components/parameters/Organization'
        - name: per_page
          in: query
          schema: {type: integer, minimum: 1, maximum: 100}
      responses:
        '200': {description: Published pieces without internal costs}
  /inventory/{serial}:
    get:
      summary: Lookup a unique piece by serial, barcode, or RFID
      description: Requires inventory.read. Costs require inventory.cost.read separately.
      parameters:
        - name: serial
          in: path
          required: true
          schema: {type: string}
      responses:
        '200': {description: Tenant-scoped piece snapshot}
        '401': {$ref: '#/components/responses/Unauthorized'}
        '403': {$ref: '#/components/responses/Forbidden'}
        '404': {description: Piece not found in token organization}
  /prices:
    get:
      summary: Historical metal prices
      description: Requires prices.read.
      responses:
        '200': {description: Paginated prices}
  /branches:
    get:
      summary: Paginated organization branches
      description: Requires organization.read.
      responses:
        '200': {description: Tenant-scoped branch list with warehouse counts}
  /warehouses:
    get:
      summary: Paginated warehouses
      description: Requires organization.read. Supports branch_uuid filtering.
      parameters:
        - {name: branch_uuid, in: query, schema: {type: string, format: uuid}}
      responses:
        '200': {description: Warehouses with branch and piece count}
  /inventory:
    get:
      summary: Search and synchronize inventory
      description: Requires inventory.read. Supports incremental synchronization.
      parameters:
        - {name: status, in: query, schema: {type: string}}
        - {name: warehouse_uuid, in: query, schema: {type: string, format: uuid}}
        - {name: updated_since, in: query, schema: {type: string, format: date-time}}
        - {name: q, in: query, schema: {type: string}}
      responses:
        '200': {description: Paginated inventory snapshots without internal costs}
  /parties:
    get:
      summary: Customers, suppliers and workshops
      description: Requires parties.read.
      parameters:
        - {name: type, in: query, schema: {enum: [customer, supplier, both, workshop]}}
        - {name: q, in: query, schema: {type: string}}
        - {name: updated_since, in: query, schema: {type: string, format: date-time}}
      responses:
        '200': {description: Paginated tenant-scoped parties}
  /parties/{code}:
    put:
      summary: Idempotently create or update a party by code
      description: Requires parties.write. Repeating the same code updates the same record.
      parameters:
        - {name: code, in: path, required: true, schema: {type: string, maxLength: 60}}
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [party_type, legal_type, name_ar]
              properties:
                party_type: {enum: [customer, supplier, both, workshop]}
                legal_type: {enum: [individual, company]}
                name_ar: {type: string}
                name_en: {type: string}
                mobile: {type: string}
                email: {type: string, format: email}
      responses:
        '201': {description: Party created}
        '200': {description: Existing party updated}
  /sales:
    get:
      summary: Paginated sales invoices
      description: Requires sales.read.
      responses:
        '200': {description: Sales invoices with party, location and items}
  /purchases:
    get:
      summary: Paginated purchase invoices
      description: Requires purchases.read.
      responses:
        '200': {description: Purchase invoices with supplier, location and items}
  /orders:
    get:
      summary: Ecommerce orders
      description: Requires orders.read.
      responses:
        '200': {description: Paginated organization orders}
  /devices/readings:
    post:
      summary: Submit scale, RFID, barcode, biometric or printer event
      description: Requires devices.write and supports Idempotency-Key.
      parameters:
        - name: Idempotency-Key
          in: header
          schema: {type: string}
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [connection_uuid, reading_id, device_type, device_id, value]
              properties:
                connection_uuid: {type: string, format: uuid}
                reading_id: {type: string}
                device_type: {enum: [scale, rfid, barcode, biometric, printer]}
                device_id: {type: string}
                value: {}
                unit: {type: string}
                metadata: {type: object}
      responses:
        '201': {description: New reading recorded}
        '200': {description: Duplicate reading safely replayed}
  /webhooks/{connection}:
    post:
      security: []
      summary: Signed provider webhook
      description: HMAC-SHA256 of the raw body using the connection secret. Duplicate X-Event-Id values are idempotent.
      parameters:
        - name: connection
          in: path
          required: true
          schema: {type: string, format: uuid}
        - name: X-Baltaji-Signature
          in: header
          required: true
          schema: {type: string}
        - name: X-Event-Id
          in: header
          schema: {type: string}
      responses:
        '202': {description: Event accepted and processed}
        '200': {description: Previously processed event}
        '401': {description: Invalid signature}
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: bte_token
  parameters:
    Organization:
      name: organization
      in: path
      required: true
      schema: {type: string, format: uuid}
  responses:
    Unauthorized: {description: Missing, expired, revoked, or invalid token}
    Forbidden: {description: Ability or source IP denied}
