openapi: 3.0.3 info: title: Ava Protocol AVS Auth Nodes API version: 1.0.0 description: 'Public REST API for the Ava Protocol AVS aggregator. Exposes workflow creation, execution monitoring, smart-wallet management, and related operations. Authentication is a single credential type — a JWT bearer token — obtained either via the wallet-signing flow (`POST /auth:exchange`) or out-of-band via the operator-run `create-api-key` CLI. Every request must include `Authorization: Bearer `. ' servers: - url: https://gateway.avaprotocol.org/api/v1 description: Production gateway - url: https://gateway-staging.avaprotocol.org/api/v1 description: Staging gateway - url: http://localhost:8080/api/v1 description: Local dev security: - bearerAuth: [] tags: - name: Nodes description: Stand-alone node execution paths: /nodes:run: post: tags: - Nodes summary: Execute a single node with inline input variables description: 'Useful for SDK testing flows — run a node definition against provided input variables without persisting a workflow. Honors `node.config.chainId` (overrides body `chainId`). ' operationId: runNode requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/RunNodeRequest' responses: '200': description: Node execution result. content: application/json: schema: $ref: '#/components/schemas/RunNodeResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' components: schemas: EventTriggerQuery: type: object description: Single ethereum.FilterQuery — one subscription per query. properties: addresses: type: array items: $ref: '#/components/schemas/EthereumAddress' description: Contract addresses to filter events from. Empty matches any contract. topics: type: array items: type: string nullable: true description: 'Topic filters (`topics[0]` is the event signature, `topics[1..]` are indexed parameter values). `null` means wildcard at that position. ' maxEventsPerBlock: type: integer format: int32 description: Safety ceiling per query per block. Exceeded → task cancelled. contractAbi: type: array items: additionalProperties: true description: Contract ABI entries (JSON form) for event decoding. conditions: type: array items: $ref: '#/components/schemas/EventCondition' description: Filters applied to decoded event data. methodCalls: type: array items: $ref: '#/components/schemas/EventMethodCall' description: Method calls used to enrich decoded event data (e.g., `decimals`). EventCondition: type: object description: Predicate evaluated against decoded event data. required: - fieldName - operator - value properties: fieldName: type: string operator: type: string enum: - eq - ne - gt - gte - lt - lte - contains value: type: string description: 'Value to compare against, encoded as a string. The operator parses it according to `fieldType` (e.g. `int256` / `uint256` → big.Int, `address` → checksummed hex, `bool` → "true"/"false"). Matches the proto `EventCondition.value`, which is also a string. ' fieldType: type: string FilterNodeConfig: type: object required: - inputVariable - expression properties: inputVariable: type: string description: Template path for the source array (e.g., `{{custom_code1.data}}`). expression: type: string description: JavaScript predicate evaluated per item. ContractReadNode: allOf: - type: object properties: type: type: string enum: - contractRead config: $ref: '#/components/schemas/ContractReadNodeConfig' EthereumAddress: type: string pattern: ^0x[a-fA-F0-9]{40}$ description: Lowercase or checksummed hex EOA / contract address. example: '0x82F2Dd9a552a69f2ceD7Ff2D05c43aB8430158FB' InputVariables: type: object additionalProperties: true description: 'Free-form key-value bag of values used to resolve `{{variable.path}}` template references inside trigger and node configs. Conventional well-known keys: `settings.runner` (smart wallet address), `settings.chainId` (chain id). camelCase keys; back-compat support for snake_case keys exists during the migration window. ' RestAPINodeConfig: type: object required: - url - method properties: url: type: string format: uri method: type: string enum: - GET - POST - PUT - PATCH - DELETE - HEAD - OPTIONS headers: type: object additionalProperties: type: string body: type: string options: type: object description: 'Generic options bag for backend features on terminal RestAPI nodes. `summarize: true` opts a SendGrid /v3/mail/send or Telegram /sendMessage node into the aggregator''s context-memory summarizer, which composes a subject + HTML body from the workflow''s execution context and injects them into the outgoing request. Without this field set, the aggregator falls back to the deterministic summarizer (no LLM polish). ' properties: summarize: type: boolean description: 'When true on a terminal SendGrid or Telegram node, ComposeSummarySmart runs at execution time and fills in the empty content.value / text slot with an AI-generated body. No-op on non-notification URLs. ' additionalProperties: true CustomCodeNodeConfig: type: object required: - lang - source properties: lang: $ref: '#/components/schemas/Lang' source: type: string MethodCall: type: object description: One call to a contract method (used by ContractWrite + ContractRead). required: - methodName properties: methodName: type: string callData: $ref: '#/components/schemas/Hex' applyToFields: type: array items: type: string methodParams: type: array items: type: string description: Handlebars template for method args. Hex: type: string pattern: ^0x[a-fA-F0-9]*$ description: Arbitrary-length hex-encoded byte string. ETHTransferNodeConfig: type: object required: - destination - amount - chainId properties: destination: $ref: '#/components/schemas/EthereumAddress' amount: type: string description: Amount in wei (decimal string for big-int safety). Special value `max` withdraws the entire balance. chainId: $ref: '#/components/schemas/ChainId' description: Chain to execute on. Required — a workflow carries no chain to inherit. EventTriggerConfig: type: object description: Fires when matching on-chain events are observed. required: - queries - chainId properties: queries: type: array items: $ref: '#/components/schemas/EventTriggerQuery' minItems: 1 cooldownSeconds: type: integer format: int32 minimum: 0 description: 'Seconds to wait after a fire before allowing the same task to trigger again. Default 300. 0 disables cooldown. ' chainId: $ref: '#/components/schemas/ChainId' description: Chain to watch events on. Required — a workflow carries no chain to inherit. ETHTransferNode: allOf: - type: object properties: type: type: string enum: - ethTransfer config: $ref: '#/components/schemas/ETHTransferNodeConfig' BalanceNodeConfig: type: object required: - address - chain properties: address: $ref: '#/components/schemas/EthereumAddress' chain: type: string description: Chain name or numeric ID (e.g., `ethereum`, `base`, `1`, `8453`). includeSpam: type: boolean includeZeroBalances: type: boolean minUsdValueCents: type: integer format: int64 description: Filter out tokens with USD value below this many cents. tokenAddresses: type: array items: $ref: '#/components/schemas/EthereumAddress' description: Restrict to these tokens. Empty = fetch all. GraphQLQueryNode: allOf: - type: object properties: type: type: string enum: - graphqlQuery config: $ref: '#/components/schemas/GraphQLQueryNodeConfig' BranchNode: allOf: - type: object properties: type: type: string enum: - branch config: $ref: '#/components/schemas/BranchNodeConfig' LoopNode: allOf: - type: object properties: type: type: string enum: - loop config: $ref: '#/components/schemas/LoopNodeConfig' BranchNodeConfig: type: object required: - conditions properties: conditions: type: array items: $ref: '#/components/schemas/BranchCondition' minItems: 1 NodeType: type: string enum: - ethTransfer - contractWrite - contractRead - graphqlQuery - restApi - customCode - branch - filter - loop - balance - await description: 'Discriminator field for the Node union. Mirrors the proto `NodeType` enum but without the `NODE_TYPE_` prefix. ' ContractWriteNodeConfig: type: object required: - contractAddress - chainId properties: contractAddress: $ref: '#/components/schemas/EthereumAddress' callData: $ref: '#/components/schemas/Hex' contractAbi: type: array items: additionalProperties: true methodCalls: type: array items: $ref: '#/components/schemas/MethodCall' isSimulated: type: boolean description: When true, use Tenderly simulation instead of sending a real UserOp. value: type: string description: ETH value to send with the call (wei, decimal string). gasLimit: type: string description: Custom gas limit (decimal string). chainId: $ref: '#/components/schemas/ChainId' description: Chain to execute on. Required — a workflow carries no chain to inherit. Lang: type: string enum: - javascript - json - graphql - handlebars description: 'Language/format of an inline payload (e.g., custom code source, manual trigger data). Mirrors the proto `Lang` enum minus the `LANG_` prefix. Wire values are lowercase. ' FilterNode: allOf: - type: object properties: type: type: string enum: - filter config: $ref: '#/components/schemas/FilterNodeConfig' RunNodeRequest: type: object required: - node properties: node: $ref: '#/components/schemas/Node' inputVariables: $ref: '#/components/schemas/InputVariables' chainId: $ref: '#/components/schemas/ChainId' erc20Overrides: type: array description: 'Optional ERC20 balance/allowance state overrides applied only during this isolated node simulation. Lets callers seed token balances and approvals so contract-write simulations (e.g. Uniswap swaps) don''t revert with "transfer amount exceeds allowance/balance" before the approval/funding transactions have been run. Simulation-only: a real-execution request (isSimulated=false) that sets these is rejected with an error, never silently ignored. ' items: $ref: '#/components/schemas/ERC20StateOverride' ContractReadNodeConfig: type: object required: - contractAddress - chainId properties: contractAddress: $ref: '#/components/schemas/EthereumAddress' contractAbi: type: array items: additionalProperties: true methodCalls: type: array items: $ref: '#/components/schemas/MethodCall' chainId: $ref: '#/components/schemas/ChainId' description: Chain to read from. Required — a workflow carries no chain to inherit. AwaitNodeConfig: type: object description: 'Pauses the workflow until a wake arrives (durable execution). Two mutually exclusive flavors: the external-signal flavor (human approval — set `channel`, e.g. a Telegram approve/reject), or the chain-event flavor (cross-chain — set `chainEvent` to pause until an operator observes that on-chain event, e.g. a bridge arrival on another chain). Exactly one flavor must be configured. ' properties: channel: type: string description: 'External-signal flavor — signal channel: `telegram` or `api`.' approvers: type: array items: type: string description: External-signal flavor — authorized approver identities. Empty = the workflow owner. prompt: type: string description: External-signal flavor — message shown to the approver. chainEvent: allOf: - $ref: '#/components/schemas/EventTriggerConfig' description: 'Chain-event flavor — the on-chain event to wait for (a mid-workflow EventTrigger). An operator covering `chainEvent.chainId` watches it and resumes the execution when it fires. Mutually exclusive with `channel`. ' timeoutSeconds: type: integer format: int64 description: Safety bound; 0 = server default (the wait is never unbounded). AwaitNode: allOf: - type: object properties: type: type: string enum: - await config: $ref: '#/components/schemas/AwaitNodeConfig' RestAPINode: allOf: - type: object properties: type: type: string enum: - restApi config: $ref: '#/components/schemas/RestAPINodeConfig' LoopNodeConfig: type: object description: 'Iterates over an input array, running an inner Node per item. The runner node is one of the chain-aware or chain-agnostic node types; a chain-aware runner must specify its own required `chainId` (there is no inheritance from the loop or workflow). ' required: - inputVariable - runner properties: inputVariable: type: string description: Template path for the iterable (e.g., `{{settings.addressList}}`). iterVar: type: string default: value description: Name of the per-iteration variable (defaults to `value`). runner: $ref: '#/components/schemas/Node' RunNodeResponse: type: object required: - success properties: success: type: boolean error: type: string errorCode: type: string output: additionalProperties: true metadata: additionalProperties: true executionContext: additionalProperties: true BranchCondition: type: object required: - id - expression properties: id: type: string type: type: string enum: - if - elseIf - else expression: type: string description: JavaScript-evaluated boolean expression. Node: type: object required: - type - id - config properties: id: type: string name: type: string type: $ref: '#/components/schemas/NodeType' discriminator: propertyName: type mapping: ethTransfer: '#/components/schemas/ETHTransferNode' contractWrite: '#/components/schemas/ContractWriteNode' contractRead: '#/components/schemas/ContractReadNode' graphqlQuery: '#/components/schemas/GraphQLQueryNode' restApi: '#/components/schemas/RestAPINode' customCode: '#/components/schemas/CustomCodeNode' branch: '#/components/schemas/BranchNode' filter: '#/components/schemas/FilterNode' loop: '#/components/schemas/LoopNode' balance: '#/components/schemas/BalanceNode' await: '#/components/schemas/AwaitNode' oneOf: - $ref: '#/components/schemas/ETHTransferNode' - $ref: '#/components/schemas/ContractWriteNode' - $ref: '#/components/schemas/ContractReadNode' - $ref: '#/components/schemas/GraphQLQueryNode' - $ref: '#/components/schemas/RestAPINode' - $ref: '#/components/schemas/CustomCodeNode' - $ref: '#/components/schemas/BranchNode' - $ref: '#/components/schemas/FilterNode' - $ref: '#/components/schemas/LoopNode' - $ref: '#/components/schemas/BalanceNode' - $ref: '#/components/schemas/AwaitNode' BalanceNode: allOf: - type: object properties: type: type: string enum: - balance config: $ref: '#/components/schemas/BalanceNodeConfig' ContractWriteNode: allOf: - type: object properties: type: type: string enum: - contractWrite config: $ref: '#/components/schemas/ContractWriteNodeConfig' ChainId: type: integer format: int64 description: 'Numeric chain ID (e.g. 11155111 for Sepolia, 8453 for Base). On chain-aware trigger/node configs this is required and must be a configured chain; on query/filter params it is optional. ' example: 11155111 GraphQLQueryNodeConfig: type: object required: - url - query properties: url: type: string format: uri query: type: string variables: type: object additionalProperties: type: string Problem: type: object description: 'RFC 7807 problem+json. Returned as `application/problem+json` on any 4xx/5xx response. `type` and `title` describe the error class; `detail` is human-readable; `instance` is a per-request identifier suitable for log correlation. ' required: - type - title - status properties: type: type: string format: uri description: URI identifying the problem type. example: https://docs.avaprotocol.org/errors/workflow-not-found title: type: string description: Short, human-readable summary. example: Workflow not found status: type: integer format: int32 description: HTTP status code (echoed for clients that surface only the body). example: 404 detail: type: string description: Human-readable explanation specific to this occurrence. example: No workflow with id 01JG2FE5MDVKBPHEG0PEYSDKAC for owner 0xabc... instance: type: string description: URI / opaque ID identifying this specific occurrence (e.g., request id). example: req_01JG2FE5MFKTH0754RGF2DMVY7 code: type: string description: 'Machine-readable error code. Stable across releases; clients can switch on this for programmatic handling. Mirrors the gRPC-era ErrorCode enum vocabulary. ' example: WORKFLOW_NOT_FOUND EventMethodCall: type: object required: - methodName properties: methodName: type: string callData: $ref: '#/components/schemas/Hex' applyToFields: type: array items: type: string methodParams: type: array items: type: string description: Handlebars template; resolves against decoded event data. CustomCodeNode: allOf: - type: object properties: type: type: string enum: - customCode config: $ref: '#/components/schemas/CustomCodeNodeConfig' ERC20StateOverride: type: object required: - tokenAddress - ownerAddress description: 'Seeds a token''s balanceOf / allowance storage slots for a single simulation. balanceOf[owner] lives at keccak256(abi.encode(owner, balanceSlot)); allowance[owner][spender] at keccak256(abi.encode(spender, keccak256(abi.encode(owner, allowanceSlot)))). ' properties: tokenAddress: $ref: '#/components/schemas/EthereumAddress' ownerAddress: $ref: '#/components/schemas/EthereumAddress' spenderAddress: $ref: '#/components/schemas/EthereumAddress' balance: type: string description: Balance override (hex 0x… or decimal string). allowance: type: string description: Allowance override (hex 0x… or decimal string). balanceSlot: type: integer format: int64 minimum: 0 description: Storage slot for the balanceOf mapping. Required when balance is set; ERC20 storage layout varies per token (OpenZeppelin 0, USDC FiatToken 9). allowanceSlot: type: integer format: int64 minimum: 0 description: Storage slot for the allowance mapping. Required when allowance is set; ERC20 storage layout varies per token (OpenZeppelin 1, USDC FiatToken 10). responses: Unauthorized: description: Missing or invalid bearer token. content: application/problem+json: schema: $ref: '#/components/schemas/Problem' BadRequest: description: Request validation failed. content: application/problem+json: schema: $ref: '#/components/schemas/Problem' securitySchemes: bearerAuth: type: http scheme: bearer bearerFormat: JWT description: 'JWT bearer token. Obtained via `POST /auth:exchange` (wallet signature flow) or via the operator-run `create-api-key` CLI (long-lived, server-to-server). Send on every request as `Authorization: Bearer `. '