asyncapi: 3.1.0
info:
  title: Kuru Relay WebSocket API
  version: 1.0.0-testnet
  description: |
    Bidirectional typed transaction submission for one JWT-bound wallet.
    The relay receives request messages and sends one correlated response for
    every accepted message ID. This is not a market-data subscription stream.

    Method payloads are shared with the REST OpenAPI contract. `BROADCAST`
    reports RPC acceptance only; clients reconcile receipts and expected
    events or state through an independent chain source.
defaultContentType: application/json
servers:
  testnet:
    host: ws.relay.testnet.kuru.io
    protocol: wss
    title: Monad testnet relay WebSocket
    description: |
      Obtain a wallet-bound JWT through the REST challenge flow, then provide it
      in the HTTP upgrade Authorization header.
      The edge must keep the upgraded connection sticky for its lifetime.
    security:
      - $ref: '#/components/securitySchemes/bearerAuth'
channels:
  relay:
    address: /relay/ws
    title: Wallet-bound relay session
    summary: Exchange typed sponsored-transaction requests and correlated results.
    description: |
      The connection is bound to the wallet claim established during upgrade.
      The server generates an opaque signer-affinity key and pins the session
      to one sponsor lane. It does not remap the connection when that lane is
      unavailable.
    servers:
      - $ref: '#/servers/testnet'
    messages:
      relayRequest:
        $ref: '#/components/messages/RelayRequest'
      relayResponse:
        $ref: '#/components/messages/RelayResponse'
operations:
  receiveRelayRequest:
    action: receive
    title: Receive a relay request
    summary: The Kuru Relay application receives one typed request from the client.
    description: |
      Requests may be in flight concurrently, but wallet nonce admission and
      update of the connection-local last accepted nonce are serialized.
    channel:
      $ref: '#/channels/relay'
    messages:
      - $ref: '#/channels/relay/messages/relayRequest'
  sendRelayResponse:
    action: send
    title: Send a relay result
    summary: The Kuru Relay application sends one response correlated by `id`.
    description: |
      A bounded recent-response cache can return the same response for a
      duplicate message ID on the same connection. Missing responses after a
      disconnect are ambiguous and require chain-state reconciliation.
    channel:
      $ref: '#/channels/relay'
    messages:
      - $ref: '#/channels/relay/messages/relayResponse'
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: Wallet-bound testnet JWT obtained from the REST authentication flow and supplied in the HTTP upgrade Authorization header.
  correlationIds:
    messageId:
      description: Opaque client-selected ID unique within one connection.
      location: $message.payload#/id
  messages:
    RelayRequest:
      name: RelayRequest
      title: Relay request
      summary: One method and payload for the wallet bound during upgrade.
      contentType: application/json
      correlationId:
        $ref: '#/components/correlationIds/messageId'
      payload:
        schemaFormat: application/vnd.oai.openapi;version=3.1.0
        schema:
          $ref: '../../../api/spec/relay/openapi.yaml#/components/schemas/WebSocketRelayRequest'
      examples:
        - name: batchCancel
          summary: Cancel slot 3 using an exact order-ID binding.
          payload:
            id: '42'
            method: wallet.execute_batch
            payload:
              header:
                accountId: '123'
                market: '0x2222222222222222222222222222222222222222'
                authNonce: '9'
                nonce: '1720000000123'
                deadline: '1720000030'
                clientOrderId: '0x0000000000000000000000000000000000000000000000000000000000000001'
                builder: '0x0000000000000000000000000000000000000000'
                builderFeePps: '0'
              orders: []
              cancelSlotIdxs: ['3']
              expectedOrderIds: ['31']
              signature: '0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b'
            authorization7702: null
    RelayResponse:
      name: RelayResponse
      title: Relay response
      summary: Broadcast acceptance, definite rejection, or ambiguous broadcast outcome.
      contentType: application/json
      correlationId:
        $ref: '#/components/correlationIds/messageId'
      payload:
        schemaFormat: application/vnd.oai.openapi;version=3.1.0
        schema:
          $ref: '../../../api/spec/relay/openapi.yaml#/components/schemas/WebSocketRelayResponse'
      examples:
        - name: broadcast
          payload:
            id: '42'
            status: BROADCAST
            txHash: '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
            sponsorAddress: '0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'
            sponsorNonce: '81'
            transactionType: DYNAMIC_FEE
            retryable: false
        - name: nonIncreasingNonce
          payload:
            id: '43'
            status: REJECTED
            code: NON_INCREASING_SESSION_NONCE
            message: nonce must increase within this WebSocket session
            retryable: false
            receivedNonce: 1720000000123
            lastAcceptedNonce: 1720000000123
        - name: unknownBroadcast
          summary: The current WS error envelope does not expose candidate identity.
          payload:
            id: '44'
            status: UNKNOWN
            code: BROADCAST_RESULT_UNKNOWN
            message: broadcast result is unknown
            retryable: false
  schemas:
    ApplicationCloseCode:
      type: integer
      enum: [4001, 4002, 4003]
      description: |
        4001 is bounded session overload, 4002 is shutdown/drain, and 4003 is
        loss of the pinned signer lane. Every application close code requires
        a new connection and reconciliation of outstanding message IDs.
