openapi: 3.0.3
info:
  title: API کلید API نوبیتکس
  version: "1.0.0"
  description: |
    API Key برای دسترسی کنترل‌شده به APIهای نوبیتکس طراحی شده است. هر کلید می‌تواند دسترسی محدود، لیست IP مجاز و تاریخ انقضا داشته باشد.

    ## چرا API Key؟
    - محدود کردن سطح دسترسی به مجوزهای مشخص
    - پشتیبانی از IP Whitelist
    - امکان تعیین تاریخ انقضا
    - امکان حذف یا غیرفعال‌سازی بدون تغییر رمز عبور اصلی
    - مناسب برای ربات‌ها و اسکریپت‌های خودکار

    ## دسترسی‌ها
    | دسترسی | کاربرد |
    | ------ | ------ |
    | `READ` | خواندن اطلاعات کاربر، سفارش‌ها، کیف‌پول‌ها، برداشت‌ها، پرتفو و داده‌های مشابه |
    | `TRADE` | ثبت، لغو یا تغییر سفارش‌های اسپات و تعهدی و عملیات تبدیل موجودی |
    | `WITHDRAW` | ثبت، تایید، لغو و عملیات مرتبط با برداشت |
    | `DEPOSIT` | ساخت آدرس واریز رمزارز |
    | `ADDRESS_BOOK` | افزودن، حذف و تغییر وضعیت دفتر آدرس و برداشت امن |
    | `OTP` | درخواست رمز یکبارمصرف از APIهای مرتبط، مانند دفتر آدرس یا آنتی‌فیشینگ |

    هر کلید می‌تواند یک یا چند دسترسی داشته باشد. مقدار `permissions` هنگام ساخت کلید به صورت رشته جداشده با کاما ارسال می‌شود، مانند `READ,TRADE`.

    ## استفاده از API Key
    برای درخواست‌های پشتیبانی‌شده، به جای هدر `Authorization` سه هدر زیر را ارسال کنید:

    | Header | توضیح |
    | ------ | ----- |
    | `Nobitex-Key` | کلید عمومی برگشتی در فیلد `key` |
    | `Nobitex-Signature` | امضای Ed25519 به صورت URL-safe Base64 |
    | `Nobitex-Timestamp` | زمان Unix بر حسب ثانیه در UTC |

    مقدار `Nobitex-Timestamp` در محیط production باید حداکثر ۳۰ ثانیه با زمان سرور اختلاف داشته باشد.

    ## ساخت امضا
    متن امضا دقیقا به این شکل ساخته می‌شود:

    ```text
    timestamp + METHOD + full_path + raw_body
    ```

    - `timestamp`: همان رشته‌ای که در هدر `Nobitex-Timestamp` ارسال می‌کنید.
    - `METHOD`: متد HTTP با حروف بزرگ، مانند `GET` یا `POST`.
    - `full_path`: مسیر کامل درخواست همراه query string، مانند `/market/orders/list?fromId=123`.
    - `raw_body`: بدنه خام درخواست دقیقا به همان شکلی که ارسال می‌شود. برای درخواست بدون body این بخش رشته خالی است.

    دقت کنید که فاصله‌ها، ترتیب کلیدهای JSON و newlineهای body در امضا اثر دارند. رشته‌ای را امضا کنید که دقیقا به سرور ارسال می‌شود.

    نمونه ساخت امضا برای درخواست `POST /market/orders/cancel-old`:

    ```python
    import base64
    import json
    import time
    from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey

    timestamp = str(int(time.time()))
    method = "POST"
    full_path = "/market/orders/cancel-old"
    body = json.dumps({"hours": 2.4}, separators=(",", ":"))
    payload = f"{timestamp}{method}{full_path}{body}".encode()

    private_key_b64 = "<Your-Private-Key>"
    private_key_bytes = base64.urlsafe_b64decode(private_key_b64)
    private_key = Ed25519PrivateKey.from_private_bytes(private_key_bytes)

    signature = private_key.sign(payload)
    signature_b64 = base64.urlsafe_b64encode(signature).decode()
    print(signature_b64)
    ```

    نمونه درخواست متناظر:

    ```bash
    BODY='{"hours":2.4}'
    curl -X POST 'https://apiv2.nobitex.ir/market/orders/cancel-old' \
      -H "Content-Type: application/json" \
      -H "Nobitex-Key: <Your-Public-Key>" \
      -H "Nobitex-Signature: <Generated-Signature>" \
      -H "Nobitex-Timestamp: <Unix-Timestamp>" \
      -d "$BODY"
    ```

    در این نمونه مقدار `BODY` باید همان رشته‌ای باشد که در متغیر `body` پایتون امضا شده است.

