Appendix B - Protocol and API Reference
This appendix provides rules for reading and implementing the interfaces. Paths, fields, and statuses are cross-checked against each node’s service entry points, oan-protocol-common/schemas/agent-contract/openapi.yaml, the frontend and backend API wrappers on the official website, and actual deployment configuration; capabilities declared only in the common contract must not be written as if they were exposed by all nodes. Interface changes must be associated with the protocol version, error pattern, authentication method, idempotency rules, and the change record in Chapter 24.
B.1 Endpoint Catalog
The endpoint catalog lists health, DID, resource registration, Root platform publication, content distribution, discovery, governance status, and statistics interfaces by service role, and distinguishes public entry points, node-to-node entry points, internal-only entry points, and deployment prefixes. The official website currently forwards some registration and discovery requests through a same-origin backend; the nodes themselves also expose independent service endpoints, so website paths cannot automatically be inferred as protocol paths for all nodes. Example base URLs use placeholders and do not hard-code the website’s current domain or a particular server address as a protocol requirement; each row records at least the call direction, HTTP method, authentication, request/response pattern, failure behavior, and version. The table below lists only representative entry points that can be verified in the current code; management, statistics, and debugging interfaces not listed here remain subject to the routes of their corresponding nodes.
| Service role | Call direction, method, and path | Authentication boundary | Main returns |
|---|---|---|---|
| Registrar node | Client -> Registrar node: POST /resources/register; Client -> Registrar node: GET /registrar/status, GET /registrar/did |
The registration endpoint receives a resource control proof; node-to-node forwarding to the Root platform uses node-to-node signatures | Registration VC, acceptance status, Root platform response |
| Root platform | Registrar node -> Root platform: POST /root/resources/verify-and-publish; Client or node -> Root platform: GET /root/resources/{did}, GET /root/status |
Publication writes are limited to authorized nodes or administrative calls; public reads depend on deployment | Root proof, resource version, status, and cursor |
| content distribution platform | Root platform or publisher -> content distribution platform: POST /cdn/resources, POST /cdn/resources/batch; Client or node -> content distribution platform: GET /cdn/resources/{did}, GET /cdn/resources/index |
Publication uses node-to-node authentication; resource reads and index reads depend on deployment | ResourcePackage, index entries, synchronization status |
| Discovery node | Client -> Discovery node: POST /discovery/resources/query; Node or operations personnel -> Discovery node: GET /discovery/index/resources/{did}, GET /discovery/status |
Queries may be public; management and synchronization interfaces are restricted | Resource results, source, and proof references |
| Operations API | Operations personnel -> node: GET /health and node status, metrics, and audit interfaces |
Operations authentication and network boundary | Status summary, without secrets |
The correspondence between core payload types and endpoints is as follows. When shared types come from oan-protocol or oan-package, field names follow the JSON mapping of serde; Value represents a dynamic response in the current implementation and cannot be used to infer a fixed schema that does not exist.
| Endpoint | Request JSON type | Response type or main fields | Notes |
|---|---|---|---|
POST /resources/register |
ResourceRegistrationSubmission |
Dynamic JSON: registration status, resource DID, registration VC, Root platform response | /resources/submit is bound to the same handler |
POST /root/resources/verify-and-publish |
ResourceVerifyAndPublishRequest |
Dynamic JSON: resource-verified-and-queued, version, three categories of hashes, and CDN queue status |
Node-to-node call limited to authorized Registrar nodes |
POST /cdn/resources |
ResourceCdnPublishRequest |
Dynamic JSON: published, version, and publication cursor |
ResourcePackage must pass Root platform source and hash validation |
POST /discovery/resources/query |
ResourceDiscoveryQuery |
ResourceDiscoveryResponse |
limit defaults to 10, versionMode defaults to latest |
POST /discovery/query/explain |
ResourceDiscoveryQuery |
Dynamic explanation JSON | Not equivalent to a normal discovery response |
GET /cdn/resources/{did} |
Path parameter did |
ResourcePackage |
Reads a ResourcePackage directly |
POST /cdn/resources/batch-get |
Local ResourceBatchGetRequest |
requestedCount, foundCount, items |
The request body contains a resourceDids array |
B.2 Request Header Fields and Signatures
Request headers and signature materials are defined by the interface profile. The current node-to-node SignedRequestEnvelope uses JSON fields such as requestId, protocolVersion, purpose, method, path, aud, requestTimestamp, requestNonce, bodyHash, and proof to carry signature semantics; the browser-facing public registration and discovery entry points on the official website must not arbitrarily add a set of required X-OAN-* headers that are not defined at the service entry point. If the interface uses a protocol envelope to carry this information, the JSON fields take precedence; if the deployment layer additionally uses HTTP headers, they may only be documented as deployment-profile details. The server must validate the normalized request covered by the signature, the target DID, the time window, and the nonce; it must reject missing, expired, replayed, or misdirected requests.
The roles of node-to-node protocol envelope fields can be checked against the table below. method and path bind the protected HTTP request, aud binds the recipient, and bodyHash binds the request body; together, these fields prevent a valid proof issued by one node from being moved to another request. When a browser submits a resource, the resource control proof is located in the request body’s subjectControlProof; it must not be mistakenly written as a node-to-node HTTP header.
| Field | Purpose | Validation focus |
|---|---|---|
requestId |
Identifies one node-to-node request | Used for log correlation; cannot replace replay protection |
protocolVersion, purpose |
Identifies the protocol version and call purpose | Must match the profile allowed by the receiving interface |
method, path, aud |
Binds the HTTP method, path, and recipient | Must not differ from the actual request or target node |
requestTimestamp, requestNonce |
Restricts the time range and prevents reuse | Check the clock window and nonce replay cache |
bodyHash, proof |
Binds the request body and provides an integrity proof | Recalculate the request-body digest and validate the proof |
POST /resources/register
Host: registrar.example
Content-Type: application/json
The upstreamAuth.proof of a node-to-node request should cover the method, normalized path, recipient, timestamp/nonce, content digest, and actual request body; the server should perform the write only after completing the time-window, replay-cache, signer-authorization, and resource-control checks. In a browser registration request, the resource control proof is located in the request body’s subjectControlProof; it is not the same type of credential as node-to-node upstreamAuth.
B.3 Response Header Fields and Cache Directives
A response may provide the source, protocol/mode version, data time, freshness, ETag, cache control, correlation identifier, and necessary security headers when applicable; these fields are not guaranteed to be uniform public response headers across all current node interfaces, and the X-* items below may only serve as deployment-layer or interface-profile extension conventions. An ETag or cache hit only indicates that the content version has not changed; it does not prove that the resource status or governance authorization remains valid. When returning an old snapshot, the response or body should include identifiable time and degradation indicators; caching must not be used to conceal an upstream failure.
| Field or directive (when applicable) | Purpose | Usage notes |
|---|---|---|
ETag |
Identifies the response content version | Does not mean that the governance status is valid |
Cache-Control |
Specifies caching and revalidation policy | An old snapshot must also identify its freshness |
X-Request-Id |
Correlates the client, nodes, and logs | Must not contain private information |
X-OAN-Data-Time |
Indicates the data generation or collection time | Distinguish it from the server response time |
X-OAN-Freshness |
Indicates statuses such as current and stale |
Must not conceal an upstream failure |
B.4 Status Codes and Error Codes
HTTP status codes express transport-layer and generic processing results, while OpenAgenet (OAN) error codes express specific semantics such as field errors, invalid signatures, unauthorized access, not found, duplication, version conflicts, dependency failures, synchronization lag, and internal errors. The current public error-code vocabulary is defined by oan-protocol-common/docs/error-codes.md, including invalid_did_document_structure, invalid_registration_credential, invalid_request_signature, unauthorized_domains, invalid_root_proof, and package_decode_failed; that file defines error semantics but does not bind every error code to a unique HTTP status. Different nodes may map these errors through an HTTP status or response body. Clients should determine whether to retry from the actual error structure; they must not treat every 2xx response as publication success, nor conflate 404, empty results, and synchronization incomplete.
| HTTP status | OAN error code examples | Client action |
|---|---|---|
400 |
invalid_did_document_structure, invalid_authorized_domains, package_decode_failed |
Correct the input or ResourcePackage and retry; the specific status depends on the interface implementation |
401/403 |
invalid_request_signature, unauthorized_domains |
Re-authenticate, use an authorized node, or stop the request |
404 |
Resource-not-found error returned by the node | Distinguish not found from an unsynchronized index |
409 |
Duplicate or version-conflict error returned by the node | Obtain the current version and process it according to the update rules |
429 |
Deployment-layer rate-limit error | Follow the retry indication and back off |
5xx |
Dependency unavailable or internal error | Back off and retry only when the interface marks the request as retryable |
B.5 Pagination and Cursor Rules
List interfaces use explicit limit, cursor, and sorting rules. Cursors may only be generated and interpreted by the server; clients must not assume that they are readable or modifiable. The current public ResourceDiscoveryQuery type always provides limit, with a default value of 10, but the request model of POST /discovery/resources/query has no cursor field; the Discovery node truncates candidate results according to limit. The interface that actually provides afterCursor, nextCursor, and hasMore is the content distribution platform’s GET /cdn/resources/index; its cursor is not the same type as the discovery query’s limit. Page size should have a deployment limit, and the sort key must remain stable during pagination; expired, invalid, or filter-mismatched cursors should return an error. Publication cursors, synchronization cursors, event cursors, and pagination cursors must not be used interchangeably.
GET /cdn/resources/index?limit=20&afterCursor=1800
Accept: application/json
{
"items": [],
"count": 0,
"afterCursor": 1800,
"nextCursor": 1800,
"hasMore": false
}
A pagination cursor only represents the reading position in the content distribution platform’s list; the limit in a discovery query only controls the number of candidate results for that request and does not produce a resumable discovery pagination cursor. Publication sequences, distribution synchronization cursors, and governance event cursors must use the fields and validation rules defined by their respective interfaces.
B.6 Version and Compatibility Header Fields
Protocol versions, resource schema versions, capability declarations, and compatibility policies are expressed through defined protocol envelope fields, request-body fields, or deployment profiles, and remain traceable in requests and responses. Current public protocol constants include oan-resource-2026, while the default value of ResourceDiscoveryQuery.versionMode is latest; such protocol fields must not be directly rewritten as uniform HTTP headers without code support. When the server encounters an unsupported version, it should return an explicit incompatibility result; compatible extensions must not change the semantics of DID, signatures, status, or publication sequences. See Chapter 24 for version selection rules.
{
"query": "a tool that can search code repositories and summarize project structure",
"capabilityTags": ["code-search", "project-structure-summary"],
"versionMode": "latest",
"limit": 10
}
The example above is a discovery query request for POST /discovery/resources/query; all fields correspond to the current ResourceDiscoveryQuery. protocolVersion belongs to the node-to-node SignedRequestEnvelope and must not be mixed into this query object. The current query model has no unified capabilities field; capability conditions should be expressed through capabilityTags or an extension explicitly supported by the target interface. When the server does not support the requested version, it should return an explicit version-incompatibility error and the range of acceptable versions; clients must not ignore the response-mode version merely because they received an HTTP 2xx response.
B.7 Health, Readiness, and Liveness Response Formats
The common minimum structure of the public /health response across current nodes is HealthResponse: status, nodeType, and an optional node DID. A node status interface may additionally provide database, upstream, synchronization cursor, or error summaries. Operations systems can use this information to distinguish process liveness, dependency readiness, business availability, and data synchronization status, but must not treat every field as a uniform schema present on every node. Passing liveness does not imply readiness, and passing readiness does not imply that registration or discovery smoke tests have passed; sensitive configuration and tokens must not appear in the response.
{
"status": "ok",
"nodeType": "discovery",
"did": "did:oan:INDS:7YpQm9Kx2VnRb6Ts3WfHa4Cd5Ej8LgNz"
}
If the deployment provides an extended status interface, it may add check time, dependency status, and synchronization cursors beyond the minimum response above; extension fields should identify their source and version, and the extended response must not be treated in reverse as the mandatory response structure of /health on every node.
| Check type | What it proves | What it does not represent |
|---|---|---|
| liveness | The process can still respond | Dependency and business availability |
| readiness | The service is ready to receive requests | Successful registration or discovery smoke tests |
| dependency | Database, upstream, or off-chain trust indexer status | All business paths are functioning normally |
| smoke test | A critical business flow can be completed | Long-term performance and full correctness |
B.8 Public, Authenticated, and Operations-Only API Matrix
The interface matrix must at least distinguish public read-only interfaces, authenticated publication/registration interfaces, node-to-node interfaces, and operations-only interfaces. Public discovery, DID, status, and necessary statistics may be accessible from the Internet; write, management, database, full-log, detailed access-statistics, and key-related interfaces must be protected by authentication, network boundaries, and auditing. The relay interface of the official website’s backend must not expand downstream service permissions, and ordinary users must not obtain backend statistics or secrets through public interfaces.
| Access level | Examples | Permitted data | Protection requirements |
|---|---|---|---|
| Public read-only | DID, discovery, necessary status | Published ResourcePackages and public proofs | Rate limiting, input validation, auditing |
| Authenticated write | Registration, updates, node-to-node synchronization | Objects within the authorized scope | Signatures, nonce, idempotency, and authorization checks |
| Operations only | Metrics, full logs, administrative operations | Internal operational data | Strong authentication, network isolation, and least privilege |
| Prohibited from public access | Database, private keys, detailed access statistics | Not open to Internet users | Must not be leaked through the official website’s relay |
Reference Sources
| Source | Type | Link |
|---|---|---|
oan-protocol-common |
Code repository: protocol types, OpenAPI contract, and error codes | https://github.com/wolfbrother/oan-protocol-common |
oan-root-services |
Code repository: Root platform API | https://github.com/OpenAgenet/oan-root-services |
oan-registrar-node |
Code repository: registration API | https://github.com/OpenAgenet/oan-registrar-node |
oan-discovery-node |
Code repository: discovery API | https://github.com/OpenAgenet/oan-discovery-node |
oan-sdk-ts |
Code repository: client API wrappers | https://github.com/OpenAgenet/oan-sdk-ts |
| OAN Resource Identity and Discovery | IETF Internet-Draft: resource identity and discovery API | https://datatracker.ietf.org/doc/draft-xu-oan-resource-identity-discovery/ |
| Efficient Agent Discovery Profile | IETF Internet-Draft: discovery API profile | https://datatracker.ietf.org/doc/draft-xu-efficient-agent-discovery-profile/ |