openapi: 3.1.0
info:
  title: XDCID API
  version: 1.4.0
  description: |
    Versioned XDCID resolution, pricing, signed-quote, subdomain, and Pay Link
    APIs. Versioned endpoints include the API version in both the URL and every
    application JSON response. Pay Link storage endpoints use compact raw JSON
    responses and never accept a private key.
servers:
  - url: /
    description: Current XDCID deployment
tags:
  - name: Names
  - name: Reverse resolution
  - name: Wallet names
  - name: Pricing
  - name: Registration quotes
  - name: Subdomain quotes
  - name: Pay Links
  - name: XDC AI gateway
paths:
  /api/v1/names/{name}:
    get:
      operationId: getName
      summary: Resolve and inspect an XDCID name
      description: |
        Accepts a bare label or a canonical .xdc name. Returns canonical name
        data, forward resolution, availability, registration status, pricing,
        expiry, and profile records.
      tags:
        - Names
      parameters:
        - name: name
          in: path
          required: true
          description: Bare label or .xdc name.
          schema:
            type: string
          examples:
            bare:
              value: alice
            canonical:
              value: alice.xdc
        - name: years
          in: query
          required: false
          description: Number of registration years used for the price quote.
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 1
      responses:
        "200":
          description: Name data returned.
          headers:
            Cache-Control:
              $ref: "#/components/headers/CacheControl"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/NameResponse"
        "400":
          description: The name or years value is invalid.
          headers:
            Cache-Control:
              $ref: "#/components/headers/CacheControl"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorResponse"
              examples:
                invalidName:
                  value:
                    version: v1
                    error:
                      code: INVALID_NAME
                      message: Invalid XDCID name
                invalidYears:
                  value:
                    version: v1
                    error:
                      code: INVALID_YEARS
                      message: years must be an integer between 1 and 100
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/RpcUnavailable"
  /api/v1/reverse/{address}:
    get:
      operationId: getReverseName
      summary: Reverse-resolve an XDC address
      description: |
        Returns the verified primary name for an address. The name is null when
        no record exists or the stored reverse record no longer matches the
        current name owner.
      tags:
        - Reverse resolution
      parameters:
        - name: address
          in: path
          required: true
          description: EVM-compatible XDC address.
          schema:
            $ref: "#/components/schemas/Address"
      responses:
        "200":
          description: Reverse-resolution result returned.
          headers:
            Cache-Control:
              $ref: "#/components/headers/CacheControl"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ReverseResponse"
        "400":
          description: The address is invalid.
          headers:
            Cache-Control:
              $ref: "#/components/headers/CacheControl"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiErrorResponse"
              example:
                version: v1
                error:
                  code: INVALID_ADDRESS
                  message: address must be a valid EVM address
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/RpcUnavailable"
  /api/v1/addresses/{address}/names:
    get:
      operationId: getOwnedNames
      summary: List all active XDCID names owned by an address
      description: |
        Discovers registrations through XDCScan, then verifies current
        ownership and expiry directly against the XDCID registry. The response
        includes the address's verified primary ID and every active owned name.
      tags:
        - Wallet names
      parameters:
        - name: address
          in: path
          required: true
          description: EVM-compatible XDC address.
          schema:
            $ref: "#/components/schemas/Address"
      responses:
        "200":
          description: Verified primary ID and owned names returned.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/OwnedNamesResponse"
        "400":
          $ref: "#/components/responses/InvalidRequest"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/IndexUnavailable"
  /api/xdcai/v1/resolve/{name}:
    get:
      operationId: getGatewayResolution
      summary: Resolve an XDCID name
      description: Protected upstream endpoint for the paid XDC AI capability.
      tags:
        - XDC AI gateway
      security:
        - XdcAiGatewayKey: []
      parameters:
        - name: name
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Ownership, forward resolution, and expiry returned.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ResolveResponse"
        "400":
          $ref: "#/components/responses/InvalidRequest"
        "401":
          $ref: "#/components/responses/GatewayUnauthorized"
        "503":
          $ref: "#/components/responses/GatewayServiceUnavailable"
  /api/xdcai/v1/reverse/{address}:
    get:
      operationId: getGatewayReverseResolution
      summary: Reverse-resolve an XDC address
      description: Protected upstream endpoint for the paid XDC AI capability.
      tags:
        - XDC AI gateway
      security:
        - XdcAiGatewayKey: []
      parameters:
        - name: address
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Address"
      responses:
        "200":
          description: Verified reverse-resolution result returned.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ReverseResponse"
        "400":
          $ref: "#/components/responses/InvalidRequest"
        "401":
          $ref: "#/components/responses/GatewayUnauthorized"
        "503":
          $ref: "#/components/responses/GatewayServiceUnavailable"
  /api/xdcai/v1/owned-names/{address}:
    get:
      operationId: getGatewayOwnedNames
      summary: List all active XDCID names owned by an address
      description: Protected upstream endpoint for the paid XDC AI capability.
      tags:
        - XDC AI gateway
      security:
        - XdcAiGatewayKey: []
      parameters:
        - name: address
          in: path
          required: true
          schema:
            $ref: "#/components/schemas/Address"
      responses:
        "200":
          description: Verified primary ID and owned names returned.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/OwnedNamesResponse"
        "400":
          $ref: "#/components/responses/InvalidRequest"
        "401":
          $ref: "#/components/responses/GatewayUnauthorized"
        "503":
          $ref: "#/components/responses/GatewayServiceUnavailable"
  /api/xdcai/v1/availability/{name}:
    get:
      operationId: getGatewayAvailability
      summary: Check availability and pricing
      description: Protected upstream endpoint for the paid XDC AI capability.
      tags:
        - XDC AI gateway
      security:
        - XdcAiGatewayKey: []
      parameters:
        - name: name
          in: path
          required: true
          schema:
            type: string
        - name: years
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 1
      responses:
        "200":
          description: Availability, expiry, and pricing returned.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AvailabilityResponse"
        "400":
          $ref: "#/components/responses/InvalidRequest"
        "401":
          $ref: "#/components/responses/GatewayUnauthorized"
        "503":
          $ref: "#/components/responses/GatewayServiceUnavailable"
  /api/xdcai/v1/profile/{name}:
    get:
      operationId: getGatewayProfile
      summary: Read XDCID profile records
      description: Protected upstream endpoint for the paid XDC AI capability.
      tags:
        - XDC AI gateway
      security:
        - XdcAiGatewayKey: []
      parameters:
        - name: name
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Profile records returned.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProfileResponse"
        "400":
          $ref: "#/components/responses/InvalidRequest"
        "401":
          $ref: "#/components/responses/GatewayUnauthorized"
        "503":
          $ref: "#/components/responses/GatewayServiceUnavailable"
  /api/v1/pricing/quote:
    get:
      operationId: getPricingQuote
      summary: Get an informational policy price
      description: Returns the current USD policy price and a buffered XDC estimate. This response cannot authorize a contract payment.
      tags:
        - Pricing
      parameters:
        - name: product
          in: query
          required: true
          schema:
            type: string
            enum: [registration, renewal, subdomain, migration]
        - name: name
          in: query
          required: false
          description: Required for registration and renewal products.
          schema:
            type: string
        - name: years
          in: query
          required: false
          description: Required except for migration.
          schema:
            type: integer
            enum: [1, 3, 5, 10]
      responses:
        "200":
          description: Informational price returned.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PricingQuoteResponse"
        "400":
          $ref: "#/components/responses/InvalidRequest"
        "503":
          $ref: "#/components/responses/RpcUnavailable"
  /api/v1/registrar/quote:
    post:
      operationId: createRegistrarQuote
      summary: Create a short-lived registration or renewal quote
      description: |
        Returns a ten-minute EIP-712 quote bound to the payer, owner, name,
        registrar, chain, policy version, and next nonce. The endpoint is
        available only after the registrar, policy, RPC, CoinGecko, and
        server-side signer settings are configured.
      tags:
        - Registration quotes
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required:
                - name
                - product
                - termYears
                - paymentCurrency
                - payer
                - nameOwner
              properties:
                name:
                  type: string
                  examples:
                    - alice.xdc
                product:
                  type: string
                  enum:
                    - registration
                    - renewal
                termYears:
                  type: integer
                  enum:
                    - 1
                    - 3
                    - 5
                    - 10
                paymentCurrency:
                  type: string
                  enum:
                    - XDC
                    - USDC
                payer:
                  $ref: "#/components/schemas/Address"
                nameOwner:
                  $ref: "#/components/schemas/Address"
      responses:
        "200":
          description: Signed quote returned.
          content:
            application/json:
              schema:
                type: object
                required:
                  - version
                  - data
                properties:
                  version:
                    type: string
                    const: v1
                  data:
                    type: object
                    required:
                      - authorizedForPayment
                      - chainId
                      - registrar
                      - policy
                      - product
                      - name
                      - paymentCurrency
                      - quote
                      - signature
                    properties:
                      authorizedForPayment:
                        type: boolean
                        const: true
                      chainId:
                        type: integer
                      registrar:
                        $ref: "#/components/schemas/Address"
                      policy:
                        $ref: "#/components/schemas/Address"
                      product:
                        type: string
                        enum:
                          - registration
                          - renewal
                      name:
                        type: string
                      paymentCurrency:
                        type: string
                        enum:
                          - XDC
                          - USDC
                      quote:
                        type: object
                      signature:
                        type: string
                        pattern: "^0x[a-fA-F0-9]+$"
                      market:
                        type:
                          - object
                          - "null"
        "400":
          description: Invalid request.
        "403":
          description: The payer is not authorized to renew the name.
        "409":
          description: The requested registration name is unavailable.
        "429":
          description: Quote request rate limit exceeded.
        "503":
          description: Quote signing, RPC, policy, or pricing is unavailable.
  /api/v1/subdomain/quote:
    post:
      operationId: createSubdomainQuote
      summary: Create a short-lived subdomain registration or renewal quote
      description: Checks the parent owner/operator, subdomain state, and parent expiry before returning an EIP-712 quote.
      tags:
        - Subdomain quotes
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required: [parentName, label, action, termYears, paymentCurrency, payer, subdomainOwner]
              properties:
                parentName:
                  type: string
                  examples: [company.xdc]
                label:
                  type: string
                  examples: [alice]
                action:
                  type: string
                  enum: [registration, renewal]
                termYears:
                  type: integer
                  enum: [1, 3, 5, 10]
                paymentCurrency:
                  type: string
                  enum: [XDC, USDC]
                payer:
                  $ref: "#/components/schemas/Address"
                subdomainOwner:
                  $ref: "#/components/schemas/Address"
      responses:
        "200":
          description: Signed subdomain quote returned.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SubdomainQuoteResponse"
        "400":
          $ref: "#/components/responses/InvalidRequest"
        "403":
          description: The payer is not an authorized parent or subdomain controller.
        "409":
          description: The name is unavailable or the requested term exceeds the parent expiry.
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          description: Quote signing, RPC, policy, or pricing is unavailable.
  /api/pay-links:
    post:
      operationId: createPayLink
      summary: Store an already signed payment request
      description: Returns a short path and a one-time private revocation token. The request signature is verified against the current XDCID owner.
      tags:
        - Pay Links
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required: [request, signature]
              properties:
                request:
                  type: string
                  pattern: "^0x[a-fA-F0-9]+$"
                signature:
                  type: string
                  pattern: "^0x[a-fA-F0-9]+$"
      responses:
        "201":
          description: Short Pay Link created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreatedPayLink"
        "400":
          description: The signed payment request is malformed.
        "403":
          description: The request is not signed by the current XDCID owner.
        "503":
          description: Pay Link storage is unavailable.
  /api/pay-links/{id}:
    get:
      operationId: getPayLink
      summary: Read a short Pay Link
      tags:
        - Pay Links
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Active Pay Link returned.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ActivePayLink"
        "404":
          description: Pay Link not found.
        "410":
          description: Pay Link was paid, revoked, or expired. Paid responses include the payment ID when available.
    delete:
      operationId: revokePayLink
      summary: Revoke a short Pay Link
      description: Requires the private revocation token returned only at creation time.
      tags:
        - Pay Links
      security:
        - PayLinkRevocationToken: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Pay Link revoked.
        "401":
          description: Revocation token missing.
        "403":
          description: Revocation token invalid.
        "404":
          description: Pay Link not found.
  /api/pay-links/cancellations/{requestId}:
    get:
      operationId: getPayLinkStatus
      summary: Read payment-request status
      description: Safe polling endpoint for updating a payer or payee UI when a request becomes paid or cancelled.
      tags:
        - Pay Links
      parameters:
        - name: requestId
          in: path
          required: true
          schema:
            type: string
            pattern: "^0x[a-fA-F0-9]{64}$"
      responses:
        "200":
          description: Current request status returned.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PayLinkStatus"
        "400":
          description: Invalid request ID.
        "503":
          description: Pay Link status storage is unavailable.
