openapi: 3.1.0
info:
  title: Atomic Flash Desk
  version: "1.0.0"
  description: >-
    Counterparty API for Atomic Flash Loans. Read facility state, simulate a flash-loan drawing
    against live chain state, and request the signed authorisation for a drawing the user is about
    to send from their own address. The desk never sends transactions; the user signs.
servers:
  - url: https://desk-api.atomicexchange.cloud
security:
  - deskKey: []
paths:
  /healthz:
    get:
      operationId: getDeskHealth
      summary: Whether the desk can sign right now, per chain
      security: []
      responses:
        "200":
          description: Desk health
          content:
            application/json:
              schema: { type: object, additionalProperties: true }
  /v1/desk/networks:
    get:
      operationId: listNetworks
      summary: Chains served, assets the desk can price (with decimals), executor address, capabilities
      security: []
      responses:
        "200":
          description: Networks
          content:
            application/json:
              schema: { type: object, additionalProperties: true }
  /v1/desk/facility:
    get:
      operationId: getFacility
      summary: The caller's facility - headroom, open authorisations, and the fee rate on the next drawing
      responses:
        "200":
          description: Facility state. Cent amounts are strings.
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Facility" }
        "401": { $ref: "#/components/responses/Refusal" }
  /v1/desk/simulate:
    post:
      operationId: simulateDrawing
      summary: Run a drawing against live state with a real signature. Reserves nothing; safe to repeat.
      description: >-
        Returns wouldSettle true/false/null. null means the simulation could not run (not a
        failure). feeBps with feeBpsSource "your rate" is what authorise would sign now.
      x-openai-isConsequential: false
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/Drawing" }
      responses:
        "200":
          description: Simulation result
          content:
            application/json:
              schema: { type: object, additionalProperties: true }
        "400": { $ref: "#/components/responses/Refusal" }
        "401": { $ref: "#/components/responses/Refusal" }
        "503": { $ref: "#/components/responses/Refusal" }
  /v1/desk/authorize:
    post:
      operationId: authorizeDrawing
      summary: Issue a real single-use authorisation. Reserves a slot and facility headroom until used or expired.
      description: >-
        Only call after the user confirms they are about to send this drawing. Always set
        idempotencyKey. Returns transaction {to,data,value} for the user to sign from their own
        caller address, willSettle, feeBps and deadline.
      x-openai-isConsequential: true
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
                - $ref: "#/components/schemas/Drawing"
              required: [idempotencyKey]
      responses:
        "200":
          description: Authorisation and ready-to-sign transaction
          content:
            application/json:
              schema: { type: object, additionalProperties: true }
        "400": { $ref: "#/components/responses/Refusal" }
        "401": { $ref: "#/components/responses/Refusal" }
        "403": { $ref: "#/components/responses/Refusal" }
        "429": { $ref: "#/components/responses/Refusal" }
        "503": { $ref: "#/components/responses/Refusal" }
components:
  securitySchemes:
    deskKey:
      type: http
      scheme: bearer
  responses:
    Refusal:
      description: A desk refusal. `error` is a stable code; `hint` says how to clear it.
      content:
        application/json:
          schema:
            type: object
            properties:
              error: { type: string }
              message: { type: string }
              hint: { type: string }
            additionalProperties: true
  schemas:
    Action:
      type: object
      required: [target]
      properties:
        target: { type: string, description: "Contract to call. Not the source, the executor, or 0x0." }
        approve: { type: string, description: "Optional token to approve to target first; 0x0 for none." }
        approveAmount: { type: string, description: "Exact approval amount, base units. Never infinite." }
        value: { type: string, description: "Native value to forward, usually \"0\"." }
        balanceToken: { type: string, description: "0x0 = use data verbatim; else splice the executor's live balance of this token into data." }
        dataOffset: { type: integer, description: "Byte offset of the 32-byte word to overwrite, past the 4-byte selector." }
        data: { type: string, description: "0x-prefixed calldata." }
    Position:
      type: object
      required: [token, minAmount]
      properties:
        token: { type: string }
        minAmount: { type: string }
        owner: { type: string, description: "Whose balance is measured; 0x0 = the caller." }
    Drawing:
      type: object
      required: [chainId, asset, amount, actions]
      properties:
        chainId: { type: integer, description: "1, 8453, 56 or 137 - read listNetworks." }
        asset: { type: string, description: "Token borrowed; must be in listNetworks assets for the chain." }
        amount: { type: string, description: "Integer string in the asset's base units (use its decimals)." }
        actions: { type: array, items: { $ref: "#/components/schemas/Action" } }
        positions: { type: array, items: { $ref: "#/components/schemas/Position" }, description: "Only for drawings that end holding a position." }
        sweepTokens: { type: array, items: { type: string }, description: "Every other token the actions may leave behind." }
        minProfit: { type: string, description: "Floor after the desk fee, base units. Derive from feeBps." }
        pool: { type: string, description: "Omit - the desk selects the cheapest source that can fund the size." }
        feeBps: { type: integer, description: "Simulate only, as a what-if. Omit to use the real rate." }
        idempotencyKey: { type: string, description: "Authorize: reuse the same key on retry so nothing is reserved twice." }
    Facility:
      type: object
      properties:
        caller: { type: string, description: "The only address that can send drawings authorised for this facility." }
        status: { type: string }
        month: { type: string }
        drawnCents: { type: string }
        outstandingCents: { type: string }
        outstandingCount: { type: integer }
        limitCents: { type: string }
        maxNotionalCents: { type: string }
        maxConcurrentAuths: { type: integer }
        band: { type: string }
        tierBpsNow: { type: integer }
        rateFloorBps: { type: integer }
        effectiveBpsOnNextDraw: { type: integer }
        centsToNextBand: { type: [string, "null"] }
        index: { type: object, additionalProperties: true }
      additionalProperties: true
