Beyond robots.txt: An Actions Manifest for Agentic Browsers
Agentic browsing is changing the contract between users and websites. When a person navigates a page, clicks buttons, and solves CAPTCHAs, the website presumes intent and capacity for judgment. When an agent does the same with headless browsing and model-driven affordances, those assumptions collapse. We are already in an escalating cycle of fragile scraping, bot-detection heuristics, and interaction walls that block legitimate automation alongside bad bots.
Robots.txt helped decouple discovery from adversarial crawling. It gave a simple, machine-readable signal for indexing. But agentic interaction is not just discovery or read access. It is booking, buying, amending, refunding, asking for availability, and negotiating terms. These are write operations with real risk, money, and compliance.
This essay proposes an Actions Manifest for the web: a standardized, machine-readable capability description that declares what intents a site supports for automated agents, under what preconditions, with what quotas and costs, and how to produce auditable receipts. It is not an API platform replacement. It is a minimal, web-native declaration layer that lets agents interact ethically and reliably without CAPTCHAs, brittle DOM scraping, or bot-detection wars.
- Robots.txt is for crawling. An Actions Manifest is for acting.
- It advertises allowed intents, typed parameters, authorization preconditions, quotas, pricing, and audit mechanisms.
- It enables safe, reversible operations with receipts and consent.
- It aligns with existing web and identity standards (OAuth, DPoP, HTTP message signatures, JSON Schema), and can co-exist with OpenAPI.
The goal is practical: make it cheap for websites to declare a safe surface for agents to accomplish high-intent tasks, and make it reliable for agentic browsers to accomplish those tasks without guessing.
From crawling to acting: what broke
LLM-powered agents do not consume the web the way humans do. They:
- Seek to achieve tasks end-to-end: find options, compare trade-offs, execute purchases, track deliveries.
- Operate at machine speed, so even benign agents can trigger rate-limits or anti-bot heuristics.
- Infer UI semantics and hidden form constraints poorly; a minor markup change can break a scraping pipeline.
- Struggle with consent and compliance: verifying age, jurisdiction, or payment authorization.
- Have difficulty proving accountability: who asked, what was consented to, and what was charged?
The result has been an unhealthy equilibrium:
- Sites obfuscate DOMs, employ extreme bot detection, or corral users behind apps.
- Agents reverse-engineer flows or rely on unstable heuristics.
- CAPTCHAs impose human friction but fail to distinguish high-intent automation from abuse.
We can do better with a simple declaration layer that moves automation from the shadows into a well-lit, auditable path.
Design principles for an agent-safe action layer
Any standard for agentic actions should embrace a few principles:
- Explicit intents: Name actions in business terms (search_flights, hold_itinerary, purchase, refund) rather than opaque endpoints.
- Typed parameters and responses: Use JSON Schema to define inputs, constraints, and exact failure modes.
- Clear preconditions: Enumerate what is needed before the action is attempted (login, scope, age, jurisdiction, 2FA, payment method on file, prior availability check).
- Quotas and costs: Publish rate limits, quota buckets, and per-action costs so agents can plan without tripping alarms.
- Consent and accountability: Bind actions to explicit consent artifacts and return signed receipts with verifiable claims.
- Fail safely: Describe negative outcomes and reversibility (hold expiration, cancellation windows, refund policy) upfront.
- Progressive complexity: Start with read and availability actions; layer purchase and irreversible actions once trust is established.
- Compatibility over reinvention: Reuse OAuth, DPoP, HTTP message signatures, JSON Schema, and OpenAPI where possible.
Discovery: where agents find the manifest
Discovery needs to be trivial and cacheable:
- Well-known path: /.well-known/actions-manifest.json
- Link headers: HTTP Link: https://example.com/.well-known/actions-manifest.json; rel="actions-manifest"
- HTML link: <link rel="actions-manifest" href="/.well-known/actions-manifest.json">
- Optional pointer in robots.txt as a comment for human discoverability.
The manifest should be cacheable with a conservative max-age and strong ETags. It can be versioned with a top-level version and include an updated timestamp.
Schema: a compact capability map, not a full API spec
The manifest is a directory of intents and guardrails. Each action advertises what an agent may do and how to do it safely.
- version: Semantic version for the manifest format.
- issuer: Domain that stands behind the manifest and signatures.
- updated: ISO 8601 timestamp of last change.
- policy: Links to terms of service and automation policy.
- actions: Array of action objects.
Action fields:
- id: Stable identifier (URL-safe) for linking and receipts.
- intent: Short, interoperable name (e.g., search_flights, book_table, purchase_item, cancel_order, query_inventory).
- title, description: Human-readable.
- method: HTTP verb (GET, POST, etc.).
- endpoint: Absolute or relative URL.
- requestSchema: JSON Schema for request body or query parameters.
- responseSchema: JSON Schema for successful response.
- auth: Supported methods and OAuth scopes.
- preconditions: Machine-readable requirements to attempt the action.
- quotas: Rate limits and cost model.
- receipts: Whether and how a signed receipt is returned.
- examples: Example requests and responses.
- safety: Constraints, reversibility, and failure modes.
Here is a minimal end-to-end example for an airline site with search, hold, and purchase actions. For readability, only essential fields are shown.
json{ "version": "0.3.0", "issuer": "https://air.example", "updated": "2025-10-20T12:34:56Z", "policy": { "terms": "https://air.example/terms", "automation": "https://air.example/automation-policy" }, "actions": [ { "id": "search_flights", "intent": "search_flights", "title": "Search flights", "description": "Search flight availability and fares.", "method": "GET", "endpoint": "/agent/v1/flights/search", "requestSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "origin": {"type": "string", "pattern": "^[A-Z]{3}$"}, "destination": {"type": "string", "pattern": "^[A-Z]{3}$"}, "depart_date": {"type": "string", "format": "date"}, "return_date": {"type": "string", "format": "date"}, "adults": {"type": "integer", "minimum": 1, "maximum": 9}, "cabin": {"type": "string", "enum": ["economy", "premium", "business", "first"]} }, "required": ["origin", "destination", "depart_date", "adults"] }, "responseSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "itineraries": {"type": "array", "items": {"type": "object", "properties": { "id": {"type": "string"}, "segments": {"type": "array"}, "total_price": {"type": "string", "pattern": "^[A-Z]{3} [0-9]+(\/[0-9]+)?$"}, "hold_allowed": {"type": "boolean"} }, "required": ["id", "total_price"]}} }, "required": ["itineraries"] }, "auth": {"type": ["none", "oauth2"], "scopes": ["read:fares"]}, "preconditions": [{"type": "geo", "allowed_countries": ["US", "CA", "GB", "EU"]}], "quotas": {"bucket": "ip|account", "rate": "60/m", "burst": 30}, "receipts": {"enabled": false} }, { "id": "hold_itinerary", "intent": "hold_itinerary", "title": "Hold itinerary", "description": "Hold an itinerary for 24 hours.", "method": "POST", "endpoint": "/agent/v1/holds", "requestSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "itinerary_id": {"type": "string"}, "passenger_count": {"type": "integer", "minimum": 1, "maximum": 9}, "contact": {"type": "object", "properties": { "email": {"type": "string", "format": "email"} }, "required": ["email"]} }, "required": ["itinerary_id", "passenger_count", "contact"] }, "responseSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "hold_id": {"type": "string"}, "expires_at": {"type": "string", "format": "date-time"}, "price_locked": {"type": "string"} }, "required": ["hold_id", "expires_at"] }, "auth": {"type": ["oauth2"], "scopes": ["write:holds"]}, "preconditions": [ {"type": "login"}, {"type": "consent", "prompt": "Hold may expire; price not guaranteed."} ], "quotas": {"bucket": "account", "rate": "10/h", "burst": 5, "cost": {"currency": "USD", "amount": 0.50}}, "receipts": {"enabled": true, "format": "jws"} }, { "id": "purchase_itinerary", "intent": "purchase", "title": "Purchase itinerary", "description": "Purchase a held itinerary using a stored payment method.", "method": "POST", "endpoint": "/agent/v1/purchases", "requestSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "hold_id": {"type": "string"}, "payment_instrument": {"type": "string", "enum": ["default", "card_on_file", "wallet"]}, "consent_token": {"type": "string"} }, "required": ["hold_id", "payment_instrument", "consent_token"] }, "responseSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "order_id": {"type": "string"}, "receipt": {"type": "object"} }, "required": ["order_id", "receipt"] }, "auth": {"type": ["oauth2"], "scopes": ["write:purchases", "charge:default"]}, "preconditions": [ {"type": "login"}, {"type": "2fa"}, {"type": "age", "minimum": 18}, {"type": "consent", "prompt": "You authorize a charge up to the locked price."} ], "quotas": {"bucket": "account", "rate": "5/d", "burst": 3, "max_amount": {"currency": "USD", "amount": 5000}}, "receipts": {"enabled": true, "format": "jws", "fields": ["order_id", "amount", "currency", "timestamp", "actor", "intent", "parameters"]} } ] }
A few notes on the shape:
- requestSchema and responseSchema are JSON Schema documents. Agents can validate locally before making calls, improving success rates and avoiding trial-and-error.
- auth enumerates supported methods. For example, OAuth 2.1 with scopes; GNAP could be added as the ecosystem matures.
- preconditions are explicit, machine-readable requirements; they can include login, scoped consent, 2FA, geofence, age, or business checks like stock_on_hand.
- quotas include both rate limits and optional economic costs, allowing the site to meter expensive actions without CAPTCHAs.
- receipts require the server to return a signed receipt with verifiable claims.
Preconditions: moving beyond human presence to verifiable readiness
Preconditions should answer: what must be true before we attempt this action? Some common types:
- login: Account-bound actions. Include supported identity providers, hints for PKCE, and SSO domains.
- scopes: Required authorization scopes (e.g., read:fares, write:holds, charge:default).
- 2fa: Time-based one-time password, push, or WebAuthn step-up.
- geo: Jurisdiction restrictions and allowed regions.
- age: Minimum age and accepted claims providers.
- payment_instrument: A stored card, wallet, or deposit is required before purchase.
- consent: A human must explicitly approve parameters above a threshold (e.g., charge up to 500 USD). Agents retrieve a short-lived consent_token via a consent endpoint.
- proof_of_cost: Instead of CAPTCHAs, require a small, non-interactive cost or Privacy Pass token for high-frequency read actions.
Preconditions are not enforcement by themselves; they are promises about enforcement. The server still enforces. But explicit declarations allow agents to route: if the user has no payment instrument, the agent can prompt to add one before attempting checkout.
Quotas and costs: rate limits that agents can reason about
Agents need to know how much they can do before being throttled. Quotas should declare:
- bucket: The identity dimension (ip, account, payment_instrument, organization) to which limits apply.
- rate and burst: For example, 60 per minute with a burst of 30.
- concurrency: Maximum simultaneous actions; useful for inventory-related endpoints.
- cost: Monetary or token cost per action; can be zero for reads and non-zero for resource-intensive operations (e.g., solving complex availability).
- grant and escalation: A link to a page or endpoint to request higher limits.
Use structured field values or a compact string format (e.g., 60/m, 10/h) for human and machine readability. Exposing costs and limits discourages naive parallelization and reduces bot-detection false positives.
Receipts: non-repudiation without screenshots
Agents need durable, verifiable evidence of what happened. An audit receipt allows replay-free dispute resolution and compliance logging. A good receipt has:
- Cryptographic signatures: JWS (RFC 7515) using a key advertised by the manifest, or HTTP Message Signatures (RFC 9421) over the response.
- Claims: issuer, action_id, intent, parameters (or a redacted/hashed subset), actor (pseudonymous subject or account id), timestamp, idempotency key, result summary (order_id, amount), and policy version.
- Binding: DPoP (RFC 9449) or mTLS confirmation binds the access token to a key, so the receipt ties to a key pair controlled by the agent for non-repudiation.
- Privacy: Redact PII; include a reference to the server-side full record retrievable by the account owner.
An example of a compact receipt as a JWS payload (base64url encoded and signed):
json{ "iss": "https://air.example", "iat": 1761113696, "act": "purchase", "aid": "purchase_itinerary", "rid": "rcpt_8f9b1a", "sub": "acct_12345", "dpop_jkt": "w7xz...", "params_hash": "sha256-6H3...", "result": { "order_id": "ORD-2025-10-20-98765", "amount": 129900, "currency": "USD" }, "consent_ref": "cns_4bd3", "policy": "automation-policy@2025-07-01" }
Authentication and authorization: scoped, bound, and human-in-the-loop when needed
For agentic actions that touch accounts or money, use standard web auth flows:
- OAuth 2.1 with PKCE for user authorization and refresh tokens with rotation. Restrict to task-specific scopes (e.g., write:holds, charge:default). Consider Pushed Authorization Requests to avoid URI leakage.
- DPoP (proof-of-possession) to bind tokens to a public key controlled by the agent. This reduces token replay.
- mTLS where appropriate, particularly for high-value B2B agents.
- HTTP Message Signatures to sign requests or responses when mutual accountability is needed.
Consent is not just OAuth scope. For high-risk actions, add a consent precondition. The recommended pattern:
- Agent initiates a consent challenge describing the proposed parameters (e.g., charge up to 1,299.00 USD for hold_id H123).
- The user is presented with an out-of-band human UI (deep link, notification, device-bound passkey prompt) to approve.
- The site issues a short-lived consent_token binding the parameters and ceiling limits.
- The agent includes the consent_token with the purchase action.
This is faster and safer than CAPTCHAs and makes the user’s intent explicit.
Failure modes and reversibility
Agents need predictable error semantics to avoid destructive loops. Recommend a small error taxonomy:
- invalid_parameters: Schema validation failed; include a JSON Pointer to the failing field.
- precondition_required: Missing precondition; include a machine-readable list of unresolved preconditions.
- quota_exceeded: Include retry_after and a link to request-raise.
- unavailable: Temporary capacity limits; include backoff hints.
- conflict: State changed (e.g., hold expired); include a fresh state reference.
- irreversible: Operation cannot be undone; require explicit consent.
Additionally, the manifest should declare reversibility:
- reversible: true/false.
- cancellation_window: duration.
- refund_policy_ref: URL to machine-readable refund terms (even a short JSON block with time steps and percentages helps).
Why not just build APIs and publish OpenAPI?
OpenAPI remains a great tool for comprehensive APIs. The Actions Manifest is complementary and intentionally opinionated:
- It starts from user intents rather than resource nouns. Agents reason about tasks, not tables.
- It foregrounds preconditions, quotas, and receipts as first-class citizens, not afterthoughts.
- It encourages small, safe surfaces for agents even when the broader API is private or unstable.
- It can link to an OpenAPI document via a reference field when the action maps cleanly to a documented endpoint.
In practice, many websites will not expose a full API for every workflow. But most can expose 3 to 8 high-value intents safely. The manifest helps them do that without becoming a platform vendor.
CAPTCHAs, bot detection, and better alternatives
CAPTCHAs have three shortcomings for agentic automation:
- They confuse identity with humanity; many agents act on behalf of humans.
- They are brittle and accessibility-hostile.
- They drive an arms race that harms legitimate users.
Better patterns for read and low-risk actions:
- Quotas declared up front, enforced consistently.
- Proof-of-cost: small per-action charges or token burns; if costly to attack, abuse declines.
- Privacy Pass–style tokens issued upon human login or device attestation; redeemable by the agent to prove the user origin without re-challenges.
- Account-level trust scoring exposed via headers to shape rate limits without blocking.
For high-risk actions, use consent tokens with short lifetime and explicit parameters rather than CAPTCHAs.
Interoperability with schema.org, web app manifests, and search
- schema.org Actions introduced a notion of potentialAction on items, but adoption remains limited and focused on deep linking. The Actions Manifest borrows the idea of intent but moves enforcement, quotas, and receipts into scope.
- The web app manifest (manifest.json) describes install-time metadata for PWAs. An Actions Manifest is runtime capability for agents. They can co-exist; link from the PWA manifest to the actions manifest for discoverability.
- Search engines and agent directories can index manifests to annotate results: a hotel site that supports book_room and cancel_booking is more attractive to an agent than one that does not.
Example: restaurant reservations
A restaurant site may allow:
- search_tables: date, time, party_size, cuisine filters, location.
- hold_table: contact email or phone, hold duration.
- confirm_reservation: consent for a no-show fee up to a ceiling.
- cancel_reservation: idempotent cancellation with policy.
A minimal action for a no-show fee consent:
json{ "id": "confirm_reservation", "intent": "book_table", "method": "POST", "endpoint": "/agent/v1/reservations", "requestSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "hold_id": {"type": "string"}, "consent_token": {"type": "string"} }, "required": ["hold_id", "consent_token"] }, "preconditions": [ {"type": "login"}, {"type": "consent", "prompt": "Authorize a no-show fee up to USD 25."} ], "quotas": {"bucket": "account", "rate": "5/d"}, "receipts": {"enabled": true, "format": "jws"} }
Example: retail checkout with per-action limits
For e-commerce, start with query_inventory and add purchase with a per-transaction ceiling to reduce risk if an agent runs amok.
json{ "id": "purchase_item", "intent": "purchase", "method": "POST", "endpoint": "/agent/v1/orders", "requestSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "sku": {"type": "string"}, "quantity": {"type": "integer", "minimum": 1, "maximum": 5}, "shipping_address_id": {"type": "string"}, "payment_instrument": {"type": "string"}, "consent_token": {"type": "string"} }, "required": ["sku", "quantity", "shipping_address_id", "payment_instrument", "consent_token"] }, "preconditions": [ {"type": "login"}, {"type": "2fa"}, {"type": "consent", "prompt": "Authorize a purchase up to USD 250."} ], "quotas": {"bucket": "account", "rate": "3/h", "max_amount": {"currency": "USD", "amount": 250}}, "receipts": {"enabled": true, "format": "jws"} }
Security considerations
- Idempotency: Require an Idempotency-Key header for POST actions; include the key in receipts. This prevents accidental duplicates.
- CSRF and confusion: Agents should present audience-bound tokens (aud claim) and servers should verify allowed origins and redirect URIs. Avoid cookie-based ambient authority; prefer token-based auth for agent endpoints.
- Parameter injection: Rely on JSON Schema and explicit allowlists; reject unknown parameters by default.
- Replay: Use DPoP or mTLS; require nonce or replay windows for signed requests.
- SSRF and callbacks: If actions require webhook callbacks, publish a signing key and require HTTP message signatures on callbacks. Agents should verify before accepting state changes.
- Inventory races: Use pre-commit holds with explicit expiration; agents should not attempt direct purchases without a prior hold if race conditions are common.
Implementation guidance for websites
- Start with a tiny surface:
- One or two read actions (search, check availability).
- One reversible write action (hold, add-to-cart) with a 24-hour expiration.
- Publish /.well-known/actions-manifest.json and a link header.
- Reuse existing backends; add thin agent endpoints that share business logic with your core API or site.
- Add quotas, and return explicit retry_after on 429.
- Return receipts for all write actions; sign with JWS using a well-advertised JWKS endpoint.
- Add a consent endpoint and UI for human approvals; return short-lived consent tokens.
- Track success metrics: agent conversion vs human, false positives in bot detection, helpdesk issues. The numbers almost always justify the effort.
Implementation guidance for agentic browsers and frameworks
- Discovery: Try well-known path, then link headers. Cache manifests per origin with ETag and consider a freshness window.
- Policy alignment: Ask the user to opt in to automation per site; tie access to user identity and key material so receipts can be bound to the same key (DPoP jkt).
- Planning: Prefer actions with strong typing; avoid scraping when a manifest is present. Respect quotas and costs.
- Consent UX: Provide a clear, secure consent UI that highlights ceilings and reversibility.
- Error handling: Back off on quota_exceeded and unavailable; bubble up precondition_required to the user for remediation.
- Logging: Persist receipts securely and make them inspectable by the user.
Standardization path and community process
This proposal intentionally reuses existing standards where possible:
- JSON Schema for types.
- OAuth 2.1, DPoP (RFC 9449), and mTLS (RFC 8705) for auth.
- JWS (RFC 7515) and HTTP Message Signatures (RFC 9421) for receipts.
- Structured Field Values (RFC 8941) for concise headers.
What needs standardization:
- The manifest media type and well-known location.
- The vocabulary for preconditions and quotas.
- A common registry for intents (e.g., purchase, refund, hold, cancel, query_inventory, book_table, pay_invoice) with minimal semantics.
- A receipt claims set and verification profile.
A good home would be a W3C Community Group or an IETF working group, with participation from browser vendors, agent framework authors, and major websites in travel, retail, and services.
Business incentives: why websites should do this
- Higher conversion: Agents represent users with strong purchase intent. Make it easy for them.
- Lower fraud and abuse: Clear quotas and preconditions outperform bot heuristics and reduce false positives.
- Reduced support: Fewer broken scrapers and helpdesk tickets about lost carts or double charges.
- Auditability: Signed receipts simplify risk, chargeback disputes, and compliance.
- Visibility: Agent directories and search can badge sites with agent-ready actions, steering demand your way.
Privacy by design
- Minimize data: Only require parameters essential to the action. Do not echo PII in receipts unless necessary.
- Pseudonymous actors: Use account ids or subject identifiers appropriate to the action; avoid IP-based gating when possible.
- Differential privacy for analytics: Aggregate agent usage with privacy-preserving techniques rather than raw logs.
- Short-lived tokens and consent: Expire consent tokens quickly; bind to parameters and ceilings.
A minimal JSON Schema for the manifest
Below is a simplified JSON Schema sketch you can adapt. It is not exhaustive, but it is enough to validate shape and types.
json{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://example.org/schemas/actions-manifest.json", "type": "object", "required": ["version", "issuer", "updated", "actions"], "properties": { "version": {"type": "string"}, "issuer": {"type": "string", "format": "uri"}, "updated": {"type": "string", "format": "date-time"}, "policy": { "type": "object", "properties": { "terms": {"type": "string", "format": "uri"}, "automation": {"type": "string", "format": "uri"} } }, "actions": { "type": "array", "items": { "type": "object", "required": ["id", "intent", "method", "endpoint", "requestSchema"], "properties": { "id": {"type": "string"}, "intent": {"type": "string"}, "title": {"type": "string"}, "description": {"type": "string"}, "method": {"type": "string", "enum": ["GET", "POST", "PUT", "DELETE"]}, "endpoint": {"type": "string"}, "requestSchema": {"type": "object"}, "responseSchema": {"type": "object"}, "auth": { "type": "object", "properties": { "type": {"type": "array", "items": {"type": "string"}}, "scopes": {"type": "array", "items": {"type": "string"}} } }, "preconditions": { "type": "array", "items": { "type": "object", "properties": { "type": {"type": "string"} }, "required": ["type"] } }, "quotas": { "type": "object", "properties": { "bucket": {"type": "string"}, "rate": {"type": "string"}, "burst": {"type": "integer"}, "concurrency": {"type": "integer"}, "cost": {"type": "object", "properties": {"currency": {"type": "string"}, "amount": {"type": "number"}}}, "max_amount": {"type": "object", "properties": {"currency": {"type": "string"}, "amount": {"type": "number"}}} } }, "receipts": { "type": "object", "properties": { "enabled": {"type": "boolean"}, "format": {"type": "string", "enum": ["jws", "http-signature"]}, "fields": {"type": "array", "items": {"type": "string"}} } }, "examples": {"type": "array"}, "safety": {"type": "object"} } } } } }
HTTP examples
Linking the manifest via headers:
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Link: <https://air.example/.well-known/actions-manifest.json>; rel="actions-manifest"
A hold request with idempotency and DPoP:
POST /agent/v1/holds HTTP/1.1
Host: air.example
Authorization: DPoP eyJhbGciOi...
DPoP: eyJhbGciOi...
Content-Type: application/json
Idempotency-Key: 0b3f4c12-5d22-4d0b-9b0c-8f0f9b31ef02
{"itinerary_id":"ITN-4421","passenger_count":2,"contact":{"email":"alice@example.org"}}
A successful response with a signed-receipt header:
HTTP/1.1 201 Created
Content-Type: application/json
Receipt-JWS: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2Fpci5leGFtcGxlIiw...<snip>
{"hold_id":"H123","expires_at":"2025-10-21T13:00:00Z","price_locked":"USD 1299.00"}
Migration strategy and incremental adoption
- Phase 0: Publish a manifest with read-only actions and quotas. Make it non-breaking; continue serving the existing site.
- Phase 1: Add reversible actions (holds, add-to-cart). Introduce receipts and idempotency.
- Phase 2: Add purchases behind consent tokens and per-action ceilings. Introduce 2FA and DPoP.
- Phase 3: Optimize: better schemas, response compression, and test sandboxes for agents.
Each phase yields value. Even read-only manifests dramatically reduce scraping breakage and support tickets.
Open questions and future work
- Standardized intent registry: How much shared meaning do we need to enable cross-site planning without per-site adapters?
- Consent UX: What are the most usable patterns for cross-device, low-latency approvals? Passkeys and push notifications look promising.
- Privacy Pass tokens: Can we mainstream token-based challenge alternatives to CAPTCHAs for read endpoints?
- Signed state continuity: For multi-step flows (search → hold → purchase), can we standardize a signed state object to reduce tampering and data drift?
- Observability: How should sites expose non-sensitive metrics to agents (queue depth, expected latency) to encourage backoff?
Conclusion
The web has a clear way to say do not crawl here. It lacks a way to say you may act here, under these explicit conditions. In a world of agentic browsers, that gap is the difference between a functional ecosystem and a perpetual bot war.
An Actions Manifest is deliberately modest: a directory of intents, types, preconditions, quotas, and receipts. It leverages what already works on the web, clarifies expectations for both sides, and reduces the need for brittle scraping and CAPTCHAs. Most importantly, it builds trust. Users get control and proof of what happened; sites get safety and conversions; agents get reliability.
This is the right layer to standardize next. It fits how the web evolves: small, incremental, and permissionless. Publish a file, add a couple of endpoints, and watch the arms race give way to collaboration.