servers:
  - url: https://apiv2.nobitex.ir
  - url: https://testnetapiv2.nobitex.ir

tags:
  - name: کلید API
    description: ایجاد، مشاهده، حذف و ویرایش کلیدهای API

paths:
  /apikeys/create:
    parameters:
      - $ref: "#/components/parameters/TraderBotUserAgent"
    post:
      operationId: createApiKey
      tags:
        - کلید API
      summary: ایجاد API Key
      description: |
        یک API Key جدید برای کاربر ایجاد می‌کند.

        ### نکات امنیتی
        - ارسال کد دوعاملی در هدر `X-TOTP` الزامی است.
        - `privateKey` فقط همین یک بار در پاسخ ساخت کلید نمایش داده می‌شود؛ آن را در محل امن ذخیره کنید.
        - هر کاربر حداکثر ۲۰ کلید فعال می‌تواند داشته باشد.
        - `ipAddressesWhitelist` حداکثر ۱۵ مقدار IPv4/IPv6 می‌پذیرد.
        - `permissions` بعد از ساخت کلید قابل تغییر نیست.

        ### محدودیت‌ها
        - فراخوانی: ۱۰ درخواست در دقیقه
      security:
        - TokenAuth: []
      parameters:
        - $ref: "#/components/parameters/XTOTP"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/APIKeyCreateRequest"
            example:
              name: my-api-key
              description: API key for internal services
              permissions: READ,TRADE
              ipAddressesWhitelist:
                - 192.168.1.10
                - 10.0.0.5
              expirationDate: "2026-12-31T23:59:59Z"
      responses:
        "200":
          description: کلید با موفقیت ساخته شد
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/APIKeyCreateResponse"
              example:
                status: ok
                privateKey: S5y19KewZzheCWCO4xqMcwwvtR8vQ-hHjE_cdjz-XxE=
                key:
                  createdAt: "2026-09-02T16:50:29.381869Z"
                  updatedAt: "2026-09-02T16:50:29.381876Z"
                  expirationDate: "2026-12-31T23:59:59Z"
                  description: API key for internal services
                  ipAddressesWhitelist:
                    - 192.168.1.10
                    - 10.0.0.5
                  key: 5XOCQZSPLQM4MiLzuUnZoBuqgYgTKl40W2X5j1pxfIA=
                  name: my-api-key
                  permissions: READ,TRADE
        "400":
          description: خطای اعتبارسنجی، کد دوعاملی یا محدودیت تعداد کلید/IP
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/APIKeyFailedResponse"

  /apikeys/list:
    parameters:
      - $ref: "#/components/parameters/TraderBotUserAgent"
    get:
      operationId: listApiKeys
      tags:
        - کلید API
      summary: لیست API Keyها
      description: |
        لیست کلیدهای API متعلق به کاربر را برمی‌گرداند.

        ### محدودیت‌ها
        - فراخوانی: ۱۰ درخواست در دقیقه
      security:
        - TokenAuth: []
      responses:
        "200":
          description: لیست کلیدها
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/APIKeyListResponse"

  /apikeys/delete/{publicKey}:
    parameters:
      - $ref: "#/components/parameters/TraderBotUserAgent"
    post:
      operationId: deleteApiKey
      tags:
        - کلید API
      summary: حذف API Key
      description: |
        یک API Key متعلق به کاربر را حذف می‌کند.

        ### نکات امنیتی
        - ارسال کد دوعاملی در هدر `X-TOTP` الزامی است.

        ### محدودیت‌ها
        - فراخوانی: ۱۰ درخواست در دقیقه
      security:
        - TokenAuth: []
      parameters:
        - $ref: "#/components/parameters/PublicKey"
        - $ref: "#/components/parameters/XTOTP"
      responses:
        "200":
          description: حذف موفق
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/StatusOnlyResponse"
              example:
                status: ok
        "404":
          description: کلید پیدا نشد
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/APIKeyFailedResponse"

  /apikeys/update/{publicKey}:
    parameters:
      - $ref: "#/components/parameters/TraderBotUserAgent"
    post:
      operationId: updateApiKey
      tags:
        - کلید API
      summary: ویرایش API Key
      description: |
        مشخصات قابل تغییر یک API Key را ویرایش می‌کند.

        فقط `name`، `description` و `ipAddressesWhitelist` قابل تغییر هستند. دسترسی‌ها و تاریخ انقضا بعد از ساخت کلید تغییر نمی‌کنند.

        ### نکات امنیتی
        - ارسال کد دوعاملی در هدر `X-TOTP` الزامی است.

        ### محدودیت‌ها
        - فراخوانی: ۱۰ درخواست در دقیقه
      security:
        - TokenAuth: []
      parameters:
        - $ref: "#/components/parameters/PublicKey"
        - $ref: "#/components/parameters/XTOTP"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/APIKeyUpdateRequest"
            example:
              name: my-api-key
              description: API key for internal services
              ipAddressesWhitelist:
                - 192.168.1.10
                - 10.0.0.5
      responses:
        "200":
          description: ویرایش موفق
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/APIKeyUpdateResponse"
        "400":
          description: خطای اعتبارسنجی یا کد دوعاملی
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/APIKeyFailedResponse"
        "404":
          description: کلید پیدا نشد
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/APIKeyFailedResponse"

