openapi: 3.1.0
info:
  title: Auth Server API
  description: |
    ## Overview
    API for Auth server with HTTP endpoints and Socket.IO WebSocket protocol.

    This server facilitates communication between the Decentraland clients and the auth dapp on the browser.
    It allows the desktop client to execute wallet methods (eth_sendTransaction, personal_sign, etc.) using the wallet 
    the user has on their browser.

    ### Request Lifecycle

    1. A request is created with a method and parameters
    2. The server returns a request ID, expiration time, and verification code
    3. The auth dapp recovers the request using the request ID
    4. The request is executed on the auth dapp with the user's wallet
    5. The outcome (result or error) is submitted back to the server
    6. The original client receives the outcome via WebSocket or polling

    ### Request Characteristics

    - Only one request can exist at a time per connected socket. A new request will invalidate a previous one if it existed.
    - Requests have an expiration (default: 5 minutes), and cannot be consumed after it.
    - If the socket disconnects, any request made by that socket will be deleted.

    ### Authentication

    - For methods other than `dcl_personal_sign`, an `authChain` is required and will be validated.
    - For `dcl_personal_sign`, no `authChain` is required initially.
    - Signature validation is performed using `@dcl/crypto` Authenticator.
  version: 1.0.0
  contact:
    name: Decentraland
    url: https://decentraland.org
  license:
    name: Apache 2.0
    url: https://www.apache.org/licenses/LICENSE-2.0.html
  x-api-id: auth-server-api
servers:
  - url: https://auth-api.decentraland.org
    description: Production server
  - url: https://auth-api.decentraland.zone
    description: Development server
  - url: http://localhost:{port}
    description: Local development server (replace {port} with your local port, typically 3000)
    variables:
      port:
        default: '3000'
        description: Local development server port
security: []
tags:
  - name: Health
    description: Health check endpoints for monitoring and orchestration
  - name: Requests
    description: Authentication request management endpoints
  - name: Identities
    description: Temporary identity endpoints used for auto-login flows
  - name: Onboarding
    description: Onboarding checkpoint tracking for email nudge campaigns (internal, requires API key)
  - name: WebSocket
    description: Socket.IO WebSocket events for real-time communication
