The Open Primitive Protocol (OPP) defines a standard interface for serving public government data to both human readers and autonomous agents. It solves the problem of fragmented, undocumented, and unsourced federal data APIs by requiring every response to carry its source, freshness, and optional cryptographic proof. OPP is designed for data providers who publish public-interest information and for agent developers who need structured, verifiable data without scraping or guesswork.
The key words MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD, SHOULD NOT, RECOMMENDED, MAY, and OPTIONAL in this document are to be interpreted as described in RFC 2119.
Additional terms used in this specification:
/.well-known/opp.json that describes the provider's domains, endpoints, and capabilities.OPP defines three components:
OPP is designed for compatibility with existing protocols and standards:
mcpServer discovery URL.agentCard discovery URL.@context for semantic interoperability.All OPP endpoints MUST be served over HTTP or HTTPS. Public providers SHOULD use HTTPS. All request and response bodies MUST be JSON. Providers MAY include a JSON-LD @context field for linked data compatibility.
The provider manifest MUST be served at /.well-known/opp.json relative to the provider's base URL. The Content-Type header MUST be application/json.
| Field | Type | Status | Description |
|---|---|---|---|
| @context | string | Required | JSON-LD context URL. MUST be "https://openprimitive.com/ns/opp/v1". |
| name | string | Required | Human-readable name of this OPP instance. |
| description | string | Required | One-sentence description of what this provider serves. |
| version | string | Required | Version of this manifest (semver). Distinct from protocolVersion. |
| protocolVersion | string | Required | OPP protocol version implemented. MUST be "0.1.0" for this specification. |
| provider | object | Required | Information about the organization operating this provider. See provider object. |
| domains | array | Required | List of data domains served. MUST contain at least one entry. See domain object. |
| endpoints | object | Required | See endpoints object. |
| discovery | object | Optional | URLs for additional discovery mechanisms. See discovery object. |
| geographic | object | Optional | Geographic coverage metadata. See geographic object. |
| authentication | object | Optional | Authentication requirements. See authentication object. |
| lastUpdated | string | Required | ISO 8601 datetime of the last manifest update. |
| Field | Type | Status | Description |
|---|---|---|---|
| name | string | Required | Organization name. |
| url | string | Required | Organization website. MUST be a valid URL. |
| contact | string | Optional | Contact email or URL for protocol-related inquiries. |
| publicKey | string | Optional | Base64url-encoded Ed25519 public key used for response signing. REQUIRED for Level 3 (Verified) conformance. |
| Field | Type | Status | Description |
|---|---|---|---|
| id | string | Required | Unique identifier for this domain. Lowercase, hyphenated (e.g., food-recalls). |
| name | string | Required | Human-readable domain name. |
| source | string | Required | Name of the upstream data source (e.g., "FDA openFDA API"). |
| entityTypes | array of strings | Required | Types of entities returned (e.g., ["recall", "enforcement"]). |
| freshness | string | Required | Expected update cadence. One of: realtime, hourly, daily, weekly, monthly, quarterly, annual. |
| license | string | Required | SPDX license identifier or URL for the upstream data license. |
| endpoint | string | Required | Relative path to this domain's query endpoint (e.g., /api/food-recalls). |
| Field | Type | Status | Description |
|---|---|---|---|
| base | string | Required | Base URL for all API endpoints. MUST be a valid URL without a trailing slash. |
| query | string | Required | Relative path to the general query endpoint (e.g., /api/query). |
| Field | Type | Status | Description |
|---|---|---|---|
| openapi | string | Optional | URL to an OpenAPI 3.x specification document. |
| llms | string | Optional | URL to an llms.txt file describing the provider for LLM consumption. |
| mcpServer | string | Optional | URL to an MCP server endpoint. |
| agentCard | string | Optional | URL to an A2A agent card. |
| Field | Type | Status | Description |
|---|---|---|---|
| scope | string | Optional | Geographic scope of the data. Examples: "US", "US-CA", "global". |
| granularity | string | Optional | Finest geographic resolution available. One of: national, state, county, city, zip, address. |
| Field | Type | Status | Description |
|---|---|---|---|
| type | string | Required | Authentication type. One of: none, apiKey, bearer. |
| header | string | Optional | HTTP header name for the authentication credential. Defaults to Authorization. Only applicable when type is apiKey or bearer. |
{
"@context": "https://openprimitive.com/ns/opp/v1",
"name": "Open Primitive API",
"description": "US federal data across 16 domains from 11 agencies.",
"version": "1.0.0",
"protocolVersion": "0.1.0",
"provider": {
"name": "Open Primitive",
"url": "https://openprimitive.com",
"contact": "david@openprimitive.com",
"publicKey": "z6MkhaXg..."
},
"domains": [
{
"id": "food-recalls",
"name": "Food Recalls",
"source": "FDA openFDA API",
"entityTypes": ["recall", "enforcement"],
"freshness": "daily",
"license": "US-PD",
"endpoint": "/api/food-recalls"
}
],
"endpoints": {
"base": "https://api.openprimitive.com",
"query": "/api/query"
},
"discovery": {
"openapi": "https://api.openprimitive.com/openapi.json",
"llms": "https://api.openprimitive.com/llms.txt",
"mcpServer": "https://api.openprimitive.com/mcp",
"agentCard": "https://api.openprimitive.com/.well-known/agent.json"
},
"geographic": {
"scope": "US",
"granularity": "zip"
},
"authentication": {
"type": "none"
},
"lastUpdated": "2026-03-19T00:00:00Z"
}
Every response from an OPP endpoint MUST return a JSON object conforming to the envelope schema. The envelope carries source metadata alongside the domain-specific payload, so that no response exists without provenance.
| Field | Type | Status | Description |
|---|---|---|---|
| domain | string | Required | Domain identifier matching a domains[].id in the manifest. |
| source | string | Required | Name of the upstream data source. |
| source_url | string | Required | Direct URL to the upstream data source. MUST be a valid URL. |
| freshness | string | Required | ISO 8601 datetime indicating when this data was last fetched from the upstream source. |
| data | object | Required | The domain-specific payload. Structure varies by domain. Providers SHOULD document the schema per domain. |
| confidence | object | Optional | Data quality metadata. See confidence object. |
| citations | object | Optional | Source citation for the data. See citations object. |
| version | object | Optional | Version information for data, schema, and protocol. See version object. |
| proof | object | Optional | Cryptographic proof of data integrity. See proof object. |
| Field | Type | Status | Description |
|---|---|---|---|
| completeness | number | Optional | A value between 0 and 1 indicating how complete the data is relative to the full upstream dataset. 1.0 means full coverage. 0.5 means roughly half of available records are represented. |
| methodology | string | Optional | Brief description of how the data was collected, filtered, or transformed. |
| note | string | Optional | Any caveats or known limitations of this particular response. |
| Field | Type | Status | Description |
|---|---|---|---|
| statement | string | Optional | A human-readable attribution statement (e.g., "Data from the FDA openFDA enforcement database"). |
| source_name | string | Optional | Name of the cited source. |
| source_url | string | Optional | URL to the cited source. MUST be a valid URL when present. |
| accessed | string | Optional | ISO 8601 datetime of when the source was last accessed. |
| license | string | Optional | SPDX license identifier or URL for the data license. |
| Field | Type | Status | Description |
|---|---|---|---|
| data | string | Optional | Temporal version of the data (e.g., "2026-03-19" or "Q1-2026"). |
| schema | string | Optional | Semver of the domain-specific schema (e.g., "2.1.0"). |
| protocol | string | Optional | OPP protocol version used to generate this response. MUST match the manifest's protocolVersion. |
| Field | Type | Status | Description |
|---|---|---|---|
| type | string | Required | MUST be "DataIntegrityProof". |
| cryptosuite | string | Required | MUST be "eddsa-jcs-2022". |
| verificationMethod | string | Required | URL resolving to the provider's public key. This SHOULD reference the manifest's provider.publicKey or a DID document. |
| created | string | Required | ISO 8601 datetime of when the proof was generated. |
| proofValue | string | Required | Base64url-encoded Ed25519 signature over the canonicalized JSON response (excluding the proof field itself). |
{
"domain": "food-recalls",
"source": "FDA openFDA API",
"source_url": "https://api.fda.gov/food/enforcement.json",
"freshness": "2026-03-19T08:00:00Z",
"data": {
"results": [
{
"product": "Organic Peanut Butter",
"reason": "Salmonella contamination",
"classification": "Class I",
"status": "Ongoing",
"date": "2026-03-18"
}
],
"total": 1
},
"confidence": {
"completeness": 0.95,
"methodology": "Direct FDA API query, filtered to last 30 days",
"note": "FDA data may lag 24-48 hours behind actual recall announcements"
},
"citations": {
"statement": "Data from the FDA openFDA enforcement database",
"source_name": "FDA openFDA",
"source_url": "https://open.fda.gov/apis/food/enforcement/",
"accessed": "2026-03-19T08:00:00Z",
"license": "US-PD"
},
"version": {
"data": "2026-03-19",
"schema": "1.0.0",
"protocol": "0.1.0"
},
"proof": {
"type": "DataIntegrityProof",
"cryptosuite": "eddsa-jcs-2022",
"verificationMethod": "https://api.openprimitive.com/.well-known/opp.json#provider",
"created": "2026-03-19T08:00:01Z",
"proofValue": "z58DAdFfa9SkqZMVPxAQpic7ndTn..."
}
}
All OPP data endpoints MUST accept GET requests. Providers MAY additionally support POST for complex queries, but GET is the baseline.
Query parameter names SHOULD use lowercase, with words separated by underscores (e.g., zip_code, date_from). Providers MUST document accepted parameters per domain in their OpenAPI specification or equivalent documentation.
Providers that return lists SHOULD support pagination using limit and offset parameters. Default limit SHOULD be between 10 and 100. Providers MUST document the maximum allowed limit.
When a request fails, the response MUST return a JSON object with an error field containing a human-readable error message. The HTTP status code MUST be appropriate to the error:
| Status | Meaning | Use when |
|---|---|---|
| 400 | Bad Request | Invalid or missing query parameters. |
| 404 | Not Found | The requested domain or entity does not exist. |
| 429 | Too Many Requests | Rate limit exceeded. |
| 500 | Internal Server Error | Upstream source failure or internal error. |
| 502 | Bad Gateway | Upstream data source returned an invalid response. |
| 503 | Service Unavailable | Upstream data source is temporarily unreachable. |
Example error response:
{
"error": "Missing required parameter: zip_code"
}
Public providers MUST set the Access-Control-Allow-Origin header to * on all responses. Providers that require authentication MAY restrict the origin list, but MUST still support CORS preflight requests.
All responses MUST include the header Content-Type: application/json.
The manifest at /.well-known/opp.json serves as the primary discovery mechanism for OPP providers. Any client that knows a provider's base URL can fetch the manifest and learn what domains are available, where to query them, and how to verify responses.
Providers SHOULD publish at least one additional discovery mechanism to maximize reachability across different consumer types:
discovery.openapi.discovery.llms.discovery.mcpServer.discovery.agentCard.Consumers SHOULD check for /.well-known/opp.json first. If it exists, the consumer has everything needed to interact with the provider. The additional discovery URLs are convenience entry points for ecosystems that do not natively understand OPP.
Verification is optional. Providers that choose to sign responses gain Level 3 (Verified) conformance and give consumers a way to detect tampering between the provider and the end user.
Providers that sign responses MUST use Ed25519 with the eddsa-jcs-2022 cryptosuite, as defined in the W3C Data Integrity EdDSA Cryptosuites specification.
The Ed25519 public key MUST be included in the provider manifest at provider.publicKey, encoded as a base64url string. Providers SHOULD rotate keys by publishing a new manifest with the updated key and re-signing subsequent responses. Old responses signed with the previous key remain valid against that key.
proof).proof object to the response with type, cryptosuite, verificationMethod, created, and proofValue fields.A consumer verifies a signed response with these steps:
/.well-known/opp.json.provider.publicKey.proof field from the response object.proof.proofValue from base64url.If verification fails, the consumer SHOULD treat the response as untrusted. The consumer MAY still use the data but MUST NOT represent it as verified.
OPP is designed to work without centralized coordination. Any organization can publish a manifest and serve data. Federation adds an optional layer for discovery across providers.
Providers MAY register with one or more OPP registries. A registry is a service that indexes provider manifests and exposes a search interface.
Registries SHOULD support search by:
food-recalls).recall).US, EU).No registry is authoritative. Multiple registries MAY index the same provider. Consumers MAY query multiple registries and merge results. When two providers serve the same domain, the consumer decides which to trust based on freshness, conformance level, and verification status.
The registry protocol is not defined in this version of the specification. A future version will specify the registry manifest format, search API, and registration process.
OPP uses three distinct version numbers, each tracking a different rate of change.
Tracked in manifest.protocolVersion. Uses semantic versioning (semver). The current protocol version is 0.1.0.
Tracked per domain in response.version.schema. Each domain defines its own payload structure, and that structure versions independently from the protocol. A provider MAY update a domain schema without changing the protocol version.
Tracked temporally in response.version.data. This represents the vintage of the data, not the structure. A data version of "2026-03-19" means the data reflects the state of the upstream source as of that date.
New fields added to the envelope or manifest are always additive and constitute a minor version bump. Consumers MUST ignore fields they do not recognize. Removing a field or changing the type or semantics of an existing field requires a major version bump.
OPP defines three conformance levels. Each level builds on the previous one. A provider claims a level by meeting all of its requirements.
Provider publishes a valid manifest at /.well-known/opp.json. Every response includes the required envelope fields: domain, source, source_url, freshness, and data.
All Level 1 requirements, plus every response includes a confidence object and a citations object. Consumers can assess data quality and trace information back to the original source.
All Level 2 requirements, plus every response includes an Ed25519 proof object. The provider's public key is published in the manifest. Consumers can cryptographically verify that the response has not been altered.
Providers SHOULD indicate their conformance level in their documentation and llms.txt. There is no certification process. Conformance is self-declared and verifiable by any consumer that checks the manifest and response structure.
A provider that includes proof on some responses but not all MUST NOT claim Level 3. Conformance applies to the provider as a whole, across all domains and endpoints.