OpenAPI Specification
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 <jwt>`.
'
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 <jwt>`.
'