openapi: 3.0.3
info:
  title: Paynet UWS (Universal Web Service) API
  description: |
    API specification for integration with the Paynet payment system via the UWS protocol (universal connector).
    Interaction is carried out via JSON-RPC 2.0 over HTTP 1.1 POST protected by TLS v1.3 (HTTPS).
    Conforms to the UWS v3.4 specification dated 07.05.2025.

    **Important requirements:**
    - All requests must use `UTF-8` encoding and the headers `Content-Type: application/json`, `Accept: application/json`.
    - Date format is strictly `YYYY-MM-dd HH:mm:ss`, time zone GMT+5.
      **The only exception:** the `timestamp` parameter in the `CheckTransaction` request arrives in the format
      `EEE MMM dd HH:mm:ss z yyyy` (e.g., `Mon Jun 16 06:12:41 UZT 2021`). The format is fixed
      historically and will not change.
    - `HTTP Basic Authentication` is mandatory. If authorization data is missing or invalid,
      the system must return `HTTP 401 Unauthorized` (not 200 OK with a JSON-RPC error).
    - SLA: transaction processing — no more than 500 ms (up to 1 s is allowed, but no more than 30 minutes per day);
      if no response is received within 30 seconds, Paynet terminates the connection by timeout.
      In case of systematic SLA violations, Paynet may disconnect the provider until the cause is eliminated.
    - Amounts (`amount`) are integers in tiyins (1 sum = 100 tiyins).
    - The composition and value types of the `fields` object are defined by the partner in the
      "Technical Interaction Procedure" questionnaire (Tables 3/5); string values are recommended.
  version: 3.4.0
  contact:
    name: Paynet Integration Team
    email: support@paynet.uz

servers:
  - url: https://api.partner.domain
    description: Partner's production server (URL is provided by the partner)

security:
  - basicAuth: []

paths:
  /uws:
    post:
      summary: Single entry point for JSON-RPC requests
      description: |
        All requests from Paynet to the partner's billing are sent to this endpoint via POST.
        The request body must conform to the JSON-RPC 2.0 standard. The method is determined by the `method` field;
        the `params` structure is strictly bound to the `method` value (see the `RpcRequest` schema).
      operationId: processRpcRequest
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RpcRequest'
            examples:
              GetInformation:
                summary: Reference information request
                value:
                  jsonrpc: "2.0"
                  method: "GetInformation"
                  id: 12350
                  params:
                    serviceId: 1
                    fields:
                      client_id: "634247"
              PerformTransaction:
                summary: Payment execution
                value:
                  jsonrpc: "2.0"
                  method: "PerformTransaction"
                  id: 12345
                  params:
                    amount: 100000
                    serviceId: 1
                    transactionId: 12345678900
                    fields:
                      client_id: "634247"
              CheckTransaction:
                summary: Status check (note the timestamp format!)
                value:
                  jsonrpc: "2.0"
                  method: "CheckTransaction"
                  id: 12346
                  params:
                    serviceId: 1
                    transactionId: 12345678900
                    timestamp: "Mon Jun 16 06:12:41 UZT 2021"
              CancelTransaction:
                summary: Transaction cancellation
                value:
                  jsonrpc: "2.0"
                  method: "CancelTransaction"
                  id: 12347
                  params:
                    serviceId: 1
                    transactionId: 12345678900
                    timestamp: "2021-06-16 12:44:57"
              GetStatement:
                summary: Reconciliation for a period
                value:
                  jsonrpc: "2.0"
                  method: "GetStatement"
                  id: 12348
                  params:
                    serviceId: 1
                    dateFrom: "2021-04-20 08:00:00"
                    dateTo: "2021-04-30 08:00:00"
              ChangePassword:
                summary: Password change (optional method)
                value:
                  jsonrpc: "2.0"
                  method: "ChangePassword"
                  id: 12351
                  params:
                    newPassword: "newSecurePassword"
      responses:
        '200':
          description: Successful or unsuccessful RPC response (result XOR error)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RpcResponse'
              examples:
                GetInformationResult:
                  summary: GetInformation response
                  value:
                    jsonrpc: "2.0"
                    id: 12350
                    result:
                      status: 0
                      timestamp: "2021-04-30 08:00:00"
                      fields:
                        balance: "420000"
                        name: "Pushkin A.S."
                PerformTransactionResult:
                  summary: PerformTransaction response
                  value:
                    jsonrpc: "2.0"
                    id: 12345
                    result:
                      timestamp: "2021-06-16 12:41:54"
                      providerTrnId: 2323
                      fields:
                        client_id: "634247"
                CheckTransactionResult:
                  summary: CheckTransaction response
                  value:
                    jsonrpc: "2.0"
                    id: 12346
                    result:
                      transactionState: 1
                      timestamp: "2021-06-16 12:44:57"
                      providerTrnId: 2323
                GetStatementResult:
                  summary: GetStatement response (successful transactions only)
                  value:
                    jsonrpc: "2.0"
                    id: 12348
                    result:
                      statements:
                        - amount: 120000
                          providerTrnId: 23
                          transactionId: 12345679800
                          timestamp: "2021-04-23 17:04:22"
                        - amount: 780000
                          providerTrnId: 47
                          transactionId: 12346578901
                          timestamp: "2021-04-24 13:25:02"
                ChangePasswordResult:
                  summary: ChangePassword response
                  value:
                    jsonrpc: "2.0"
                    id: 12351
                    result: "success"
                BusinessError:
                  summary: Business error (client not found)
                  value:
                    jsonrpc: "2.0"
                    id: 12350
                    error:
                      code: 302
                      message: "Client not found"
        '401':
          description: Unauthorized. HTTP Basic Auth data is missing or invalid. No response body required.