paths:
  /health/ready:
    get:
      tags:
        - Health
      summary: Readiness probe
      description: Returns 200 when service is ready to accept traffic
      operationId: getReadiness
      security: []
      responses:
        '200':
          description: Service is ready
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                type: object
                properties: &ref_0
                  error:
                    type: string
                    description: Error message describing what went wrong
                required: &ref_1
                  - error
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                type: object
                properties: *ref_0
                required: *ref_1
  /health/startup:
    get:
      tags:
        - Health
      summary: Startup probe
      description: Returns 200 when service has started
      operationId: getStartup
      security: []
      responses:
        '200':
          description: Service has started
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                type: object
                properties: *ref_0
                required: *ref_1
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                type: object
                properties: *ref_0
                required: *ref_1
  /health/live:
    get:
      tags:
        - Health
      summary: Liveness probe
      description: Returns 200 when service is alive
      operationId: getLiveness
      security: []
      responses:
        '200':
          description: Service is alive
          content:
            application/json:
              schema:
                type: object
                properties: &ref_7
                  timestamp:
                    type: number
                    description: Server timestamp in milliseconds
                required: &ref_8
                  - timestamp
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                type: object
                properties: *ref_0
                required: *ref_1
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                type: object
                properties: *ref_0
                required: *ref_1
  /requests:
    post:
      tags:
        - Requests
      summary: Create authentication request
      description: |
        Creates a new authentication request that can be executed by the auth dapp.

        **Important:**
        - For methods other than `dcl_personal_sign`, the `authChain` field is **required** and will be validated.
        - For `dcl_personal_sign`, the `authChain` field is **optional**.
        - Signature validation is performed using `@dcl/crypto` Authenticator.
        - The request will expire after the configured expiration time (default: 5 minutes).
      operationId: createRequest
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties: &ref_9
                method:
                  type: string
                  description: Wallet method to execute (e.g., 'eth_sendTransaction', 'personal_sign', 'dcl_personal_sign')
                  example: personal_sign
                params:
                  type: array
                  items: {}
                  description: Method parameters (any JSON-serializable type)
                  example:
                    - Message to sign
                    - '0x1234567890123456789012345678901234567890'
                authChain:
                  description: |
                    Optional authentication chain. 
                    **Required** for methods other than `dcl_personal_sign`.
                    **Optional** for `dcl_personal_sign` method.
                  type: array
                  items: &ref_4
                    type: object
                    properties:
                      type:
                        type: string
                        description: Auth link type (e.g., SIGNER, ECDSA_EPHEMERAL)
                      payload:
                        type: string
                        description: Link payload
                      signature:
                        type: string
                        description: Link signature
                    required:
                      - type
                      - payload
                      - signature
                  minItems: 1
              required: &ref_10
                - method
                - params
              additionalProperties: false
            examples:
              personalSign:
                summary: Personal sign request
                value:
                  method: personal_sign
                  params:
                    - Message to sign
                    - '0x1234567890123456789012345678901234567890'
                  authChain:
                    - type: SIGNER
                      payload: '0x1234567890123456789012345678901234567890'
                      signature: ''
                    - type: ECDSA_EPHEMERAL
                      payload: ...
                      signature: ...
              dclPersonalSign:
                summary: DCL personal sign request (no authChain required)
                value:
                  method: dcl_personal_sign
                  params:
                    - |-
                      DCL Signed Message:
                      Ephemeral address: 0x...
                      Expiration: ...
      responses:
        '201':
          description: Request created successfully
          content:
            application/json:
              schema:
                type: object
                properties: &ref_11
                  requestId:
                    type: string
                    format: uuid
                    description: Unique request identifier
                  expiration:
                    type: string
                    format: date-time
                    description: Request expiration time (ISO 8601). Request must be consumed before this time.
                  code:
                    type: number
                    minimum: 0
                    maximum: 99
                    description: Random verification code (0-99) for visual confirmation on both client and auth dapp
                required: &ref_12
                  - requestId
                  - expiration
                  - code
              example:
                requestId: 550e8400-e29b-41d4-a716-446655440000
                expiration: '2024-01-01T12:10:00.000Z'
                code: 42
        '400':
          description: Invalid request (missing required fields, invalid authChain, signature validation failed)
          content:
            application/json:
              schema:
                type: object
                properties: *ref_0
                required: *ref_1
              examples:
                missingAuthChain:
                  summary: Missing auth chain for non-dcl_personal_sign method
                  value:
                    error: Auth chain is required
                invalidSignature:
                  summary: Signature validation failed
                  value:
                    error: Signature validation failed
                invalidPayload:
                  summary: Invalid request payload
                  value:
                    error: '[{"instancePath":"/method","schemaPath":"#/required","keyword":"required","params":{"missingProperty":"method"},"message":"must have required property ''method''"}]'
  /requests/{requestId}:
    get:
      tags:
        - Requests
      summary: Poll for request outcome
      description: |
        Polls for the outcome of an authentication request. 

        This endpoint can be used as an alternative to WebSocket for receiving request outcomes.
        The client should poll this endpoint periodically until a result is returned.

        **Status Codes:**
        - `200`: Request completed, outcome returned
        - `204`: Request not yet completed, continue polling
        - `404`: Request not found
        - `410`: Request expired
      operationId: pollRequest
      security: []
      parameters:
        - name: requestId
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: Request ID to poll for
          example: 550e8400-e29b-41d4-a716-446655440000
      responses:
        '200':
          description: Request completed with outcome
          content:
            application/json:
              schema:
                type: object
                properties: &ref_28
                  requestId:
                    type: string
                    format: uuid
                    description: Request identifier
                  sender:
                    type: string
                    description: Address that executed the request
                    example: '0x1234567890123456789012345678901234567890'
                  result:
                    description: Success result (any JSON-serializable type). Present when request succeeded.
                  error:
                    description: Error details. Present when request failed.
                    type: object
                    properties: &ref_2
                      code:
                        type: number
                        description: Error code
                      message:
                        type: string
                        description: Error message
                      data:
                        description: Additional error data (any type)
                    required: &ref_3
                      - code
                      - message
                required: &ref_29
                  - requestId
                  - sender
                oneOf: &ref_30
                  - required:
                      - result
                  - required:
                      - error
              example:
                requestId: 550e8400-e29b-41d4-a716-446655440000
                sender: '0x1234567890123456789012345678901234567890'
                result: 0xabcdef1234567890...
        '204':
          description: Request not yet completed (continue polling)
          content:
            application/json:
              schema:
                type: object
                properties: *ref_0
                required: *ref_1
              example:
                error: Request with id "550e8400-e29b-41d4-a716-446655440000" has not been completed
        '404':
          description: Request not found
          content:
            application/json:
              schema:
                type: object
                properties: *ref_0
                required: *ref_1
              example:
                error: Request with id "550e8400-e29b-41d4-a716-446655440000" not found
        '410':
          description: Request expired
          content:
            application/json:
              schema:
                type: object
                properties: *ref_0
                required: *ref_1
              example:
                error: Request with id "550e8400-e29b-41d4-a716-446655440000" has expired
  /v2/requests/{requestId}/outcome:
    post:
      tags:
        - Requests
      summary: Submit request outcome
      description: |
        Submits the outcome of a previously created request. If the request originated from a WebSocket client, the server will immediately emit the `outcome` event to that client and delete the request. Otherwise, the outcome is stored for later retrieval via polling.
      operationId: submitOutcome
      security: []
      parameters:
        - name: requestId
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: Request ID to submit outcome for
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties: &ref_17
                sender:
                  type: string
                  description: Address that executed the request
                  example: '0x1234567890123456789012345678901234567890'
                result:
                  description: Success result (any JSON-serializable type). Required if error is not present.
                error:
                  description: Error details. Required if result is not present.
                  type: object
                  properties: *ref_2
                  required: *ref_3
              required: &ref_18
                - sender
              oneOf: &ref_19
                - required:
                    - result
                - required:
                    - error
            examples:
              success:
                summary: Successful outcome
                value:
                  sender: '0x1234567890123456789012345678901234567890'
                  result: 0xabcdef1234567890...
              failure:
                summary: Failed outcome
                value:
                  sender: '0x1234567890123456789012345678901234567890'
                  error:
                    code: 4001
                    message: User rejected the request
      responses:
        '200':
          description: Outcome accepted
        '400':
          description: Bad request (invalid body or request already has a response)
          content:
            application/json:
              schema:
                type: object
                properties: *ref_0
                required: *ref_1
        '404':
          description: Request not found
          content:
            application/json:
              schema:
                type: object
                properties: *ref_0
                required: *ref_1
        '410':
          description: Request expired
          content:
            application/json:
              schema:
                type: object
                properties: *ref_0
                required: *ref_1
  /v2/requests/{requestId}/validation:
    post:
      tags:
        - Requests
      summary: Notify request requires validation
      description: |
        Notifies that the request requires additional user validation (e.g., visual code confirmation).  
        If the requester is connected via WebSocket, the server relays a `request-validation-status` event to that client.
      operationId: notifyRequestValidation
      security: []
      parameters:
        - name: requestId
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: Request ID to notify
      responses:
        '204':
          description: Notification accepted (no content)
        '404':
          description: Request not found
          content:
            application/json:
              schema:
                type: object
                properties: *ref_0
                required: *ref_1
        '410':
          description: Request expired
          content:
            application/json:
              schema:
                type: object
                properties: *ref_0
                required: *ref_1
    get:
      tags:
        - Requests
      summary: Get request validation status
      description: Returns whether a request requires additional validation.
      operationId: getRequestValidationStatus
      security: []
      parameters:
        - name: requestId
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: Request ID to check
      responses:
        '200':
          description: Validation status
          content:
            application/json:
              schema:
                type: object
                properties: &ref_15
                  requiresValidation:
                    type: boolean
                    description: Whether this request requires additional validation
                required: &ref_16
                  - requiresValidation
        '404':
          description: Request not found
          content:
            application/json:
              schema:
                type: object
                properties: *ref_0
                required: *ref_1
        '410':
          description: Request expired
          content:
            application/json:
              schema:
                type: object
                properties: *ref_0
                required: *ref_1
  /identities:
    post:
      tags:
        - Identities
      summary: Create identity (Signed Fetch)
      description: |
        Creates a temporary identity used for auto-login.  
        This endpoint requires a Signed Fetch request per ADR-44. Requests signed by scenes are rejected.
      operationId: createIdentity
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties: &ref_22
                identity:
                  type: object
                  properties: &ref_5
                    expiration:
                      type: string
                      format: date-time
                    ephemeralIdentity:
                      type: object
                      properties: &ref_20
                        address:
                          type: string
                          description: Ephemeral wallet address
                        publicKey:
                          type: string
                          description: Ephemeral wallet public key
                        privateKey:
                          type: string
                          description: Ephemeral wallet private key
                      required: &ref_21
                        - address
                        - publicKey
                        - privateKey
                    authChain:
                      type: array
                      items: *ref_4
                      description: Authentication chain for signature validation (from @dcl/schemas)
                      minItems: 1
                  required: &ref_6
                    - expiration
                    - ephemeralIdentity
                    - authChain
              required: &ref_23
                - identity
              additionalProperties: false
            example:
              identity:
                expiration: '2024-01-01T12:10:00.000Z'
                ephemeralIdentity:
                  address: '0x1234567890123456789012345678901234567890'
                  publicKey: 0x...
                  privateKey: 0x...
                authChain:
                  - type: SIGNER
                    payload: '0x1234567890123456789012345678901234567890'
                    signature: 0x...
                  - type: ECDSA_EPHEMERAL
                    payload: ...
                    signature: 0x...
      responses:
        '201':
          description: Identity created
          content:
            application/json:
              schema:
                type: object
                properties: &ref_24
                  identityId:
                    type: string
                    format: uuid
                    description: Unique identity identifier
                  expiration:
                    type: string
                    format: date-time
                    description: Identity expiration time (ISO 8601)
                required: &ref_25
                  - identityId
                  - expiration
        '400':
          description: Invalid request or auth chain
          content:
            application/json:
              schema:
                type: object
                properties: *ref_0
                required: *ref_1
        '401':
          description: Ephemeral key expired
          content:
            application/json:
              schema:
                type: object
                properties: *ref_0
                required: *ref_1
        '403':
          description: Authorization mismatch or invalid signer
          content:
            application/json:
              schema:
                type: object
                properties: *ref_0
                required: *ref_1
  /identities/{id}:
    get:
      tags:
        - Identities
      summary: Retrieve and consume identity
      description: |
        Retrieves an identity by ID for auto-login.  
        The identity is deleted after a successful retrieval.  
        The request must originate from the same IP (flexible matching) used when creating the identity.
      operationId: getIdentity
      security: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: Identity ID
      responses:
        '200':
          description: Identity retrieved
          content:
            application/json:
              schema:
                type: object
                properties: &ref_26
                  identity:
                    type: object
                    properties: *ref_5
                    required: *ref_6
                required: &ref_27
                  - identity
        '400':
          description: Invalid identity format
          content:
            application/json:
              schema:
                type: object
                properties: *ref_0
                required: *ref_1
        '403':
          description: IP address mismatch
          content:
            application/json:
              schema:
                type: object
                properties: *ref_0
                required: *ref_1
        '404':
          description: Identity not found
          content:
            application/json:
              schema:
                type: object
                properties: *ref_0
                required: *ref_1
        '410':
          description: Identity expired
          content:
            application/json:
              schema:
                type: object
                properties: *ref_0
                required: *ref_1
  /v2/requests/{requestId}:
    get:
      tags:
        - Requests
      summary: Get request details
      description: |
        Retrieves the details of an authentication request for execution.

        This endpoint is used by the auth dapp to recover request information before executing it.
        The request must exist, not be expired, and pass IP address validation (if applicable).
      operationId: getRequestDetails
      security: []
      parameters:
        - name: requestId
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: Request ID to retrieve
          example: 550e8400-e29b-41d4-a716-446655440000
      responses:
        '200':
          description: Request details retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties: &ref_13
                  expiration:
                    type: string
                    format: date-time
                    description: Request expiration time
                  code:
                    type: number
                    description: Request verification code
                  method:
                    type: string
                    description: Original method that was requested
                  params:
                    type: array
                    items: {}
                    description: Original parameters for the method
                  sender:
                    type: string
                    description: Sender address derived from auth chain (if applicable)
                    example: '0x1234567890123456789012345678901234567890'
                required: &ref_14
                  - expiration
                  - code
                  - method
                  - params
              example:
                expiration: '2024-01-01T12:10:00.000Z'
                code: 42
                method: personal_sign
                params:
                  - Message to sign
                  - '0x1234567890123456789012345678901234567890'
                sender: '0x1234567890123456789012345678901234567890'
        '403':
          description: IP validation failed
          content:
            application/json:
              schema:
                type: object
                properties: *ref_0
                required: *ref_1
              example:
                error: IP validation failed
        '404':
          description: Request not found
          content:
            application/json:
              schema:
                type: object
                properties: *ref_0
                required: *ref_1
              example:
                error: Request with id "550e8400-e29b-41d4-a716-446655440000" not found
        '410':
          description: Request expired
          content:
            application/json:
              schema:
                type: object
                properties: *ref_0
                required: *ref_1
              example:
                error: Request with id "550e8400-e29b-41d4-a716-446655440000" has expired
  /onboarding/checkpoint:
    post:
      tags:
        - Onboarding
      summary: Record an onboarding checkpoint
      description: |
        Records that a user has reached or completed an onboarding checkpoint.

        Called by events-notifier after validating a Segment webhook. Not intended to be called directly from the browser.

        **Checkpoints (1–7):**
        1. Authentication Started
        2. Auth Method Selected
        3. Profile Creation
        4. Avatar Creator Started
        5. Download Page Viewed
        6. Download Clicked
        7. Launcher Ready

        **Implicit completion:** Recording checkpoint N automatically marks checkpoint N-1 as completed.
      operationId: recordCheckpoint
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties: &ref_31
                checkpointId:
                  type: integer
                  minimum: 1
                  maximum: 7
                  description: Onboarding checkpoint identifier (1–7)
                userIdentifier:
                  type: string
                  description: User identifier (email address or wallet address)
                identifierType:
                  type: string
                  enum:
                    - email
                    - wallet
                  description: Type of user identifier
                action:
                  type: string
                  enum:
                    - reached
                    - completed
                  description: Whether the user reached or completed this checkpoint
                email:
                  type: string
                  format: email
                  description: User's email address (used for nudge emails)
                source:
                  type: string
                  description: Source of the checkpoint event (e.g. "auth", "website", "launcher")
                metadata:
                  type: object
                  additionalProperties: true
                  description: Additional context (e.g. loginMethod)
              required: &ref_32
                - checkpointId
                - userIdentifier
                - identifierType
                - action
            examples:
              reached:
                summary: User reached a checkpoint
                value:
                  checkpointId: 3
                  userIdentifier: user@example.com
                  identifierType: email
                  action: reached
                  email: user@example.com
                  source: auth
                  metadata:
                    loginMethod: email
              completed:
                summary: Mark a checkpoint as completed
                value:
                  checkpointId: 2
                  userIdentifier: '0x1234567890abcdef'
                  identifierType: wallet
                  action: completed
      responses:
        '200':
          description: Checkpoint recorded
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                required:
                  - success
              example:
                success: true
        '400':
          description: Invalid payload (missing fields, invalid checkpointId, invalid identifierType)
          content:
            application/json:
              schema:
                type: object
                properties: *ref_0
                required: *ref_1
              example:
                error: Invalid checkpointId. Must be between 1 and 7.
        '401':
          description: Missing or invalid API key
          content:
            application/json:
              schema:
                type: object
                properties: *ref_0
                required: *ref_1
              example:
                error: Unauthorized
        '500':
          description: Internal server error (e.g. database failure)
          content:
            application/json:
              schema:
                type: object
                properties: *ref_0
                required: *ref_1
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: API key passed as Bearer token. Required for onboarding endpoints.
  schemas:
    LiveResponseMessage:
      type: object
      properties: *ref_7
      required: *ref_8
    RequestMessage:
      type: object
      properties: *ref_9
      required: *ref_10
      additionalProperties: false
    AuthChain:
      type: array
      items: *ref_4
      description: Authentication chain for signature validation (from @dcl/schemas)
      minItems: 1
    RequestResponseMessage:
      type: object
      properties: *ref_11
      required: *ref_12
    RecoverResponseMessage:
      type: object
      properties: *ref_13
      required: *ref_14
    RequestValidationStatusMessage:
      type: object
      properties: *ref_15
      required: *ref_16
    OutcomeMessageInput:
      type: object
      properties: *ref_17
      required: *ref_18
      oneOf: *ref_19
    EphemeralIdentity:
      type: object
      properties: *ref_20
      required: *ref_21
    AuthIdentity:
      type: object
      properties: *ref_5
      required: *ref_6
    IdentityRequest:
      type: object
      properties: *ref_22
      required: *ref_23
      additionalProperties: false
    IdentityResponse:
      type: object
      properties: *ref_24
      required: *ref_25
    IdentityIdValidationResponse:
      type: object
      properties: *ref_26
      required: *ref_27
    OutcomeError:
      type: object
      properties: *ref_2
      required: *ref_3
    OutcomeResponseMessage:
      type: object
      properties: *ref_28
      required: *ref_29
      oneOf: *ref_30
    CheckpointPayload:
      type: object
      properties: *ref_31
      required: *ref_32
    InvalidResponseMessage:
      type: object
      properties: *ref_0
      required: *ref_1
