Guides/Poll for new form submissions

Poll for new form submissions

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 start

4. 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`);
}

FAQ

How often should I poll?

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.

Will I miss submissions between polls?

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.

Should I use webhooks instead?

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.

Can I filter submissions while polling?

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.

What is Sutrena?

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

Get started in two API calls

1. Get a trial key (no auth, no signup)

curl -X POST https://sutrena.com/api/trial

2. 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>"}'

Ready to build?

Get a trial API key instantly with no signup, or create an account for the full experience.

Poll for new form submissions — agent polling pattern | Sutrena | Sutrena