OpenTerms Specification
Machine-readable legal terms for the agentic web. Define what AI agents can and can't do on your service — in a format they can actually parse.
OpenTerms is a JSON-based protocol that lets services declare their terms of service, permissions, rate limits, and compliance requirements in a structured format. Think of it as robots.txt for AI agent behavior.
New in v0.2.0: JSON-LD support (@context), policy identifiers (policy_id), ORS verification integration, HIPAA compliance fields, data residency, permission scoping/frequency, and an extensions namespace.
Quick Start
Create an openterms.json file and host it at the root of your domain:
{
"$schema": "https://openterms.com/schema/openterms.schema.json",
"openterms_version": "0.2.0",
"service": {
"name": "Your Service",
"domain": "yourservice.com",
"tos_url": "https://yourservice.com/terms"
},
"permissions": {
"read_content": true,
"create_account": false,
"make_purchases": false,
"scrape_data": false,
"api_access": true,
"browser_automation": false
},
"requires_consent": true,
"jurisdiction": "US",
"contact": "legal@yourservice.com",
"last_updated": "2025-06-01"
}
That's it. AI agents fetch https://yourservice.com/openterms.json before taking any action, just like crawlers check robots.txt.
Pro tip: Add the $schema field to get auto-completion and inline validation in VS Code, JetBrains, and other editors that support JSON Schema.
How It Works
- Services publish an
openterms.jsonat their domain root (or any discoverable URL) - Agents query the file before taking actions — permissions are structured data, not legalese
- Compliance is automatic — every agent action has a legal basis on record, with optional cryptographic receipts via ORS
Core Fields
| Field | Type | Status | Description |
|---|---|---|---|
openterms_version |
string |
Required | Spec version (e.g. "0.2.0"). Semver format. |
service |
string | object |
Required | Service info. Shorthand: "acme.com". Full: object with name, domain, tos_url, privacy_url, description, logo_url. |
permissions |
object |
Required | What agents can do. See Permissions section. |
$schema |
string (URI) |
Optional | Self-referencing schema URI. Enables editor auto-completion. |
@context |
string | object |
New | JSON-LD context for semantic web / linked data interoperability. |
policy_id |
string |
New | Globally unique identifier for this terms document. Used in ORS receipts and audit trails. |
requires_consent |
boolean |
Optional | Must the agent obtain explicit consent before acting? |
jurisdiction |
string | string[] |
Optional | ISO 3166-1/2 jurisdiction code(s). E.g. "US-DE", ["US-CA", "EU"]. |
contact |
string | object |
Optional | Legal contact. Shorthand: email string. Full: object with email, name, url. |
last_updated |
string (date) |
Optional | ISO 8601 date when terms were last modified. |
expires |
string (date) |
Optional | Date these terms expire. Agents should re-fetch after this date. |
Permissions
The permissions object defines what AI agents can do. Each value is either:
true— allowed unconditionallyfalse— denied- Conditional object — allowed with conditions
Standard Permissions
| Permission | Description |
|---|---|
read_content | Read publicly available content |
create_account | Create user accounts |
make_purchases | Make purchases or financial transactions |
scrape_data | Scrape or bulk-download data |
post_content | Post, publish, or submit content |
modify_data | Modify existing data or settings |
delete_data | Delete data |
automated_messaging | Send messages to users |
api_access | Access the service's API |
browser_automation | Use browser automation tools |
execute_code | Execute code on the platform New |
access_user_data | Access personal or user-specific data New |
Custom permissions are also allowed — the schema accepts any additional string keys with permission values.
Conditional Permission Object
{
"make_purchases": {
"allowed": true,
"conditions": "Max $500/day. Agent must be linked to verified human.",
"requires_auth": true,
"max_frequency": "50/day",
"scope": "authenticated"
}
}
| Field | Type | Description |
|---|---|---|
allowed | boolean | Required Whether the permission is granted. |
conditions | string | Human-readable conditions or restrictions. |
requires_auth | boolean | Whether this permission requires authentication. |
max_frequency | string | Rate limit for this specific action. E.g. "10/hour", "100/day". New |
scope | string | What data subset this applies to. E.g. "public", "authenticated", "premium". New |
Rate Limits
{
"rate_limits": {
"requests_per_minute": 60,
"requests_per_hour": 1000,
"requests_per_day": 10000,
"concurrent_sessions": 5
}
}
All fields are optional integers. concurrent_sessions is new in v0.2.0 and limits how many simultaneous agent connections are allowed.
Data Handling
{
"data_handling": {
"stores_agent_data": true,
"shares_with_third_parties": false,
"retention_days": 90,
"gdpr_compliant": true,
"ccpa_compliant": true,
"hipaa_compliant": false,
"data_residency": ["US", "EU"]
}
}
| Field | Type | Description |
|---|---|---|
stores_agent_data | boolean | Stores data about agent interactions? |
shares_with_third_parties | boolean | Shares agent data with third parties? |
retention_days | integer | Days data is retained. 0 = no retention. |
gdpr_compliant | boolean | GDPR compliant? |
ccpa_compliant | boolean | CCPA compliant? |
hipaa_compliant | boolean | HIPAA compliant? New |
data_residency | string | string[] | Where data is stored. ISO codes. New |
Authentication
{
"authentication": {
"required": true,
"methods": ["api_key", "oauth2"],
"registration_url": "https://acme.com/developers",
"docs_url": "https://docs.acme.com/auth"
}
}
Supported methods: api_key, oauth2, bearer_token, basic_auth, mTLS New, none.
The docs_url field is new in v0.2.0 — link directly to your auth documentation for faster agent onboarding.
Verification
New in v0.2.0. Enables ORS (Open Receipt Specification) integration — cryptographic receipts proving an agent acknowledged your terms before acting.
{
"verification": {
"jwks_url": "https://acme.com/.well-known/jwks.json",
"signing_algorithm": "Ed25519",
"policy_hash": "a1b2c3d4e5f6..."
}
}
| Field | Type | Description |
|---|---|---|
jwks_url | string (URI) | URL to your JWKS endpoint for verifying signed receipts. |
signing_algorithm | string | One of: Ed25519, RS256, ES256. |
policy_hash | string | SHA-256 hash of the canonical terms document. 64 hex chars. |
How ORS + OpenTerms work together: OpenTerms defines what agents can do. ORS provides cryptographic proof they acknowledged those terms. The policy_id field links your terms to ORS receipts.
Extensions
The extensions object is a namespace for custom or industry-specific fields. Use reverse-domain notation to avoid conflicts:
{
"extensions": {
"health.hipaa.baa_required": true,
"health.hipaa.audit_log_url": "https://acme.com/api/audit",
"com.acme.internal_tier": "enterprise",
"org.fintech.pci_dss_level": 1
}
}
Extensions are free-form — any JSON value is accepted. This keeps the core schema stable while allowing domain-specific needs.
Examples
Complete, validated examples for common use cases:
| Use Case | File | Key Features |
|---|---|---|
| SaaS API | saas-api.json |
Full API with OAuth, rate limits, conditional purchases, sandboxed code execution |
| E-Commerce | ecommerce.json |
Purchase limits, product scraping with conditions, multi-jurisdiction |
| Social Platform | social-platform.json |
AI disclosure requirements, DM opt-in, frequency limits per permission |
| Open/Public API | open-api.json |
Minimal restrictions, high rate limits, no auth required |
| Healthcare (HIPAA) | healthcare.json |
HIPAA fields, ORS verification, BAA requirement, extensions namespace, mTLS auth |
Load any example directly in the Validator to explore it interactively.
Adoption Guide
Step 1: Create your openterms.json
Start with the Quick Start template. Add permissions that match your service's terms of service. Be explicit — false is better than omitting a permission.
Step 2: Host it
Place the file at https://yourdomain.com/openterms.json — the standard discovery path. Alternatively, reference it from your existing robots.txt:
# AI Agent Terms OpenTerms: https://yourdomain.com/openterms.json
Step 3: Validate
Use the interactive validator or the programmatic API:
curl -X POST https://openterms.com/api/validate \
-H "Content-Type: application/json" \
-d '{"content": <your openterms.json>}'
Step 4: Keep it updated
Update last_updated whenever you change terms. Set expires to force agents to re-fetch periodically.
ORS Integration
The Open Receipt Specification (ORS) provides cryptographic receipts proving AI agents acknowledged specific policies before taking actions.
OpenTerms + ORS together create a complete policy lifecycle:
- OpenTerms declares what's allowed (the policy)
- ORS proves an agent read and acknowledged that policy (the receipt)
- The
policy_idlinks the two together
To enable ORS, add the verification and policy_id fields to your openterms.json. See the Healthcare example for a complete implementation.
CI/CD Validation
Validate your openterms.json in CI/CD pipelines using the API endpoint:
- name: Validate openterms.json
run: |
RESULT=$(curl -s -X POST https://openterms.com/api/validate \
-H "Content-Type: application/json" \
-d "{\"content\": $(cat openterms.json)}")
echo "$RESULT" | jq .
VALID=$(echo "$RESULT" | jq -r '.valid')
if [ "$VALID" != "true" ]; then
echo "openterms.json validation failed!"
exit 1
fi
// package.json
{
"scripts": {
"validate:terms": "curl -sf -X POST https://openterms.com/api/validate -H 'Content-Type: application/json' -d '{\"content\":'$(cat openterms.json)'}' | jq -e '.valid'"
}
}