Ava Protocol Workflows API
Workflow CRUD and lifecycle actions
Workflow CRUD and lifecycle actions
openapi: 3.0.3
info:
title: Ava Protocol AVS Auth Workflows 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: Workflows
description: Workflow CRUD and lifecycle actions
paths:
/workflows:
post:
tags:
- Workflows
summary: Create a workflow
description: 'Persist a new workflow definition. Each chain-aware trigger and node
carries its own required `chainId` (there is no workflow-level chain);
the server validates those chains and ensures the smart wallet belongs
to the authenticated user. Returns the persisted Workflow with its
server-assigned `id` and `createdAt`.
'
operationId: createWorkflow
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateWorkflowRequest'
responses:
'201':
description: Workflow created.
content:
application/json:
schema:
$ref: '#/components/schemas/Workflow'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'429':
$ref: '#/components/responses/RateLimited'
get:
tags:
- Workflows
summary: List workflows
operationId: listWorkflows
parameters:
- name: smartWalletAddress
in: query
description: Filter by smart wallet address. Repeat to OR multiple addresses.
schema:
type: array
items:
$ref: '#/components/schemas/EthereumAddress'
- name: status
in: query
description: Filter by status. Repeat to OR multiple statuses.
schema:
type: array
items:
$ref: '#/components/schemas/WorkflowStatus'
- $ref: '#/components/parameters/PageBefore'
- $ref: '#/components/parameters/PageAfter'
- $ref: '#/components/parameters/PageLimit'
responses:
'200':
description: Page of workflows.
content:
application/json:
schema:
$ref: '#/components/schemas/WorkflowList'
'401':
$ref: '#/components/responses/Unauthorized'
'429':
$ref: '#/components/responses/RateLimited'
/workflows/{id}:
parameters:
- name: id
in: path
required: true
schema:
$ref: '#/components/schemas/Ulid'
get:
tags:
- Workflows
summary: Retrieve a workflow
operationId: getWorkflow
responses:
'200':
description: The workflow.
content:
application/json:
schema:
$ref: '#/components/schemas/Workflow'
'401':
$ref: '#/components/responses/Unauthorized'
'404':
$ref: '#/components/responses/NotFound'
delete:
tags:
- Workflows
summary: Cancel a workflow
description: 'Permanently cancels and removes the workflow. SDK method is
`cancel(id)` to align with Stripe-style vocabulary.
'
operationId: cancelWorkflow
responses:
'204':
description: Workflow cancelled.
'401':
$ref: '#/components/responses/Unauthorized'
'404':
$ref: '#/components/responses/NotFound'
/workflows/{id}:pause:
parameters:
- name: id
in: path
required: true
schema:
$ref: '#/components/schemas/Ulid'
post:
tags:
- Workflows
summary: Pause a workflow
description: Transition from `enabled` to `disabled`. Idempotent.
operationId: pauseWorkflow
responses:
'200':
description: Workflow paused.
content:
application/json:
schema:
$ref: '#/components/schemas/Workflow'
'401':
$ref: '#/components/responses/Unauthorized'
'404':
$ref: '#/components/responses/NotFound'
'409':
description: Workflow is in a terminal state and cannot be paused.
content:
application/problem+json:
schema:
$ref: '#/components/schemas/Problem'
/workflows/{id}:resume:
parameters:
- name: id
in: path
required: true
schema:
$ref: '#/components/schemas/Ulid'
post:
tags:
- Workflows
summary: Resume a workflow
description: Transition from `disabled` to `enabled`. Idempotent.
operationId: resumeWorkflow
responses:
'200':
description: Workflow resumed.
content:
application/json:
schema:
$ref: '#/components/schemas/Workflow'
'401':
$ref: '#/components/responses/Unauthorized'
'404':
$ref: '#/components/responses/NotFound'
'409':
description: Workflow is in a terminal state and cannot be resumed.
content:
application/problem+json:
schema:
$ref: '#/components/schemas/Problem'
/workflows/{id}:trigger:
parameters:
- name: id
in: path
required: true
schema:
$ref: '#/components/schemas/Ulid'
post:
tags:
- Workflows
summary: Manually trigger a workflow
description: 'Simulate an operator-detected trigger fire. The server enqueues an
execution; when `isBlocking=true`, the response waits for the
execution to complete.
'
operationId: triggerWorkflow
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/TriggerWorkflowRequest'
responses:
'202':
description: Execution enqueued (async). Returned when isBlocking=false.
content:
application/json:
schema:
$ref: '#/components/schemas/TriggerWorkflowResponse'
'200':
description: Execution completed (blocking). Returned when isBlocking=true.
content:
application/json:
schema:
$ref: '#/components/schemas/TriggerWorkflowResponse'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'404':
$ref: '#/components/responses/NotFound'
'412':
description: Workflow is disabled or has reached its max execution count.
content:
application/problem+json:
schema:
$ref: '#/components/schemas/Problem'
/workflows:simulate:
post:
tags:
- Workflows
summary: Simulate a workflow without persisting it
description: 'Run a workflow definition end-to-end against the engine (Tenderly
simulation for chain-writing nodes) and return the full Execution.
Nothing is persisted.
'
operationId: simulateWorkflow
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/SimulateWorkflowRequest'
responses:
'200':
description: Simulated execution.
content:
application/json:
schema:
type: object
additionalProperties: true
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
/workflows:estimateFees:
post:
tags:
- Workflows
summary: Estimate per-execution fees for a workflow definition
description: 'Returns the platform execution fee, per-node COGS (gas, external
API costs), and the workflow-level value-capture fee tier.
'
operationId: estimateWorkflowFees
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/EstimateFeesRequest'
responses:
'200':
description: Fee estimate.
content:
application/json:
schema:
$ref: '#/components/schemas/EstimateFeesResponse'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
/workflows:count:
get:
tags:
- Workflows
summary: Count workflows
description: Cheap aggregation over the same filter set as `GET /workflows`.
operationId: countWorkflows
parameters:
- name: smartWalletAddress
in: query
schema:
type: array
items:
$ref: '#/components/schemas/EthereumAddress'
- name: status
in: query
schema:
type: array
items:
$ref: '#/components/schemas/WorkflowStatus'
responses:
'200':
description: Workflow count for the filter set.
content:
application/json:
schema:
$ref: '#/components/schemas/WorkflowCount'
'401':
$ref: '#/components/responses/Unauthorized'
components:
schemas:
SimulateWorkflowRequest:
type: object
required:
- trigger
- nodes
- inputVariables
properties:
chainId:
$ref: '#/components/schemas/ChainId'
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'
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.
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
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.
'
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
TriggerWorkflowRequest:
type: object
required:
- triggerType
properties:
triggerType:
$ref: '#/components/schemas/TriggerType'
triggerOutput:
description: 'Type-specific output payload (BlockTrigger.Output,
EventTrigger.Output, etc.) that simulates what the operator
would have observed. Defined alongside execution schemas.
'
additionalProperties: true
triggerInput:
$ref: '#/components/schemas/InputVariables'
isBlocking:
type: boolean
description: When true, wait for the execution to complete and return its result.
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.
EventTrigger:
allOf:
- type: object
properties:
type:
type: string
enum:
- event
config:
$ref: '#/components/schemas/EventTriggerConfig'
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.
'
EstimateFeesRequest:
type: object
required:
- trigger
- nodes
- createdAt
- expireAt
- maxExecution
properties:
chainId:
$ref: '#/components/schemas/ChainId'
trigger:
$ref: '#/components/schemas/Trigger'
nodes:
type: array
items:
$ref: '#/components/schemas/Node'
edges:
type: array
items:
$ref: '#/components/schemas/Edge'
runner:
$ref: '#/components/schemas/EthereumAddress'
description: Smart wallet address used for gas estimation (overrides settings.runner).
createdAt:
type: integer
format: int64
expireAt:
type: integer
format: int64
maxExecution:
type: integer
format: int64
inputVariables:
$ref: '#/components/schemas/InputVariables'
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.
EstimateFeesResponse:
type: object
required:
- chainId
- executionFee
- cogs
- valueFee
properties:
chainId:
$ref: '#/components/schemas/ChainId'
nativeToken:
$ref: '#/components/schemas/NativeToken'
executionFee:
$ref: '#/components/schemas/Fee'
description: Flat per-execution platform fee (typically USD).
cogs:
type: array
items:
$ref: '#/components/schemas/NodeCOGS'
description: Per-node operational costs (gas, external API).
valueFee:
$ref: '#/components/schemas/ValueFee'
description: Workflow-level value-capture fee (PERCENTAGE).
discounts:
type: array
items:
$ref: '#/components/schemas/FeeDiscount'
pricingModel:
type: string
description: Pricing model label (e.g., `tiered_value_capture_v1`).
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.
Fee:
type: object
required:
- amount
- unit
properties:
amount:
type: string
description: Decimal numeric value, encoded as a string for big-int safety.
unit:
type: string
enum:
- USD
- WEI
- PERCENTAGE
ETHTransferNode:
allOf:
- type: object
properties:
type:
type: string
enum:
- ethTransfer
config:
$ref: '#/components/schemas/ETHTransferNodeConfig'
FeeDiscount:
type: object
properties:
discountType:
type: string
enum:
- newUser
- volume
- promotional
- betaProgram
discountName:
type: string
discount:
$ref: '#/components/schemas/Fee'
expiryDate:
$ref: '#/components/schemas/Timestamp'
terms:
type: string
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.
BlockTrigger:
allOf:
- type: object
properties:
type:
type: string
enum:
- block
config:
$ref: '#/components/schemas/BlockTriggerConfig'
GraphQLQueryNode:
allOf:
- type: object
properties:
type:
type: string
enum:
- graphqlQuery
config:
$ref: '#/components/schemas/GraphQLQueryNodeConfig'
Ulid:
type: string
pattern: ^[0-9A-HJKMNP-TV-Z]{26}$
description: ULID identifier (26-char Crockford base32).
example: 01JG2FE5MDVKBPHEG0PEYSDKAC
FixedTimeTrigger:
allOf:
- type: object
properties:
type:
type: string
enum:
- fixedTime
config:
$ref: '#/components/schemas/FixedTimeTriggerConfig'
TriggerWorkflowResponse:
type: object
required:
- executionId
- status
properties:
executionId:
$ref: '#/components/schemas/Ulid'
status:
$ref: '#/components/schemas/ExecutionStatus'
startAt:
type: integer
format: int64
endAt:
type: integer
format: int64
error:
type: string
BranchNode:
allOf:
- type: object
properties:
type:
type: string
enum:
- branch
config:
$ref: '#/components/schemas/BranchNodeConfig'
ExecutionStatus:
type: string
enum:
- pending
- waiting
- success
- failed
- error
description: 'Outcome of an execution. `pending` is in-flight; `waiting` is suspended
mid-workflow at an `await` node, durably parked until a signal arrives
(a human approve/reject or an operator-observed chain event) or the wait
times out — non-terminal, like `pending`, but distinguishable so a client
can show "awaiting approval"; `success` is full success; `failed` is
logical failure (e.g., a node returned an error, or a wait timed out);
`error` is a system / infrastructure failure (e.g., RPC unreachable).
'
Timestamp:
type: string
format: date-time
description: RFC 3339 timestamp.
LoopNode:
allOf:
- type: object
properties:
type:
type: string
enum:
- loop
config:
$ref: '#/components/schemas/LoopNodeConfig'
CronTrigger:
allOf:
- type: object
properties:
type:
type: string
enum:
- cron
config:
$ref: '#/components/schemas/CronTriggerConfig'
BranchNodeConfig:
type: object
required:
- conditions
properties:
conditions:
type: array
items:
$ref: '#/components/schemas/BranchCondition'
minItems: 1
NodeCOGS:
type: object
required:
- nodeId
- costType
- fee
properties:
nodeId:
type: string
costType:
type: string
enum:
- gas
- externalApi
- walletCreation
fee:
$ref: '#/components/schemas/Fee'
gasUnits:
type: string
description: Gas units (for `gas` cost type only).
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.
NativeToken:
type: object
required:
- symbol
- decimals
properties:
symbol:
type: string
example: ETH
decimals:
type: integer
format: int32
ManualTriggerConfig:
type: object
description: User-initiated trigger; no chain context.
required:
- lang
properties:
data:
description: Arbitrary structured payload returned in the trigger output.
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'
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'
WorkflowList:
type: object
required:
- data
- pageInfo
properties:
data:
type: array
items:
$ref: '#/components/schemas/Workflow'
pageInfo:
$ref: '#/components/schemas/PageInfo'
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).
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.
Workflow:
type: o
# --- truncated at 32 KB (45 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/ava-protocol/refs/heads/main/openapi/ava-protocol-workflows-api-openapi.yml