Use with an AI Agent
AgentsForms is designed to be driven by AI agents. An agent detects it needs human input, creates a form session, sends the URL to the user, and resumes when the webhook fires with validated data.
The pattern
Section titled “The pattern”Agent detects missing info → Creates a session (POST /v1/forms/:id/sessions) → Sends the hosted form URL to the human → Human fills the form → Validated submission arrives → Signed webhook fires → Agent resumes with structured dataThe integration surface is HTTP + webhooks. Three approaches follow.
Generic HTTP agent (curl / fetch)
Section titled “Generic HTTP agent (curl / fetch)”The simplest integration. Your agent code makes HTTP calls to the AgentsForms API.
Create a session
Section titled “Create a session”curl -X POST https://api.agentsforms.com/v1/forms/form_abc123/sessions \ -H "Authorization: Bearer $AGENT...EY" \ -H "Content-Type: application/json" \ -d '{ "expires_in": 3600, "prefill": { "email": "user@example.com" }, "metadata": { "thread_id": "thread_42" } }'Poll for submissions
Section titled “Poll for submissions”curl -X GET "https://api.agentsforms.com/v1/forms/form_abc123/submissions?session_id=sess_xyz789" \ -H "Authorization: Bearer $AGENT...-H "Accept: application/json"Or better: set up a webhook. Polling adds latency and cost. A webhook pushes the submission to your agent the moment the human submits.
Webhook verification
Section titled “Webhook verification”When your agent receives a webhook, verify the HMAC signature:
import { createHmac } from 'node:crypto';
function verifyWebhook(body: string, signature: string, secret: string): boolean { const expected = createHmac('sha256', secret).update(body).digest('hex'); return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(`sha256=${expected}`) );}LangGraph
Section titled “LangGraph”In LangGraph, AgentsForms fits the human-in-the-loop interrupt pattern.
from langgraph.graph import StateGraph, START, ENDimport httpx
class AgentState(TypedDict): thread_id: str session_url: str | None submission: dict | None
async def detect_missing_info(state: AgentState): # Your agent logic: determine what information is needed if needs_human_input(state): resp = await httpx.Client().post( "https://api.agentsforms.com/v1/forms/form_abc123/sessions", headers={"Authorization": f"Bearer {API_KEY}"}, json={"metadata": {"thread_id": state["thread_id"]}} ) session = resp.json()["session"] return {"session_url": session["url"]} return {}
async def resume_on_webhook(state: AgentState): # Your webhook handler populates state["submission"] # Resume the graph from the interrupt point ...
graph = StateGraph(AgentState)graph.add_node("detect", detect_missing_info)graph.add_node("resume", resume_on_webhook)graph.add_edge(START, "detect")graph.add_conditional_edges("detect", lambda s: "resume" if s["session_url"] else END)graph.add_edge("resume", END)How the interrupt works
Section titled “How the interrupt works”- The LangGraph node creates a session and returns the hosted URL.
- Your agent sends that URL to the user via its existing channel (Slack, email, chat).
- A webhook handler receives the submission and resumes the graph.
OpenAI Agents SDK / function calling
Section titled “OpenAI Agents SDK / function calling”Define AgentsForms as a function that your agent can call:
from agents import Agent, function_tool, Runner
@function_toolasync def request_human_input(form_slug: str, prefill: dict = {}) -> str: """Request missing information from a human. Returns a URL to send them.""" # Look up form_id by slug, create a session resp = await httpx.Client().post( "https://api.agentsforms.com/v1/forms/form_abc123/sessions", headers={"Authorization": f"Bearer {API_KEY}"}, json={"prefill": prefill} ) session = resp.json()["session"] return session["url"]
agent = Agent( name="SupportBot", instructions="Collect user info before opening a ticket.", tools=[request_human_input],)
result = await Runner.run(agent, "I need help with billing")The agent calls request_human_input, receives the URL, presents it to the human in the chat interface, and the webhook resumes the conversation.
Local development
Section titled “Local development”During development, use a tunneling service to expose your local webhook endpoint:
# Terminal 1: Start your agentpython agent.py
# Terminal 2: Expose your webhook endpointngrok http 3000Then register the ngrok URL as a webhook:
agentsforms webhooks create \ --url https://abc123.ngrok.io/webhook \ --events submission.created