components:
  securitySchemes:
    XdcAiGatewayKey:
      type: apiKey
      in: header
      name: X-XDCID-Gateway-Key
      description: Server-only key injected by the XDC AI Gateway.
    PayLinkRevocationToken:
      type: http
      scheme: bearer
      description: One-time private token returned when the short Pay Link is created.
  headers:
    CacheControl:
      description: Application responses are not stored by shared or browser caches.
      schema:
        type: string
        const: no-store
    RetryAfter:
      description: Seconds until the client may retry.
      schema:
        type: integer
        minimum: 1
  responses:
    InvalidRequest:
      description: A path or query value is invalid.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ApiErrorResponse"
    GatewayUnauthorized:
      description: The gateway key is missing or invalid.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ApiErrorResponse"
          example:
            version: v1
            error:
              code: UNAUTHORIZED
              message: Invalid gateway credentials
    GatewayServiceUnavailable:
      description: The gateway key is not configured or XDC RPC is unavailable.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ApiErrorResponse"
    RateLimited:
      description: |
        The Vercel edge rate limit was exceeded. Because this response is
        generated before the application route runs, its body is
        platform-managed and is not part of the versioned JSON envelope.
      headers:
        Retry-After:
          $ref: "#/components/headers/RetryAfter"
    IndexUnavailable:
      description: XDCScan indexing or configured XDC RPC access is unavailable.
      headers:
        Cache-Control:
          $ref: "#/components/headers/CacheControl"
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ApiErrorResponse"
    RpcUnavailable:
      description: All configured XDC RPC providers were unavailable.
      headers:
        Cache-Control:
          $ref: "#/components/headers/CacheControl"
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ApiErrorResponse"
          example:
            version: v1
            error:
              code: XDC_RPC_UNAVAILABLE
              message: Unable to read the XDC Network
  schemas:
    PricingQuoteResponse:
      type: object
      required: [version, data]
      properties:
        version:
          $ref: "#/components/schemas/ApiVersion"
        data:
          type: object
          required: [authorizedForPayment, warning, policyVersion, product, pricing, xdc]
          properties:
            authorizedForPayment:
              type: boolean
              const: false
            warning:
              type: string
            policyVersion:
              type: integer
            product:
              type: string
              enum: [registration, renewal, subdomain, migration]
            name:
              type: [string, "null"]
            years:
              type: [integer, "null"]
            pricing:
              type: object
              required: [currency, annualMicros, grossMicros, discountBps, totalMicros]
              properties:
                currency:
                  type: string
                  const: USD
                annualMicros:
                  type: [string, "null"]
                grossMicros:
                  type: string
                discountBps:
                  type: string
                totalMicros:
                  type: string
            xdc:
              type: object
              required: [wei, xdc, bufferBps, marketPriceUsdMicros, provider, observedAt, fetchedAt]
              properties:
                wei:
                  type: string
                xdc:
                  type: string
                bufferBps:
                  type: string
                marketPriceUsdMicros:
                  type: string
                provider:
                  type: string
                coinId:
                  type: string
                observedAt:
                  type: string
                  format: date-time
                fetchedAt:
                  type: string
                  format: date-time
    SubdomainQuoteResponse:
      type: object
      required: [version, data]
      properties:
        version:
          $ref: "#/components/schemas/ApiVersion"
        data:
          type: object
          required: [authorizedForPayment, chainId, registrar, pricingPolicy, action, parentName, label, fullName, paymentCurrency, quote, signature]
          properties:
            authorizedForPayment:
              type: boolean
              const: true
            chainId:
              type: integer
              const: 50
            registrar:
              $ref: "#/components/schemas/Address"
            pricingPolicy:
              $ref: "#/components/schemas/Address"
            action:
              type: string
              enum: [registration, renewal]
            parentName:
              type: string
            label:
              type: string
            fullName:
              type: string
            paymentCurrency:
              type: string
              enum: [XDC, USDC]
            quote:
              type: object
            signature:
              type: string
              pattern: "^0x[a-fA-F0-9]+$"
            market:
              type: [object, "null"]
    CreatedPayLink:
      type: object
      additionalProperties: false
      required: [id, path, expiresAt, revocationToken]
      properties:
        id:
          type: string
        path:
          type: string
        expiresAt:
          type: string
          format: date-time
        revocationToken:
          type: string
          description: Private bearer token returned only at creation time.
    ActivePayLink:
      type: object
      additionalProperties: false
      required: [id, name, status, request, signature, expiresAt]
      properties:
        id:
          type: string
        name:
          type: string
        status:
          type: string
          const: active
        request:
          type: string
          pattern: "^0x[a-fA-F0-9]+$"
        signature:
          type: string
          pattern: "^0x[a-fA-F0-9]+$"
        expiresAt:
          type: string
          format: date-time
    PayLinkStatus:
      type: object
      additionalProperties: false
      required: [requestId, cancelled, paid, status]
      properties:
        requestId:
          type: string
          pattern: "^0x[a-fA-F0-9]{64}$"
        cancelled:
          type: boolean
        paid:
          type: boolean
        status:
          type: string
          enum: [active, cancelled, paid]
    ApiVersion:
      type: string
      enum:
        - v1
    Address:
      type: string
      pattern: "^0x[a-fA-F0-9]{40}$"
      examples:
        - "0xe82a4267CC310FC6Db334601671A043DFc8Ce06A"
    NameResponse:
      type: object
      additionalProperties: false
      required:
        - version
        - data
      properties:
        version:
          $ref: "#/components/schemas/ApiVersion"
        data:
          $ref: "#/components/schemas/NameData"
    ReverseResponse:
      type: object
      additionalProperties: false
      required:
        - version
        - data
      properties:
        version:
          $ref: "#/components/schemas/ApiVersion"
        data:
          $ref: "#/components/schemas/ReverseData"
    OwnedNamesResponse:
      type: object
      additionalProperties: false
      required:
        - version
        - data
      properties:
        version:
          $ref: "#/components/schemas/ApiVersion"
        data:
          $ref: "#/components/schemas/OwnedNamesData"
    OwnedNamesData:
      type: object
      additionalProperties: false
      required:
        - address
        - network
        - primaryName
        - names
      properties:
        address:
          $ref: "#/components/schemas/Address"
        network:
          $ref: "#/components/schemas/NameData/properties/network"
        primaryName:
          type:
            - string
            - "null"
          description: Verified canonical primary .xdc name, or null.
        names:
          type: array
          items:
            $ref: "#/components/schemas/OwnedName"
    OwnedName:
      type: object
      additionalProperties: false
      required:
        - name
        - node
        - primary
        - expiry
      properties:
        name:
          type: string
          description: Canonical lowercase name ending in .xdc.
        node:
          type: string
          pattern: "^0x[a-fA-F0-9]{64}$"
        primary:
          type: boolean
        expiry:
          type: object
          additionalProperties: false
          required:
            - timestamp
            - iso
          properties:
            timestamp:
              type: string
              pattern: "^[0-9]+$"
            iso:
              type: string
              format: date-time
    ApiErrorResponse:
      type: object
      additionalProperties: false
      required:
        - version
        - error
      properties:
        version:
          $ref: "#/components/schemas/ApiVersion"
        error:
          type: object
          additionalProperties: false
          required:
            - code
            - message
          properties:
            code:
              type: string
              enum:
                - INVALID_NAME
                - INVALID_ADDRESS
                - INVALID_YEARS
                - UNAUTHORIZED
                - NOT_FOUND
                - GATEWAY_UNAVAILABLE
                - XDC_INDEX_UNAVAILABLE
                - XDC_RPC_UNAVAILABLE
            message:
              type: string
    ResolveResponse:
      type: object
      additionalProperties: false
      required:
        - version
        - data
      properties:
        version:
          $ref: "#/components/schemas/ApiVersion"
        data:
          $ref: "#/components/schemas/ResolveData"
    AvailabilityResponse:
      type: object
      additionalProperties: false
      required:
        - version
        - data
      properties:
        version:
          $ref: "#/components/schemas/ApiVersion"
        data:
          $ref: "#/components/schemas/AvailabilityData"
    ProfileResponse:
      type: object
      additionalProperties: false
      required:
        - version
        - data
      properties:
        version:
          $ref: "#/components/schemas/ApiVersion"
        data:
          $ref: "#/components/schemas/ProfileData"
    ResolveData:
      type: object
      additionalProperties: false
      required:
        - name
        - label
        - node
        - network
        - registered
        - owner
        - resolvedAddress
        - expiry
      properties:
        name:
          $ref: "#/components/schemas/NameData/properties/name"
        label:
          $ref: "#/components/schemas/NameData/properties/label"
        node:
          $ref: "#/components/schemas/NameData/properties/node"
        network:
          $ref: "#/components/schemas/NameData/properties/network"
        registered:
          $ref: "#/components/schemas/NameData/properties/registered"
        owner:
          $ref: "#/components/schemas/NameData/properties/owner"
        resolvedAddress:
          $ref: "#/components/schemas/NameData/properties/resolvedAddress"
        expiry:
          $ref: "#/components/schemas/NameData/properties/expiry"
    AvailabilityData:
      type: object
      additionalProperties: false
      required:
        - name
        - label
        - node
        - network
        - available
        - registered
        - expiry
        - pricing
      properties:
        name:
          $ref: "#/components/schemas/NameData/properties/name"
        label:
          $ref: "#/components/schemas/NameData/properties/label"
        node:
          $ref: "#/components/schemas/NameData/properties/node"
        network:
          $ref: "#/components/schemas/NameData/properties/network"
        available:
          $ref: "#/components/schemas/NameData/properties/available"
        registered:
          $ref: "#/components/schemas/NameData/properties/registered"
        expiry:
          $ref: "#/components/schemas/NameData/properties/expiry"
        pricing:
          $ref: "#/components/schemas/Pricing"
    ProfileData:
      type: object
      additionalProperties: false
      required:
        - name
        - label
        - node
        - network
        - registered
        - owner
        - profile
      properties:
        name:
          $ref: "#/components/schemas/NameData/properties/name"
        label:
          $ref: "#/components/schemas/NameData/properties/label"
        node:
          $ref: "#/components/schemas/NameData/properties/node"
        network:
          $ref: "#/components/schemas/NameData/properties/network"
        registered:
          $ref: "#/components/schemas/NameData/properties/registered"
        owner:
          $ref: "#/components/schemas/NameData/properties/owner"
        profile:
          $ref: "#/components/schemas/Profile"
    NameData:
      type: object
      additionalProperties: false
      required:
        - name
        - label
        - node
        - network
        - available
        - registered
        - owner
        - resolvedAddress
        - expiry
        - pricing
        - profile
      properties:
        name:
          type: string
          description: Canonical lowercase name ending in .xdc.
          examples:
            - alice.xdc
        label:
          type: string
          description: Canonical lowercase label without the .xdc suffix.
          examples:
            - alice
        node:
          type: string
          pattern: "^0x[a-fA-F0-9]{64}$"
          description: keccak256 hash of the canonical name.
        network:
          type: object
          additionalProperties: false
          required:
            - chainId
            - name
          properties:
            chainId:
              type: integer
              const: 50
            name:
              type: string
        available:
          type: boolean
        registered:
          type: boolean
        owner:
          anyOf:
            - $ref: "#/components/schemas/Address"
            - type: "null"
        resolvedAddress:
          anyOf:
            - $ref: "#/components/schemas/Address"
            - type: "null"
        expiry:
          type: object
          additionalProperties: false
          required:
            - timestamp
            - iso
          properties:
            timestamp:
              type:
                - string
                - "null"
              pattern: "^[0-9]+$"
              description: Unix timestamp in seconds, encoded as a decimal string.
            iso:
              type:
                - string
                - "null"
              format: date-time
        pricing:
          $ref: "#/components/schemas/Pricing"
        profile:
          $ref: "#/components/schemas/Profile"
    ReverseData:
      type: object
      additionalProperties: false
      required:
        - address
        - name
        - verified
      properties:
        address:
          $ref: "#/components/schemas/Address"
        name:
          type:
            - string
            - "null"
          description: Verified canonical .xdc name, or null.
        verified:
          type: boolean
    Pricing:
      type: object
      additionalProperties: false
      required:
        - currency
        - years
        - perYear
        - total
      properties:
        currency:
          type: string
          const: XDC
        years:
          type: integer
          minimum: 1
          maximum: 100
        perYear:
          $ref: "#/components/schemas/Amount"
        total:
          $ref: "#/components/schemas/Amount"
    Amount:
      type: object
      additionalProperties: false
      required:
        - wei
        - xdc
      properties:
        wei:
          type: string
          pattern: "^[0-9]+$"
        xdc:
          type: string
          pattern: ^[0-9]+([.][0-9]+)?$
    Profile:
      type: object
      additionalProperties: false
      required:
        - avatar
        - website
        - twitter
        - telegram
        - bio
      properties:
        avatar:
          $ref: "#/components/schemas/NullableProfileValue"
        website:
          $ref: "#/components/schemas/NullableProfileValue"
        twitter:
          $ref: "#/components/schemas/NullableProfileValue"
        telegram:
          $ref: "#/components/schemas/NullableProfileValue"
        bio:
          $ref: "#/components/schemas/NullableProfileValue"
    NullableProfileValue:
      type:
        - string
        - "null"