components:
  securitySchemes:
    basicAuth:
      type: http
      scheme: basic
      description: Login and password are provided by the partner to authorize Paynet requests.

  schemas:
    RpcId:
      description: Request identifier. Can be of any type (number or string); the response must return the same value.
      oneOf:
        - type: integer
          format: int64
        - type: string

    RpcRequest:
      description: JSON-RPC 2.0 request. The `params` structure is determined by the `method` value.
      oneOf:
        - $ref: '#/components/schemas/GetInformationRequest'
        - $ref: '#/components/schemas/PerformTransactionRequest'
        - $ref: '#/components/schemas/CheckTransactionRequest'
        - $ref: '#/components/schemas/CancelTransactionRequest'
        - $ref: '#/components/schemas/GetStatementRequest'
        - $ref: '#/components/schemas/ChangePasswordRequest'

    GetInformationRequest:
      type: object
      additionalProperties: false
      required: [jsonrpc, method, id, params]
      properties:
        jsonrpc:
          type: string
          enum: ["2.0"]
        method:
          type: string
          enum: [GetInformation]
        id:
          $ref: '#/components/schemas/RpcId'
        params:
          $ref: '#/components/schemas/GetInformationParams'

    PerformTransactionRequest:
      type: object
      additionalProperties: false
      required: [jsonrpc, method, id, params]
      properties:
        jsonrpc:
          type: string
          enum: ["2.0"]
        method:
          type: string
          enum: [PerformTransaction]
        id:
          $ref: '#/components/schemas/RpcId'
        params:
          $ref: '#/components/schemas/PerformTransactionParams'

    CheckTransactionRequest:
      type: object
      additionalProperties: false
      required: [jsonrpc, method, id, params]
      properties:
        jsonrpc:
          type: string
          enum: ["2.0"]
        method:
          type: string
          enum: [CheckTransaction]
        id:
          $ref: '#/components/schemas/RpcId'
        params:
          $ref: '#/components/schemas/CheckTransactionParams'

    CancelTransactionRequest:
      type: object
      additionalProperties: false
      required: [jsonrpc, method, id, params]
      properties:
        jsonrpc:
          type: string
          enum: ["2.0"]
        method:
          type: string
          enum: [CancelTransaction]
        id:
          $ref: '#/components/schemas/RpcId'
        params:
          $ref: '#/components/schemas/CancelTransactionParams'

    GetStatementRequest:
      type: object
      additionalProperties: false
      required: [jsonrpc, method, id, params]
      properties:
        jsonrpc:
          type: string
          enum: ["2.0"]
        method:
          type: string
          enum: [GetStatement]
        id:
          $ref: '#/components/schemas/RpcId'
        params:
          $ref: '#/components/schemas/GetStatementParams'

    ChangePasswordRequest:
      type: object
      additionalProperties: false
      required: [jsonrpc, method, id, params]
      properties:
        jsonrpc:
          type: string
          enum: ["2.0"]
        method:
          type: string
          enum: [ChangePassword]
        id:
          $ref: '#/components/schemas/RpcId'
        params:
          $ref: '#/components/schemas/ChangePasswordParams'

    GetInformationParams:
      type: object
      additionalProperties: false
      required: [serviceId, fields]
      properties:
        serviceId:
          type: integer
          description: Service identifier on the provider side (static, specified in the "Technical Interaction Procedure")
        fields:
          type: object
          description: List of filled-in service fields (e.g., phone number, personal account). Composition and value types — per the partner's questionnaire.

    PerformTransactionParams:
      type: object
      additionalProperties: false
      required: [amount, serviceId, transactionId, fields]
      properties:
        amount:
          type: integer
          format: int64
          minimum: 1
          description: Operation amount in tiyins (integer, 1 sum = 100 tiyins)
        serviceId:
          type: integer
          description: Service identifier on the provider side
        transactionId:
          type: integer
          format: int64
          description: Unique PAYNET transaction identifier (idempotency key)
        fields:
          type: object
          description: List of filled-in service fields. Composition and value types — per the partner's questionnaire.

    CheckTransactionParams:
      type: object
      additionalProperties: false
      required: [serviceId, transactionId, timestamp]
      properties:
        serviceId:
          type: integer
        transactionId:
          type: integer
          format: int64
        timestamp:
          type: string
          pattern: '^[A-Z][a-z]{2} [A-Z][a-z]{2} \d{2} \d{2}:\d{2}:\d{2} [A-Z]{2,5} \d{4}$'
          description: |
            Date and time of request processing on the PAYNET side (GMT+5).
            **ATTENTION: exception to the general rule.** The format is `EEE MMM dd HH:mm:ss z yyyy`
            (e.g., `Mon Jun 16 06:12:41 UZT 2021`). The format is fixed historically and will not change.
            The month is strictly in the abbreviated `MMM` form ("Jun").
          example: "Mon Jun 16 06:12:41 UZT 2021"

    CancelTransactionParams:
      type: object
      additionalProperties: false
      required: [serviceId, transactionId, timestamp]
      properties:
        serviceId:
          type: integer
        transactionId:
          type: integer
          format: int64
        timestamp:
          type: string
          pattern: '^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$'
          description: |
            Date and time of request processing on the PAYNET side (GMT+5).
            Confirmed by the core team: both the CancelTransaction request and response use the standard
            `YYYY-MM-dd HH:mm:ss` format (unlike CheckTransaction). Legacy specification examples
            used `dd.MM.yyyy HH:mm:ss` — that is a source typo.
          example: "2021-06-16 12:44:57"

    GetStatementParams:
      type: object
      additionalProperties: false
      required: [serviceId, dateFrom, dateTo]
      properties:
        serviceId:
          type: integer
        dateFrom:
          type: string
          pattern: '^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$'
          description: Start date and time of the period (GMT+5)
        dateTo:
          type: string
          pattern: '^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$'
          description: End date and time of the period (GMT+5)

    ChangePasswordParams:
      type: object
      additionalProperties: false
      required: [newPassword]
      properties:
        newPassword:
          type: string
          minLength: 8
          description: New password (minimum length is agreed upon with Paynet)

    RpcResponse:
      description: JSON-RPC 2.0 response. Contains either `result` (success) or `error` (failure) — never both.
      oneOf:
        - $ref: '#/components/schemas/RpcSuccessResponse'
        - $ref: '#/components/schemas/RpcErrorResponse'

    RpcSuccessResponse:
      type: object
      additionalProperties: false
      required: [jsonrpc, id, result]
      properties:
        jsonrpc:
          type: string
          enum: ["2.0"]
        id:
          $ref: '#/components/schemas/RpcId'
        result:
          $ref: '#/components/schemas/RpcResult'

    RpcErrorResponse:
      type: object
      additionalProperties: false
      required: [jsonrpc, id, error]
      properties:
        jsonrpc:
          type: string
          enum: ["2.0"]
        id:
          description: Matches the request id; null is allowed for a parse error (-32700).
          oneOf:
            - type: integer
              format: int64
            - type: string
              nullable: true
        error:
          $ref: '#/components/schemas/RpcError'

    RpcResult:
      oneOf:
        - $ref: '#/components/schemas/GetInformationResult'
        - $ref: '#/components/schemas/PerformTransactionResult'
        - $ref: '#/components/schemas/CheckCancelTransactionResult'
        - $ref: '#/components/schemas/GetStatementResult'
        - $ref: '#/components/schemas/ChangePasswordResult'

    GetInformationResult:
      type: object
      additionalProperties: false
      required: [status, timestamp, fields]
      properties:
        status:
          type: integer
          description: Request state (0 — success). Legacy examples used the string "0" — return an integer.
        timestamp:
          type: string
          pattern: '^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$'
          description: Date and time of request processing on the provider side (GMT+5)
        fields:
          type: object
          description: List of additional parameters (e.g., client balance and name)

    PerformTransactionResult:
      type: object
      additionalProperties: false
      required: [providerTrnId, fields, timestamp]
      properties:
        providerTrnId:
          type: integer
          format: int64
          description: Provider's transaction identifier
        fields:
          type: object
          description: |
            List of filled-in service fields. If agreed in the questionnaire (Table 4),
            the payer's balance after the transaction (in tiyins) is returned here.
        timestamp:
          type: string
          pattern: '^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$'
          description: Date and time of request processing on the provider side (GMT+5)

    CheckCancelTransactionResult:
      type: object
      additionalProperties: false
      required: [providerTrnId, timestamp, transactionState]
      properties:
        providerTrnId:
          type: integer
          format: int64
        timestamp:
          type: string
          pattern: '^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$'
          description: Date and time of request processing on the provider side (GMT+5)
        transactionState:
          $ref: '#/components/schemas/TransactionStateEnum'

    GetStatementResult:
      type: object
      additionalProperties: false
      required: [statements]
      properties:
        statements:
          type: array
          description: Array of transactions for the period. ONLY successful transactions (state 1) are included; cancelled ones are not.
          items:
            $ref: '#/components/schemas/StatementItem'

    StatementItem:
      type: object
      additionalProperties: false
      required: [amount, transactionId, providerTrnId, timestamp]
      properties:
        amount:
          type: integer
          format: int64
          minimum: 1
          description: Financial operation amount in tiyins
        transactionId:
          type: integer
          format: int64
        providerTrnId:
          type: integer
          format: int64
        timestamp:
          type: string
          pattern: '^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$'
          description: Date and time of transaction processing on the provider side (GMT+5)

    ChangePasswordResult:
      type: string
      description: Request processing status (string, e.g., "success")
      example: "success"

    TransactionStateEnum:
      type: integer
      description: |
        1 – Successfully completed transaction, 2 – Cancelled transaction, 3 – Transaction not found.
        For CheckTransaction on an unknown transaction, return state 3 (a success envelope), not error 203.
      enum: [1, 2, 3]

    RpcError:
      type: object
      additionalProperties: false
      required:
        - code
        - message
      properties:
        code:
          type: integer
          description: |
            Paynet error code — a JSON-RPC-level code returned inside the error object (the HTTP status of the response stays 200 OK; this is NOT an HTTP status code, the two are often confused). Full reference:
            0: Processed successfully (status value; never returned inside the error object)
            77: Insufficient funds on the client's account to cancel the payment
            100: Service temporarily unsupported
            101: Quota exhausted
            102, 103: System/Unknown error
            113: Wallet not identified
            140: The monthly limit is exceeded for this account
            141: The daily limit is exceeded for this account
            201, 202: Transaction exists/cancelled
            203: Transaction not found (used in CancelTransaction; for CheckTransaction — state 3)
            301, 302, 304, 305: Entity not found
            306: The allowed transaction cancellation period has expired (the provider declines the refund per its own business rules — closing documents issued, reporting period closed; e.g., paid in January, refund attempted in March)
            401-410: Parameter validation errors 1-10 (parameter mapping is service-specific)
            411: One or more required parameters not specified (business level; cf. -32602 at the protocol level)
            412: Invalid login or password (legacy; authentication is performed via HTTP 401)
            413: Invalid amount
            414: Invalid date and time format
            415: Amount exceeds maximum limit
            501, 601, 603: Access/command restrictions
            JSON-RPC: -32300, -32700, -32600, -32601, -32602, -32603
        message:
          type: string
          description: Error description
