Monitoring
After executing a plan, you need to know when it confirms. Legend offers two approaches: polling activities and long-polling events.Polling activities
The simplest approach. After executing a plan, poll the activities endpoint until you see your transaction:let confirmed = false;
for (let i = 0; i < 30; i++) {
const { activities } = await client.accounts.activities(account.account_id);
if (activities.length > 0 && activities[0].activity_status === "confirmed") {
console.log("Transaction confirmed!");
confirmed = true;
break;
}
await new Promise((r) => setTimeout(r, 2000));
}
import asyncio
confirmed = False
for _ in range(30):
result = await client.accounts.activities(account["account_id"])
activities = result["activities"]
if activities and activities[0]["activity_status"] == "confirmed":
print("Transaction confirmed!")
confirmed = True
break
await asyncio.sleep(2)
use std::time::Duration;
use tokio::time::sleep;
let mut confirmed = false;
for _ in 0..30 {
let result = client
.accounts()
.activities(&account.account_id)
.await?;
if let Some(activity) = result.activities.first() {
if activity.activity_status == "confirmed" {
println!("Transaction confirmed!");
confirmed = true;
break;
}
}
sleep(Duration::from_secs(2)).await;
}
Long-polling events
The events endpoint withpoll=true holds the connection open until something happens — no wasted requests:
let cursor = 0;
// Wait for the next event
const { events, cursor: newCursor } = await client.accounts.events(
account.account_id,
{ since: cursor, poll: true }
);
for (const event of events) {
if (event.event_type === "activity_updated") {
console.log(`Activity ${event.data.activity_id}: ${event.data.activity_status}`);
}
}
cursor = newCursor;
cursor = 0
# Wait for the next event
result = await client.accounts.events(
account["account_id"],
since=cursor,
poll=True,
)
for event in result["events"]:
if event["event_type"] == "activity_updated":
print(f"Activity {event['data']['activity_id']}: {event['data']['activity_status']}")
cursor = result["cursor"]
let mut cursor = 0;
// Wait for the next event
let result = client
.accounts()
.events(&account.account_id, Some(cursor), Some(true))
.await?;
for event in &result.events {
if event.event_type == "activity_updated" {
println!(
"Activity {}: {}",
event.data.activity_id, event.data.activity_status
);
}
}
cursor = result.cursor;
Continuous monitoring loop
For a service that needs to react to all account changes:async function monitor(accountId: string) {
let cursor = 0;
while (true) {
try {
const { events, cursor: newCursor } = await client.accounts.events(
accountId,
{ since: cursor, poll: true }
);
for (const event of events) {
await handleEvent(event);
}
cursor = newCursor;
} catch (error) {
console.error("Event polling error, retrying...", error);
await new Promise((r) => setTimeout(r, 5000));
}
}
}
async def monitor(account_id: str):
cursor = 0
while True:
try:
result = await client.accounts.events(
account_id,
since=cursor,
poll=True,
)
for event in result["events"]:
await handle_event(event)
cursor = result["cursor"]
except Exception as e:
print(f"Event polling error, retrying... {e}")
await asyncio.sleep(5)
async fn monitor(client: &LegendPrime, account_id: &str) -> Result<(), Box<dyn std::error::Error>> {
let mut cursor = 0;
loop {
match client
.accounts()
.events(account_id, Some(cursor), Some(true))
.await
{
Ok(result) => {
for event in &result.events {
handle_event(event).await;
}
cursor = result.cursor;
}
Err(e) => {
eprintln!("Event polling error, retrying... {e}");
sleep(Duration::from_secs(5)).await;
}
}
}
}
Which approach to use
| Scenario | Recommendation |
|---|---|
| Wait for one transaction | Poll activities in a loop |
| Monitor an account continuously | Long-poll events |
| Dashboard with live updates | Long-poll events |
| Batch job checking final state | Single activities fetch |