openapi: 3.0.3
# AVS Aggregator REST API — public partner-facing surface.
#
# Source of truth for the REST API: Go handler interfaces and SDK types are
# generated from this spec via `make rest-gen`. See
# avs-infra/API_REST_IMPLEMENTATION_PLAN.md for the full design rationale.
#
# Conventions:
# - All field names are camelCase (request bodies, response bodies, query
# parameters, template variables).
# - Resources are plural nouns; IDs in path; bodies in JSON.
# - Custom actions use colon-suffix routes (Google AIP-136):
# POST /workflows/{id}:pause, POST /workflows:simulate, etc.
# - Errors follow RFC 7807 (application/problem+json).
# - Pagination uses opaque cursors via `?before=` / `?after=` query params
# and a uniform `{ data, pageInfo }` envelope.
info:
title: Ava Protocol AVS 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
# Health check lives at root, outside /api/v1/. Documented here so the spec is
# self-describing; the actual route is mounted by the server above /api/v1/.
tags:
- name: Health
description: Liveness / readiness probes
- name: Auth
description: Token issuance and credential management
- name: Workflows
description: Workflow CRUD and lifecycle actions
- name: Executions
description: Workflow execution history and status
- name: Wallets
description: Smart-wallet derivation and operations
- name: Secrets
description: User/workflow/org secret storage
- name: Tokens
description: ERC-20 metadata lookup
- name: Nodes
description: Stand-alone node execution
- name: Triggers
description: Stand-alone trigger evaluation
- name: Operators
description: Connected operator status (read-only)
security:
- bearerAuth: []
components:
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>`.
parameters:
PageBefore:
name: before
in: query
description: Cursor — return items immediately before this position (backward pagination).
schema:
type: string
PageAfter:
name: after
in: query
description: Cursor — return items immediately after this position (forward pagination).
schema:
type: string
PageLimit:
name: limit
in: query
description: Max items to return. Default 20; server-enforced ceiling applies.
schema:
type: integer
format: int32
minimum: 1
maximum: 200
default: 20
ChainIdQuery:
name: chainId
in: query
description: |
The chain to operate on (a single value). Omit to use the aggregator
default (the request's JWT `aud` chain, then the gateway default).
schema:
type: integer
format: int64
schemas:
# -------------------------------------------------------------------
# Common scalars
# -------------------------------------------------------------------
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
EthereumAddress:
type: string
pattern: '^0x[a-fA-F0-9]{40}$'
description: Lowercase or checksummed hex EOA / contract address.
example: '0x82F2Dd9a552a69f2ceD7Ff2D05c43aB8430158FB'
Hex:
type: string
pattern: '^0x[a-fA-F0-9]*$'
description: Arbitrary-length hex-encoded byte string.
Ulid:
type: string
pattern: '^[0-9A-HJKMNP-TV-Z]{26}$'
description: ULID identifier (26-char Crockford base32).
example: '01JG2FE5MDVKBPHEG0PEYSDKAC'
Timestamp:
type: string
format: date-time
description: RFC 3339 timestamp.
# -------------------------------------------------------------------
# Pagination envelope (shared by every list endpoint)
# -------------------------------------------------------------------
PageInfo:
type: object
required:
- hasNextPage
- hasPreviousPage
properties:
hasNextPage:
type: boolean
hasPreviousPage:
type: boolean
startCursor:
type: string
description: Cursor for the first item in the current page; pass to `before` for the previous page.
endCursor:
type: string
description: Cursor for the last item in the current page; pass to `after` for the next page.
# -------------------------------------------------------------------
# RFC 7807 problem+json error shape
# -------------------------------------------------------------------
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'
# -------------------------------------------------------------------
# Health
# -------------------------------------------------------------------
HealthStatus:
type: object
required:
- status
- version
properties:
status:
type: string
enum: [ok, degraded, starting]
version:
type: string
description: |
Aggregator binary version (e.g., `v3.2.0`). Always set —
SDK clients use this to stamp the canonical EIP-191 auth
message so the signed `Version` field reflects the
gateway the user actually authenticated against.
chainId:
$ref: '#/components/schemas/ChainId'
description: EigenLayer registration chain ID.
# -------------------------------------------------------------------
# Auth
# -------------------------------------------------------------------
AuthExchangeRequest:
type: object
required:
- ownerAddress
- signature
- message
properties:
ownerAddress:
$ref: '#/components/schemas/EthereumAddress'
signature:
$ref: '#/components/schemas/Hex'
description: EIP-191 personal_sign signature of `message`.
message:
type: string
description: |
The plain-text message that was signed. Must use the canonical
format with the EigenLayer registration chain ID (NOT the workflow
target chain). SDKs generate this locally.
AuthExchangeResponse:
type: object
required:
- token
- expiresAt
properties:
token:
type: string
description: JWT bearer token.
expiresAt:
$ref: '#/components/schemas/Timestamp'
subject:
$ref: '#/components/schemas/EthereumAddress'
description: The EOA the token is bound to (echoed for clients).
# -------------------------------------------------------------------
# Workflow domain — Workflow envelope + Triggers + Nodes + Edges
#
# A Workflow is a DAG: one Trigger fires it, Nodes are executed in
# topological order following Edges, and the run is recorded as an
# Execution (see executions section in a later commit).
#
# Trigger and Node are discriminated unions, keyed by `type`. Each
# variant has its own typed `config` shape. The discriminator lets
# SDKs and OpenAPI codegen produce exhaustive switch handling.
# -------------------------------------------------------------------
WorkflowStatus:
type: string
enum:
- enabled
- disabled
- running
- completed
- failed
description: |
Lifecycle status. `enabled` means actively monitored; `disabled` is
paused. `running`, `completed`, `failed` are terminal-ish states
emitted during/after execution.
TriggerType:
type: string
enum:
- manual
- fixedTime
- cron
- block
- event
description: |
Discriminator field for the Trigger union. Mirrors the proto
`TriggerType` enum but without the `TRIGGER_TYPE_` prefix.
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.
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.
# ---- Trigger configs ----
ManualTriggerConfig:
type: object
description: User-initiated trigger; no chain context.
required: [lang]
properties:
data:
description: Arbitrary structured payload returned in the trigger output.
# google.protobuf.Value equivalent; OpenAPI allows any JSON.
additionalProperties: true
headers:
type: object
additionalProperties: { type: string }
description: HTTP headers (for webhook testing).
pathParams:
type: object
additionalProperties: { type: string }
description: Path parameters (for webhook testing).
lang:
$ref: '#/components/schemas/Lang'
FixedTimeTriggerConfig:
type: object
description: Fires at one or more absolute Unix-epoch milliseconds.
required: [epochs]
properties:
epochs:
type: array
items:
type: integer
format: int64
minItems: 1
CronTriggerConfig:
type: object
description: Fires on one or more cron schedules.
required: [schedules]
properties:
schedules:
type: array
items:
type: string
description: 'Standard cron expression (e.g., `* * * * *`).'
minItems: 1
timezone:
type: string
description: 'IANA timezone (e.g., `UTC`, `America/New_York`). Default UTC.'
BlockTriggerConfig:
type: object
description: Fires every N blocks on the target chain.
required: [interval, chainId]
properties:
interval:
type: integer
format: int64
minimum: 1
description: Fire every N blocks.
chainId:
$ref: '#/components/schemas/ChainId'
description: Chain to watch blocks on. Required — a workflow carries no chain to inherit.
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 }
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.
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.
# ---- Trigger union ----
Trigger:
type: object
required: [type, name, config]
properties:
id: { type: string }
name: { type: string }
type: { $ref: '#/components/schemas/TriggerType' }
discriminator:
propertyName: type
mapping:
manual: '#/components/schemas/ManualTrigger'
fixedTime: '#/components/schemas/FixedTimeTrigger'
cron: '#/components/schemas/CronTrigger'
block: '#/components/schemas/BlockTrigger'
event: '#/components/schemas/EventTrigger'
oneOf:
- $ref: '#/components/schemas/ManualTrigger'
- $ref: '#/components/schemas/FixedTimeTrigger'
- $ref: '#/components/schemas/CronTrigger'
- $ref: '#/components/schemas/BlockTrigger'
- $ref: '#/components/schemas/EventTrigger'
ManualTrigger:
allOf:
- type: object
properties:
type:
type: string
enum: [manual]
config: { $ref: '#/components/schemas/ManualTriggerConfig' }
FixedTimeTrigger:
allOf:
- type: object
properties:
type:
type: string
enum: [fixedTime]
config: { $ref: '#/components/schemas/FixedTimeTriggerConfig' }
CronTrigger:
allOf:
- type: object
properties:
type:
type: string
enum: [cron]
config: { $ref: '#/components/schemas/CronTriggerConfig' }
BlockTrigger:
allOf:
- type: object
properties:
type:
type: string
enum: [block]
config: { $ref: '#/components/schemas/BlockTriggerConfig' }
EventTrigger:
allOf:
- type: object
properties:
type:
type: string
enum: [event]
config: { $ref: '#/components/schemas/EventTriggerConfig' }
# ---- Node configs ----
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.
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.
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.
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.
GraphQLQueryNodeConfig:
type: object
required: [url, query]
properties:
url:
type: string
format: uri
query: { type: string }
variables:
type: object
additionalProperties: { type: string }
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 }
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.
BranchNodeConfig:
type: object
required: [conditions]
properties:
conditions:
type: array
items: { $ref: '#/components/schemas/BranchCondition' }
minItems: 1
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.
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'
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.
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).
SignalExecutionRequest:
type: object
required: [decision]
properties:
decision:
type: string
enum: [approve, reject]
description: The approver's decision.
payload:
type: object
additionalProperties: true
description: Optional structured data delivered as the await step's output.
# ---- Node union ----
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'
ETHTransferNode:
allOf:
- type: object
properties:
type: { type: string, enum: [ethTransfer] }
config: { $ref: '#/components/schemas/ETHTransferNodeConfig' }
ContractWriteNode:
allOf:
- type: object
properties:
type: { type: string, enum: [contractWrite] }
config: { $ref: '#/components/schemas/ContractWriteNodeConfig' }
ContractReadNode:
allOf:
- type: object
properties:
type: { type: string, enum: [contractRead] }
config: { $ref: '#/components/schemas/ContractReadNodeConfig' }
GraphQLQueryNode:
allOf:
- type: object
properties:
type: { type: string, enum: [graphqlQuery] }
config: { $ref: '#/components/schemas/GraphQLQueryNodeConfig' }
RestAPINode:
allOf:
- type: object
properties:
type: { type: string, enum: [restApi] }
config: { $ref: '#/components/schemas/RestAPINodeConfig' }
CustomCodeNode:
allOf:
- type: object
properties:
type: { type: string, enum: [customCode] }
config: { $ref: '#/components/schemas/CustomCodeNodeConfig' }
BranchNode:
allOf:
- type: object
properties:
type: { type: string, enum: [branch] }
config: { $ref: '#/components/schemas/BranchNodeConfig' }
FilterNode:
allOf:
- type: object
properties:
type: { type: string, enum: [filter] }
config: { $ref: '#/components/schemas/FilterNodeConfig' }
LoopNode:
allOf:
- type: object
properties:
type: { type: string, enum: [loop] }
config: { $ref: '#/components/schemas/LoopNodeConfig' }
BalanceNode:
allOf:
- type: object
properties:
type: { type: string, enum: [balance] }
config: { $ref: '#/components/schemas/BalanceNodeConfig' }
AwaitNode:
allOf:
- type: object
properties:
type: { type: string, enum: [await] }
config: { $ref: '#/components/schemas/AwaitNodeConfig' }
# ---- Workflow envelope ----
Edge:
type: object
required: [id, source, target]
properties:
id: { type: string }
source:
type: string
description: Node or trigger ID where this edge starts.
target:
type: string
description: Node ID where this edge ends.
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.
Workflow:
type: object
required: [id, owner, smartWalletAddress, trigger, nodes, status]
properties:
id: { $ref: '#/components/schemas/Ulid' }
name: { type: string }
owner: { $ref: '#/components/schemas/EthereumAddress' }
smartWalletAddress: { $ref: '#/components/schemas/EthereumAddress' }
trigger: { $ref: '#/components/schemas/Trigger' }
nodes:
type: array
items: { $ref: '#/components/schemas/Node' }
edges:
type: array
items: { $ref: '#/components/schemas/Edge' }
inputVariables: { $ref: '#/components/schemas/InputVariables' }
status: { $ref: '#/components/schemas/WorkflowStatus' }
startAt:
type: integer
format: int64
description: Unix-epoch milliseconds — workflow is inert before this time.
expiredAt:
type: integer
format: int64
description: Unix-epoch milliseconds — workflow is inert after this time.
maxExecution:
type: integer
format: int64
description: Cap on how many times this workflow may execute. 0 = unlimited.
# --- truncated at 32 KB (83 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/ava-protocol/refs/heads/main/openapi/ava-protocol-avs-openapi-original.yml