For agents that can't receive HTTP. Poll on an interval, process new submissions, act.
Updated March 2026
Not every agent can run a web server. CLI tools, cron jobs, serverless functions, and local scripts can't receive webhook callbacks. For these, polling works. The pattern is simple: store a timestamp, query submissions since that timestamp, process new ones, update the timestamp. Sutrena's submission search endpoint accepts a `from` parameter that returns only submissions after a given time, so you never process the same submission twice. This guide shows the polling pattern in both Python and Node.js.
1. Create a form to collect data
First, the agent creates a form. Share the hosted URL with humans. Submissions will accumulate until the agent polls for them.
curl -X POST https://sutrena.com/api/forms \
-H "Authorization: Bearer $SUTRENA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Feedback Queue",
"fields": [
{"name": "email", "label": "Email", "type": "email", "required": true},
{"name": "feedback", "label": "Feedback", "type": "textarea", "required": true},
{"name": "priority", "label": "Priority", "type": "select", "options": ["Low", "Medium", "High"]}
]
}'2. Poll with a Python loop
This Python script polls every 30 seconds for new submissions. It tracks the last-seen timestamp and only processes submissions that arrived after it. Replace the `process_submission` function with your agent's logic.
import requests, time, os
from datetime import datetime, timezone
API_KEY = os.environ["SUTRENA_API_KEY"]
FORM_ID = os.environ["FORM_ID"]
BASE = "https://sutrena.com"
POLL_INTERVAL = 30 # seconds
last_seen = datetime.now(timezone.utc).isoformat()
def process_submission(sub):
"""Your agent logic here."""
print(f"New: {sub['payload']['email']} — {sub['payload']['priority']}")
# Update a page, send a notification, log to a dashboard, etc.
while True:
res = requests.get(
f"{BASE}/api/forms/{FORM_ID}/submissions",
headers={"Authorization": f"Bearer {API_KEY}"},
params={"from": last_seen, "limit": 100},
)
data = res.json().get("data", res.json())
submissions = data.get("submissions", [])
for sub in submissions:
process_submission(sub)
last_seen = sub["createdAt"]
if submissions:
print(f"Processed {len(submissions)} new submissions")
time.sleep(POLL_INTERVAL)3. Poll with Node.js setInterval
The same pattern in Node.js. Uses setInterval to check for new submissions periodically.
const API_KEY = process.env.SUTRENA_API_KEY;
const FORM_ID = process.env.FORM_ID;
const BASE = "https://sutrena.com";
let lastSeen = new Date().toISOString();
async function poll() {
const url = new URL(`${BASE}/api/forms/${FORM_ID}/submissions`);
url.searchParams.set("from", lastSeen);
url.searchParams.set("limit", "100");
const res = await fetch(url, {
headers: { Authorization: `Bearer ${API_KEY}` },
});
const json = await res.json();
const submissions = json.data?.submissions ?? json.submissions ?? [];
for (const sub of submissions) {
console.log("New:", sub.payload.email, "—", sub.payload.priority);
// Your agent logic here
lastSeen = sub.createdAt;
}
if (submissions.length > 0) {
console.log(`Processed ${submissions.length} new submissions`);
}
}
// Poll every 30 seconds
setInterval(poll, 30_000);
poll(); // Run immediately on start4. Handle pagination for high volume
If your form receives many submissions between polls, use cursor-based pagination to fetch all of them. The response includes a cursor when there are more results.
async function pollAll() {
let cursor = undefined;
let total = 0;
do {
const url = new URL(`${BASE}/api/forms/${FORM_ID}/submissions`);
url.searchParams.set("from", lastSeen);
url.searchParams.set("limit", "100");
if (cursor) url.searchParams.set("cursor", cursor);
const res = await fetch(url, {
headers: { Authorization: `Bearer ${API_KEY}` },
});
const json = await res.json();
const data = json.data ?? json;
const submissions = data.submissions ?? [];
for (const sub of submissions) {
// Process each submission
lastSeen = sub.createdAt;
total++;
}
cursor = data.cursor; // undefined when no more pages
} while (cursor);
if (total > 0) console.log(`Processed ${total} submissions`);
}Every 15-60 seconds for interactive use cases (feedback walls, approval queues). Every 5-15 minutes for batch processing (daily reports, weekly digests). The endpoint is rate-limited to standard API limits, so polling every few seconds is fine on paid plans.
No. The `from` parameter is inclusive and returns all submissions created after that timestamp. As long as you update `lastSeen` to the most recent submission's `createdAt`, you won't miss anything.
If your agent can receive HTTP requests (runs a web server), webhooks are better -- zero latency, no wasted requests. See the webhook callback guide. Polling is for agents that can't receive inbound HTTP: CLI tools, cron jobs, serverless functions, local scripts.
Yes. Add `field` and `value` params to filter by a specific field (e.g. `field=priority&value=High`). Add `status=clean` to skip spam. Add `search=keyword` for full-text search.
Sutrena is the web runtime for AI agents. Forms, Pages, Dashboards, Analytics, Webhooks, Automations, Emails — all through 75 MCP tools and one REST API. Your agent creates web artifacts, humans interact with them, and your agent gets the data back. Use any one feature or all of them together.
Pages
Deploy HTML instantly
Forms
Collect structured data
Dashboards
Visualize with 7 widget types
Analytics
Privacy-first, no cookies
Webhooks
Slack, Discord, Telegram
1. Get a trial key (no auth, no signup)
curl -X POST https://sutrena.com/api/trial2. Create anything — a page, form, dashboard, or analytics site
# Create a form with a dashboard
curl -X POST https://sutrena.com/api/forms \
-H "Authorization: Bearer st_trial_xxx" \
-H "Content-Type: application/json" \
-d '{"workflowId": "waitlist", "createDashboard": true}'
# Or deploy a page
curl -X POST https://sutrena.com/api/pages \
-H "Authorization: Bearer st_trial_xxx" \
-H "Content-Type: application/json" \
-d '{"slug": "index", "title": "My Site", "html": "<h1>Live</h1>"}'Get a trial API key instantly with no signup, or create an account for the full experience.