x-websocket:
  tag: WebSocket
  description: |
    Socket.IO WebSocket protocol for real-time authentication.

    Clients connect using Socket.IO and can send/receive messages in real-time.
    The server uses acknowledgment callbacks for request/response patterns.

    **Connection:**
    - Connect to the server URL using Socket.IO client
    - Example: `const socket = io('https://auth-api.decentraland.org')`

    **Important Notes:**
    - Only one request can exist per socket at a time. A new request invalidates previous ones.
    - If a socket disconnects, all requests made by that socket are deleted.
    - Requests expire after the configured time (default: 5 minutes).
  protocol: socket.io
  events:
    request:
      description: |
        Create authentication request (client→server).

        Used by the desktop client to request execution of a wallet method.
        The server validates the request and returns a request ID with expiration.

        **Response Handling:**
        Use `socket.emitWithAck()` to send and receive the response:
        ```typescript
        const response = await socket.emitWithAck('request', {
          method: 'personal_sign',
          params: ['message', 'address'],
          authChain: [...]
        })
        ```
      message:
        $ref: '#/components/schemas/RequestMessage'
      response:
        oneOf:
          - $ref: '#/components/schemas/RequestResponseMessage'
          - $ref: '#/components/schemas/InvalidResponseMessage'
      validation:
        description: |
          Validates request structure and auth chain:
          - Validates JSON schema using Ajv
          - For methods other than `dcl_personal_sign`, validates that authChain is present
          - Validates authChain signature using @dcl/crypto Authenticator
          - Checks that ephemeral address can be extracted from authChain
    recover:
      description: |
        Recover existing request (client→server).

        Used by the auth dapp to retrieve request details for execution.
        The request must exist and not be expired.
      message:
        type: object
        properties:
          requestId:
            type: string
            format: uuid
            description: Request ID to recover
        required:
          - requestId
      response:
        oneOf:
          - $ref: '#/components/schemas/RecoverResponseMessage'
          - $ref: '#/components/schemas/InvalidResponseMessage'
    outcome:
      description: |
        Submit request outcome (client→server) and receive response (server→client).

        **Sending Outcome (auth dapp → server):**
        The auth dapp sends the outcome after executing the request.
        The message should include either `result` (success) or `error` (failure).

        **Receiving Outcome (server → desktop client):**
        After receiving an outcome, if the original request was made via WebSocket, 
        the server emits an `outcome` event to the original requester with the complete outcome message.

        If the original request was made via HTTP, the outcome is stored and retrieved via polling.
      message:
        type: object
        properties:
          requestId:
            type: string
            format: uuid
            description: Request ID
          sender:
            type: string
            description: Address that executed the request
          result:
            description: Success result (any JSON-serializable type). Required if error is not present.
          error:
            $ref: '#/components/schemas/OutcomeError'
            description: Error details. Required if result is not present.
        required:
          - requestId
          - sender
        oneOf:
          - required:
              - result
          - required:
              - error
      response:
        type: object
        description: Empty acknowledgment object
        properties: {}
      emits:
        - description: Emitted to original requester (if request was made via WebSocket)
          event: outcome
          message:
            $ref: '#/components/schemas/OutcomeResponseMessage'
    request-validation-status:
      description: |
        Notify that a request requires validation (auth dapp → server).  
        If the original request was made over WebSocket and the client is connected, the server relays a `request-validation-status` message to that client with the `requestId` and `code`.
      message:
        type: object
        properties:
          requestId:
            type: string
            format: uuid
            description: Request ID
        required:
          - requestId
      response:
        oneOf:
          - type: object
            description: Empty acknowledgment object
            properties: {}
          - $ref: '#/components/schemas/InvalidResponseMessage'
      emits:
        - description: Emitted to original requester (if request was made via WebSocket)
          event: request-validation-status
          message:
            type: object
            properties:
              requestId:
                type: string
                format: uuid
              code:
                type: number
                description: Request verification code
            required:
              - requestId
              - code
  authentication:
    type: ethereum-signature
    description: |
      Ethereum signature validation via @dcl/crypto Authenticator.
      - For non-dcl_personal_sign methods, authChain is validated on request creation
      - Signature validation ensures the request is authorized by the wallet owner
  cors:
    description: |
      CORS configuration via environment variables:
      - CORS_ORIGIN: Comma-separated list of allowed origins (supports regex patterns)
      - CORS_METHODS: Allowed HTTP methods
  expiration:
    description: |
      Request expiration configurable via `requestExpirationInSeconds` (default: 300 seconds / 5 minutes).
      Requests cannot be consumed after expiration.