components:
  securitySchemes:
    TokenAuth:
      type: apiKey
      in: header
      name: Authorization
      description: توکن احراز هویت به صورت `Token <token>`.
    NobitexKeyAuth:
      type: apiKey
      in: header
      name: Nobitex-Key
      description: کلید عمومی API Key.
    NobitexSignatureAuth:
      type: apiKey
      in: header
      name: Nobitex-Signature
      description: امضای Ed25519 به صورت URL-safe Base64.
    NobitexTimestampAuth:
      type: apiKey
      in: header
      name: Nobitex-Timestamp
      description: زمان Unix بر حسب ثانیه در UTC.

  parameters:
    TraderBotUserAgent:
      name: User-Agent
      in: header
      required: false
      description: |
        برای شناسایی بات، این هدر را در همه درخواست‌های HTTP بات با الگوی
        `TraderBot/<name-and-version>` ارسال کنید. این هدر هنگام ورود خودکار با
        `captcha=api` الزامی و در سایر فراخوانی‌های بات اکیداً توصیه می‌شود.
      schema:
        type: string
      example: TraderBot/MyBot-1.0.0

    PublicKey:
      name: publicKey
      in: path
      required: true
      description: کلید عمومی API Key، همان مقدار فیلد `key`.
      schema:
        type: string
      example: 5XOCQZSPLQM4MiLzuUnZoBuqgYgTKl40W2X5j1pxfIA=
    XTOTP:
      name: X-TOTP
      in: header
      required: true
      description: کد دوعاملی کاربر.
      schema:
        type: string
      example: "123456"

  schemas:
    APIKeyCreateRequest:
      type: object
      required:
        - name
        - permissions
      properties:
        name:
          type: string
          maxLength: 1024
          description: نام کلید برای شناسایی توسط کاربر
          example: my-api-key
        description:
          type: string
          maxLength: 1000
          default: ""
          description: توضیح دلخواه
          example: API key for internal services
        permissions:
          type: string
          description: |
            دسترسی‌ها به صورت رشته جداشده با کاما.
            مقادیر مجاز: `READ`, `TRADE`, `WITHDRAW`, `DEPOSIT`, `ADDRESS_BOOK`, `OTP`.
          example: READ,TRADE
        ipAddressesWhitelist:
          type: array
          maxItems: 15
          description: لیست IPهای مجاز. در صورت خالی بودن، محدودیت IP اعمال نمی‌شود.
          items:
            type: string
          default: []
        expirationDate:
          type: string
          format: date-time
          nullable: true
          description: تاریخ انقضای اختیاری. باید در آینده باشد.

    APIKeyUpdateRequest:
      type: object
      properties:
        name:
          type: string
          maxLength: 1024
        description:
          type: string
          maxLength: 1000
        ipAddressesWhitelist:
          type: array
          maxItems: 15
          items:
            type: string

    APIKey:
      type: object
      properties:
        key:
          type: string
          description: کلید عمومی API Key
        name:
          type: string
        description:
          type: string
        permissions:
          type: string
          example: READ,TRADE
        ipAddressesWhitelist:
          type: array
          items:
            type: string
        expirationDate:
          type: string
          format: date-time
          nullable: true
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time

    APIKeyCreateResponse:
      type: object
      properties:
        status:
          type: string
          example: ok
        privateKey:
          type: string
          description: کلید خصوصی؛ فقط در پاسخ ساخت کلید نمایش داده می‌شود.
        key:
          $ref: "#/components/schemas/APIKey"

    APIKeyListResponse:
      type: object
      properties:
        status:
          type: string
          example: ok
        keys:
          type: array
          items:
            $ref: "#/components/schemas/APIKey"

    APIKeyUpdateResponse:
      type: object
      properties:
        status:
          type: string
          example: ok
        key:
          $ref: "#/components/schemas/APIKey"

    StatusOnlyResponse:
      type: object
      properties:
        status:
          type: string
          example: ok

    APIKeyFailedResponse:
      type: object
      properties:
        status:
          type: string
          example: failed
        code:
          type: string
          example: ParseError
        message:
          type: string
          example: Validation Failed
