Most forms were designed for humans filling inputs in a browser. An AI agent — whether it’s Claude, a custom GPT, a Cursor agent, or an autonomous workflow — isn’t a human filling inputs. It’s a program that needs to understand your form’s contract, construct a valid payload, and submit it without guessing.
The problem is that most form backends weren’t built with this in mind. An agent pointed at a typical form endpoint has no way to discover what fields are required, what format they expect, or what validation rules apply. It either hallucinates a payload and learns from 422 errors, or it fails silently.
Why agents fail on typical forms
When a human fills a form, they read the labels, see the field types, and understand context from the surrounding page. An agent has none of that unless you explicitly provide it.
Typical form backends offer an opaque POST endpoint. The agent knows the URL but nothing else — not what fields are expected, not what types they should be, not what validation rules apply. This forced trial-and-error approach is fragile and breaks production workflows.
The Postbox standard: self-documenting endpoints
A self-documenting endpoint responds to a GET request with its own schema. The agent discovers what to submit before it submits anything.
Every Postbox endpoint works this way. A GET with Accept: application/json returns the complete field schema — names, types, and validation rules:
GET https://usepostbox.com/api/{segment}/f/contact
Accept: application/jsonThe agent now knows exactly what to send. No HTML scraping. No guessing. Two HTTP calls — one to discover, one to submit:
sequenceDiagram
autonumber
participant A as Agent
participant P as Postbox
A->>P: GET (Accept: application/json)
P-->>A: Returns JSON Schema (Rules, Enums, Constraints)
Note over A: Constructs payload based on schema
A->>P: POST (Content-Type: application/json)
P-->>A: 201 Created
Honeypots are invisible to agents. Postbox automatically omits honeypot fields from the JSON discovery response. This ensures that an agent following the schema will never accidentally trip a spam trap intended for bots.
Giving an LLM the endpoint as a tool
If your agent is LLM-powered (OpenAI function calling, Claude tool use, etc.), you can generate the tool definition dynamically from the Postbox schema:
import httpx
async def get_form_tool_definition(endpoint_url: str) -> dict:
"""Fetch the schema and convert it to an LLM tool definition."""
async with httpx.AsyncClient() as client:
res = await client.get(endpoint_url, headers={"Accept": "application/json"})
schema = res.json()
properties = {}
required = []
for field in schema["fields"]:
properties[field["name"]] = {"type": field["type"]}
if any(r["op"] == "required" for r in field.get("rules", [])):
required.append(field["name"])
# Surface one_of constraints as enum for the LLM
for rule in field.get("rules", []):
if rule["op"] == "one_of":
properties[field["name"]]["enum"] = rule["values"]
return {
"name": f"submit_{schema['slug']}",
"description": f"Submit data to the {schema['name']} form",
"parameters": {
"type": "object",
"properties": properties,
"required": required,
},
}Now the LLM receives a tool definition generated from the live schema. When you update a form in Postbox, the agent re-discovers the contract and updates its own tool parameters automatically. No code changes required.
The Postbox MCP Server
For users of the Claude desktop app or Cursor, the Postbox MCP server gives your agent direct access to your infrastructure:
{
"mcpServers": {
"postbox": {
"type": "http",
"url": "https://usepostbox.com/mcp",
"headers": {
"Authorization": "Bearer YOUR_API_KEY"
}
}
}
}With MCP connected, your agent can:
- List forms and their live schemas.
- Submit data on your behalf.
- Search submissions and review smart replies.
Building a custom agent that submits forms
If you’re building a custom autonomous script—a Python workflow or a multi-step task—the integration is two clean HTTP calls. You don’t need to hardcode field names or validation logic into your script; you let the agent discover them at runtime.
import httpx
async def submit_to_postbox(endpoint_url: str, data: dict) -> dict:
async with httpx.AsyncClient() as client:
# Step 1: Discover the contract
schema_res = await client.get(endpoint_url, headers={"Accept": "application/json"})
schema = schema_res.json()
# Step 2: Validate data against schema (Optional)
# You can check for required fields or regex patterns before the round-trip
# Step 3: Submit
res = await client.post(endpoint_url, json=data, headers={"Content-Type": "application/json"})
return {"success": res.status_code == 201, "status": res.status_code}
This pattern makes your agent future-proof. If you add a “Department” field to your form in the Postbox dashboard, your agent will immediately see it in the GET response and can adapt its payload without a single line of code change.
Private forms and agent authentication
For internal tools, backend-to-backend integrations, or sensitive data collection, you can make a form Private. Private forms require a Bearer submission token on every POST.
The schema discovery endpoint (GET) for private forms includes an authentication block explaining the requirement. This allows a sophisticated agent to learn not just what to submit, but how to authorize its request.
# Discovery response for a private form
{
"visibility": "private",
"authentication": {
"type": "bearer",
"location": "header",
"name": "Authorization"
},
"fields": [...]
}What happens when the schema evolves?
When you update a form’s schema in Postbox, we generate a new endpoint URL. This is a critical design choice: it prevents breaking changes.
- Legacy Agents: Older scripts using the previous URL continue to work against the old schema.
- New Agents: You point new integrations at the new URL, where they discover the updated requirements.
This “Schema Versioning” approach means you can iterate on your data collection infrastructure without worrying about which agents are currently “in the field” using your endpoints.
The contract is the interface
The same Postbox endpoint works for a human filling a form in a browser, a curl script in a CI pipeline, and an autonomous agent acting on a user’s behalf. The contract — the schema, the validation rules, the error format — is identical for all three.
When you build your forms as contracts rather than UIs, you get agent compatibility for free.
Ready to build for the agentic web? Try Postbox free — every endpoint is self-documenting and agent-ready out of the box. No credit card required.