Skip to main content
Every node in a definition is an envelope with the same shape:
Most nodes route onward through cases — ordered conditions where the first match wins (see Conditions and variables). time nodes use a single to instead, and end nodes have no exit. When no case matches, the execution moves to the node’s on_no_match, or the definition-wide one if the node doesn’t declare its own. The Node Types API returns this catalog programmatically — every parameter with defaults and bounds, generated from the same models that publish enforces.
Definition limits: at most 200 nodes, 25 cases per node, 10 effects per case, 50 declared start fields, and 512 KB of definition JSON.

start

The entry point. Exactly one per workflow, referenced by entry_node_id, and it must have at least one case. It declares the contact fields the workflow accepts — the schema that single runs and campaign uploads are validated against. Four system fields are always accepted without declaring them: reference_id, mobile_number, name, email. Declaring one (for example to make mobile_number required) refines the built-in rather than duplicating it.
Declared fields become entry.* variables — entry.loan_amount in the example — usable in any downstream condition. Typed fields are coerced at upload, so "42000" in a CSV compares numerically.

agent

Places a call with one of your Bolna voice agents and waits for it to finish. After the call, the node writes call.* variables and its cases branch on them:
  • call.statuscompleted, busy, no_answer, failed, voicemail, cancelled, rejected, timeout, or error
  • call.duration_s — call duration when known
  • call.error — set when status is error (for example missing_recipient when the recipient variable is blank)
Each agent node produces a regular call execution with its own transcript and recording.

extraction

Exposes fields your agent extracted from the call — its dispositions — as extraction.* variables for branching. An extraction node must directly follow its linked agent node. At publish, the field types are filled in server-side from the agent’s dispositions — numeric dispositions compare numerically.

api

Calls an external HTTP endpoint, maps values out of the response, and branches on the result. After the request, cases branch on response.*:
  • response.status — the HTTP status code as a number. A 4xx/5xx is not retried away — it reaches your cases so you decide what happens.
  • response.<name> — every response_map entry.
  • response.error"transport" on DNS failure, connection refusal or timeout (no response.status in that case).

time

Waits, then moves on. The only node with a single exit — it takes to instead of cases. Exactly one of delay or at must be set.

retry

Re-runs an earlier node on a schedule — the only legal way to close a cycle in the graph. Any other loop back upstream is rejected at publish with unbounded_cycle. Each time the execution reaches the retry node it consumes the next attempt: waits out that entry’s schedule, then jumps back to the target. Once all attempts are consumed, the node’s cases are evaluated instead — that’s your “gave up” path. The target therefore runs at most attempts + 1 times.

aisensy_whatsapp

Sends a WhatsApp template message through your connected AiSensy account.
Cases branch on whatsapp.status (sent or failed), with whatsapp.message_id and whatsapp.error alongside.

end

Terminates the execution.
Design your endings deliberately: every distinct label becomes a row in the campaign report, and the outcomes drive the success_count / failure_count / neutral_count rollups everywhere.

Next Steps

Conditions and variables

The expression language cases are written in

Node Types API

This catalog, programmatically