{
  "schemaVersion": "1.0",
  "title": "Transport bindings",
  "description": "Transport bindings move AIP messages without changing their protocol meaning. Use this reference to choose a binding, encode its frames, authenticate its peer, and recover after an interrupted delivery.",
  "canonical": "https://getaip.org/docs/reference/transport-bindings",
  "route": "/docs/reference/transport-bindings",
  "source": "docs/reference/transport-bindings.md",
  "protocol": "Agent Interoperability Protocol",
  "protocolVersion": "1.0",
  "section": "API Reference",
  "documentType": "Reference",
  "language": "en",
  "revision": {
    "lastReviewedRevision": "d7cce13d1d555644d04a4d73c66c95b113737635",
    "documentationSourceRevision": "9192fef3695ad294994f2712f6d156241e5e92fb",
    "basis": "frontmatter"
  },
  "downloads": {
    "md": "/docs/download/reference/transport-bindings.md",
    "txt": "/docs/download/reference/transport-bindings.txt",
    "json": "/docs/download/reference/transport-bindings.json",
    "pdf": "/docs/download/reference/transport-bindings.pdf"
  },
  "content": {
    "format": "text/markdown",
    "markdown": "---\ntitle: Transport bindings\ndescription: Select and implement native HTTP, SSE, WebSocket, and NATS transport behavior\nkind: reference\naudience: developer\nappliesTo: \"1.x\"\nwritingStandard: \"aip-docs/1.0\"\nlastReviewedRevision: \"d7cce13d1d555644d04a4d73c66c95b113737635\"\n---\n\n# Transport bindings\n\nTransport bindings move AIP messages without changing their protocol meaning.\nUse this reference to choose a binding, encode its frames, authenticate its\npeer, and recover after an interrupted delivery.\n\nThis page describes source revision\n`d7cce13d1d555644d04a4d73c66c95b113737635`. It separates reusable transport\ncodecs from the routes actually exposed by `getaip-server`. That distinction matters for\nSSE and WebSocket, where the daemon adds operational query behavior around the\nlower-level frame codecs.\n\n## Choose a binding\n\n| Binding | Direction | Use it for | Recovery source |\n|---|---|---|---|\n| Native HTTP | Request and response | Envelope exchange and ergonomic operational queries | Durable action, event, approval, transaction, and receipt views |\n| Signed peer HTTP | Request and response | Daemon-to-host connector execution and trusted remote delegation | Pinned route plus durable action or delegation state |\n| Native SSE | Server to client | Following action events, stream chunks, or global events | Durable event cursor and action status |\n| Native WebSocket | Bidirectional | Envelope exchange and multiplexed event subscriptions | Durable cursor and operational HTTP reads |\n| Native NATS | Publish or request and reply | Broker-routed native envelope delivery | Runtime state; this implementation does not configure JetStream persistence |\n\nMCP and A2A reuse HTTP or streaming primitives but have independent protocol,\nsession, version, and error rules. They are compatibility profiles, not aliases\nfor the native bindings on this page.\n\n## Semantics that do not move into the transport\n\nAcross every binding, the AIP envelope remains the semantic unit. Transport\nheaders, subjects, connections, and reply inboxes do not replace:\n\n- authenticated principal and tenant binding;\n- action, session, delegation, and transaction identifiers;\n- approval and policy decisions;\n- idempotency keys and replay checks;\n- lifecycle and terminal state;\n- typed error category, retryability, and receipt evidence.\n\nNetwork reachability proves neither identity nor authorization. A gateway must\nstill bind a peer to a trusted principal and enforce scopes, tenant, route,\napproval, delegation, and transaction policy. Do not trust an envelope's\n`from` field or caller-controlled transport metadata on its own.\n\n## Common transport frame\n\nThe framework-neutral transport crate defines:\n\n```json\n{\n  \"envelope\": {\n    \"aip_version\": \"1.0\",\n    \"message_type\": \"aip.discovery.v1.manifest_request\",\n    \"message_id\": \"msg_0190c42f2d5a70008000000000000001\",\n    \"sent_at\": \"2026-07-26T12:00:00Z\",\n    \"body\": {\n      \"manifest_request\": {}\n    }\n  },\n  \"metadata\": {\n    \"transport-key\": \"transport-value\"\n  }\n}\n```\n\n`TransportMessage` contains one complete `Envelope` and a string-to-string\nmetadata map. Empty metadata is omitted. `RawFrame` contains serialized bytes\nplus the same normalized metadata. The common traits distinguish\nfire-and-forget publish, request/reply, and correlation-scoped streaming; they\ndo not prescribe durability or authentication.\n\n## Native HTTP\n\nThe native HTTP profile is `aip.native.http.v1`. Its codec serializes a complete\nenvelope as JSON and records two frame metadata values:\n\n| Metadata | Value |\n|---|---|\n| `content-type` | `application/aip+json` |\n| `aip-message-type` | The envelope's exact message-type string |\n\nThe path helper recommends `/aip/v1/actions` for actions,\n`/aip/v1/manifest` for manifest request or response bodies, and\n`/aip/v1/messages` for other message families. This helper selects a path only.\nThe deployed daemon exposes manifest discovery as `GET`, so clients must use\nthe method and route contract in the [native HTTP API](http-api.md).\n\nThe daemon's Axum JSON extractors and responses currently use\n`application/json`. The signed peer client also sends through a JSON request\nbuilder, which uses `application/json`. The binding codec's\n`application/aip+json` media type is therefore not consistently emitted by the\ndeployed HTTP surfaces at this revision. This difference is recorded in\n[implementation status](implementation-status.md).\n\nProtocol error categories map to HTTP as follows:\n\n| Category | HTTP status |\n|---|---:|\n| `auth` | `401` |\n| `policy` | `403` |\n| `temporary`, `transport` | `503` |\n| `connector` | `502` |\n| `economic` | `402` |\n| `permanent` | `400` |\n\nAn HTTP status is a transport projection. Clients still use the protocol error\ncode, category, `retryable`, and `retry_after_ms` fields for decisions.\n\n## Signed peer HTTP\n\nThe pooled `NativeAipHttpClient` is the authenticated HTTP binding used for\nconnector hosts and remote native delegation. Before sending, it:\n\n1. validates the destination against scheme, host, DNS, and private-network\n   policy;\n2. resolves the host and pins one address into a host-specific client;\n3. disables redirects and applies the configured timeout and TLS roots;\n4. signs the envelope with the route's request identity;\n5. adds `AIP-Trust-Domain` and `Idempotency-Key` headers.\n\nThe idempotency header uses the delegation ID for a delegation request, the\naction ID for an action, and the message ID for any other body.\n\nThe default\nendpoint policy allows no hosts, disallows plaintext HTTP and private networks,\nuses a five-second request timeout, and limits a response to 4 MiB. A caller\nmust opt into every destination. The default client cache retains at most 256\nhost-specific pools.\n\nThe client verifies a response before returning it. The response must:\n\n- carry the exact expected peer DID and a valid Ed25519 envelope signature;\n- come from the expected principal and target the request signer;\n- preserve the request correlation ID;\n- reference the exact request message in `in_response_to`; and\n- have a timestamp within five minutes of the verifier's clock.\n\nThe peer-security object defaults to two retries after the first attempt.\nRetries occur only when sending the HTTP request returns a transport error.\nThey reuse the same signed envelope and idempotency header, with bounded\nexponential delays starting at 50 ms. A returned HTTP response, malformed body,\noversized body, or failed peer verification is not transport-retried by this\nloop.\n\nConnector dispatch adds a complete `security.connector_route` and verifies\nadditional assignment fences at both ends. See the [connector fleet HTTP\nAPI](connector-fleet-api.md) for those fields and central callback ingress.\n\n## Native SSE in `getaip-server`\n\nSet `follow=true` on one of these bearer-authenticated native routes:\n\n| Route | Stream scope |\n|---|---|\n| `/aip/v1/events` | Events visible to the authenticated identity |\n| `/aip/v1/actions/{action_id}/events` | One action's events and optional chunks |\n| `/aip/v1/actions/{action_id}/chunks` | One action's durable chunks |\n\nThe response uses `text/event-stream`. A query `cursor` takes precedence over\n`Last-Event-ID`; otherwise the header becomes the resume cursor. Persist only a\ncursor returned by the same route and authorization context.\n\nThe daemon emits these frame forms:\n\n| Event name | `id` | JSON data |\n|---|---|---|\n| An event's `kind` | Event ID | `{\"event\": ...}` |\n| `aip.stream.chunk` | `chunk:{sequence}` | `{\"chunk\": ...}` |\n| `aip.stream.cursor` | Returned cursor | `{\"next_cursor\": \"...\"}` |\n| `aip.stream.terminal` | Current cursor when present | `{\"terminal\": true, \"action_id\": \"...\"}` |\n| `aip.error` | None | `{\"error\": ...}` followed by stream termination |\n\nAction-scoped follow ends after a terminal response. Global follow continues\nuntil disconnect or error. The current loop polls the durable view every\n500 ms and emits an SSE keep-alive every 15 seconds.\n\nSSE is delivery, not storage. A disconnect does not cancel the action. Resume\nwith the retained cursor, accept possible duplicate delivery, and confirm\nterminal business state through the durable action or transaction view.\n\n### Framework-neutral SSE codec\n\nThe lower-level `aip-transport-sse` crate has profile\n`aip.sse.stream.v1`. It serializes an entire envelope in each `data` field and\nuses generic event names such as `ack`, `chunk`, `done`, `result`,\n`delegation_request`, `delegation_result`, `heartbeat`, `heartbeat_ack`,\n`error`, or `message`.\n\nIts `SseCursor` is an in-memory zero-based index rendered as `sse_{index}`. The\nembedded `SseTransport` groups messages by correlation ID and closes a stream\nafter a done chunk, action result, delegation result, or error. These helpers\ndo not describe the durable cursor or data shape returned by the deployed\n`getaip-server` follow routes.\n\n## Native WebSocket in `getaip-server`\n\n`GET /aip/v1/ws` upgrades through the native-auth middleware. A client text\nframe can use either of two forms:\n\n- one complete AIP `Envelope`, which receives one response envelope; or\n- a JSON object with `\"type\": \"subscribe\"`, which requests an action-scoped\n  or global event page.\n\nA subscription object accepts `subscription_id`, `action_id`, `session_id`,\n`tenant_id`, `cursor`, `limit`, `kind`, `kinds`, `include_chunks`, and\n`follow`. With `action_id`, the daemon issues an action-events query. Without\nit, the daemon issues a global event query. `tenant_id` is used only by the\naction-scoped request at this revision. Responses remain complete AIP envelopes\nand include WebSocket cursor and terminal details in `trace`.\n\n`follow=true` repeats the query every 500 ms until an action becomes terminal,\nan error occurs, or the connection closes. The daemon allows at most 16 active\nsubscriptions per connection and buffers eight outbound frames. If a slow\nconsumer exhausts that buffer, delivery stops rather than growing memory\nwithout a bound.\n\nPing receives Pong with the same payload. Close is echoed when capacity allows.\nBinary application frames and inbound Pong frames are ignored by the daemon.\nAfter a disconnect, reconnect with a durable cursor or use native HTTP reads;\nconnection state is not a recovery record.\n\n### Framework-neutral WebSocket codec\n\nThe lower-level codec uses profile `aip.websocket.stream.v1`. It encodes one\nenvelope per text frame, rejects non-text application frames, maps Ping to\nPong, and groups its in-memory queues by session ID. Its subscription trait\ntracks correlation IDs only inside that transport object. The daemon's\n`\"type\": \"subscribe\"` control object is an application adapter above this\ncodec.\n\n## Native NATS\n\nThe native NATS profile is `aip.native.nats.v1`. A request or publish subject\nhas this form:\n\n```text\naip.v1.{trust_domain}.{service}.{version}.{message_type}\n```\n\nDots, spaces, forward slashes, and backslashes in every component are replaced\nwith underscores. For example, message type `aip.core.v1.action` becomes\n`aip_core_v1_action` in the subject. A daemon listens on the service wildcard:\n\n```text\naip.v1.{trust_domain}.{service}.{version}.>\n```\n\nThe library also defines a correlation-scoped stream subject:\n\n```text\naip.v1.{trust_domain}.{service}.{version}.stream.{correlation_id}\n```\n\nThe payload is JSON `TransportMessage`. For compatibility at the receive\nboundary, the decoder also accepts a raw envelope and wraps NATS headers as\ntransport metadata. Outbound request, response, and publish operations use the\nwrapped form.\n\nEvery outbound frame sets these NATS headers:\n\n| Header | Source |\n|---|---|\n| `AIP-Version` | `envelope.aip_version` |\n| `AIP-Message-Type` | Exact unsanitized message type |\n| `AIP-Message-Id` | Message ID |\n| `AIP-Session-Id` | Session ID when present |\n| `AIP-Correlation-Id` | Correlation ID when present |\n\nThe default request timeout is 30 seconds. The `getaip-server` listener processes both\nordinary and queue subscriptions. It returns one `TransportMessage` only when\nthe NATS message has a reply subject; a publish without a reply is still sent\nthrough the gateway. Decode failure produces a typed NATS transport-error\nenvelope when a reply is possible.\n\nA native NATS delegation route validates the broker destination against its\nendpoint policy, signs the request envelope, and performs one request/reply\nexchange. It applies the same peer-DID, signature, principal, recipient,\ncorrelation, request-reference, and clock checks used by signed HTTP. The HTTP\nclient's retry-budget loop is not applied to this NATS request path.\n\nOptional username/password authentication is attached only at connection time;\nthe password is omitted from serialized configuration and redacted from debug\noutput. Broker accounts, TLS, subject ACLs, availability, and retention remain\ndeployment responsibilities. The current transport uses Core NATS APIs and\ndoes not configure JetStream persistence or durable consumers.\n\nA queue group distributes requests among daemon listeners. It does not replace\nAIP action leases, idempotency reservations, replay protection, or durable\nterminal reads. When a configured listener is not running, daemon readiness is\nfalse.\n\n## Compatibility-profile boundary\n\nDo not apply native frame rules to MCP Streamable HTTP, legacy MCP HTTP/SSE, or\nA2A JSON-RPC and streaming. Use [AIP through MCP](../guides/use-aip-through-mcp.md)\nand [AIP through A2A](../guides/use-aip-through-a2a.md) for their media types,\nsession headers, protocol versions, and errors.\n\n## Delivery and recovery decisions\n\n| Observation | Safe next step |\n|---|---|\n| HTTP request was rejected with a typed error | Follow its retry fields and the capability's side-effect contract |\n| Signed peer send failed before a response | Let the bounded peer client reuse the same signed request and idempotency header; then query durable state |\n| HTTP, WebSocket, or NATS outcome is uncertain | Do not create a new mutation identity; read the existing action, transaction, or receipt |\n| SSE or WebSocket disconnected | Resume from the last retained route cursor and tolerate replay |\n| NATS subscriber changed because of queue-group rebalance | Continue from runtime state; do not infer completion from broker delivery |\n| Peer signature, principal, recipient, correlation, or request reference failed | Reject the response and investigate the trust boundary; do not retry it as a valid result |\n\nSee [errors and retry decisions](errors.md) for the complete taxonomy,\n[actions and sessions](../concepts/actions-and-sessions.md) for durable recovery,\nand [identity and trust](../concepts/identity-and-trust.md) for principal binding.\n\n## Related documentation\n\n- [Configure `getaip-server`](configuration.md)\n- [Use native AIP](../guides/use-native-aip.md)\n",
    "text": "Transport bindings\n\nTransport bindings move AIP messages without changing their protocol meaning.\nUse this reference to choose a binding, encode its frames, authenticate its\npeer, and recover after an interrupted delivery.\n\nThis page describes source revision\nd7cce13d1d555644d04a4d73c66c95b113737635. It separates reusable transport\ncodecs from the routes actually exposed by getaip-server. That distinction matters for\nSSE and WebSocket, where the daemon adds operational query behavior around the\nlower-level frame codecs.\n\nChoose a binding\n\n| Binding | Direction | Use it for | Recovery source |\n\n| Native HTTP | Request and response | Envelope exchange and ergonomic operational queries | Durable action, event, approval, transaction, and receipt views |\n| Signed peer HTTP | Request and response | Daemon-to-host connector execution and trusted remote delegation | Pinned route plus durable action or delegation state |\n| Native SSE | Server to client | Following action events, stream chunks, or global events | Durable event cursor and action status |\n| Native WebSocket | Bidirectional | Envelope exchange and multiplexed event subscriptions | Durable cursor and operational HTTP reads |\n| Native NATS | Publish or request and reply | Broker-routed native envelope delivery | Runtime state; this implementation does not configure JetStream persistence |\n\nMCP and A2A reuse HTTP or streaming primitives but have independent protocol,\nsession, version, and error rules. They are compatibility profiles, not aliases\nfor the native bindings on this page.\n\nSemantics that do not move into the transport\n\nAcross every binding, the AIP envelope remains the semantic unit. Transport\nheaders, subjects, connections, and reply inboxes do not replace:\n• authenticated principal and tenant binding;\n• action, session, delegation, and transaction identifiers;\n• approval and policy decisions;\n• idempotency keys and replay checks;\n• lifecycle and terminal state;\n• typed error category, retryability, and receipt evidence.\n\nNetwork reachability proves neither identity nor authorization. A gateway must\nstill bind a peer to a trusted principal and enforce scopes, tenant, route,\napproval, delegation, and transaction policy. Do not trust an envelope's\nfrom field or caller-controlled transport metadata on its own.\n\nCommon transport frame\n\nThe framework-neutral transport crate defines:\n\n{\n  \"envelope\": {\n    \"aipversion\": \"1.0\",\n    \"messagetype\": \"aip.discovery.v1.manifestrequest\",\n    \"messageid\": \"msg0190c42f2d5a70008000000000000001\",\n    \"sentat\": \"2026-07-26T12:00:00Z\",\n    \"body\": {\n      \"manifestrequest\": {}\n    }\n  },\n  \"metadata\": {\n    \"transport-key\": \"transport-value\"\n  }\n}\n\nTransportMessage contains one complete Envelope and a string-to-string\nmetadata map. Empty metadata is omitted. RawFrame contains serialized bytes\nplus the same normalized metadata. The common traits distinguish\nfire-and-forget publish, request/reply, and correlation-scoped streaming; they\ndo not prescribe durability or authentication.\n\nNative HTTP\n\nThe native HTTP profile is aip.native.http.v1. Its codec serializes a complete\nenvelope as JSON and records two frame metadata values:\n\n| Metadata | Value |\n\n| content-type | application/aip+json |\n| aip-message-type | The envelope's exact message-type string |\n\nThe path helper recommends /aip/v1/actions for actions,\n/aip/v1/manifest for manifest request or response bodies, and\n/aip/v1/messages for other message families. This helper selects a path only.\nThe deployed daemon exposes manifest discovery as GET, so clients must use\nthe method and route contract in the native HTTP API (http-api.md).\n\nThe daemon's Axum JSON extractors and responses currently use\napplication/json. The signed peer client also sends through a JSON request\nbuilder, which uses application/json. The binding codec's\napplication/aip+json media type is therefore not consistently emitted by the\ndeployed HTTP surfaces at this revision. This difference is recorded in\nimplementation status (implementation-status.md).\n\nProtocol error categories map to HTTP as follows:\n\n| Category | HTTP status |\n\n| auth | 401 |\n| policy | 403 |\n| temporary, transport | 503 |\n| connector | 502 |\n| economic | 402 |\n| permanent | 400 |\n\nAn HTTP status is a transport projection. Clients still use the protocol error\ncode, category, retryable, and retryafterms fields for decisions.\n\nSigned peer HTTP\n\nThe pooled NativeAipHttpClient is the authenticated HTTP binding used for\nconnector hosts and remote native delegation. Before sending, it:\n1. validates the destination against scheme, host, DNS, and private-network\n   policy;\n2. resolves the host and pins one address into a host-specific client;\n3. disables redirects and applies the configured timeout and TLS roots;\n4. signs the envelope with the route's request identity;\n5. adds AIP-Trust-Domain and Idempotency-Key headers.\n\nThe idempotency header uses the delegation ID for a delegation request, the\naction ID for an action, and the message ID for any other body.\n\nThe default\nendpoint policy allows no hosts, disallows plaintext HTTP and private networks,\nuses a five-second request timeout, and limits a response to 4 MiB. A caller\nmust opt into every destination. The default client cache retains at most 256\nhost-specific pools.\n\nThe client verifies a response before returning it. The response must:\n• carry the exact expected peer DID and a valid Ed25519 envelope signature;\n• come from the expected principal and target the request signer;\n• preserve the request correlation ID;\n• reference the exact request message in inresponseto; and\n• have a timestamp within five minutes of the verifier's clock.\n\nThe peer-security object defaults to two retries after the first attempt.\nRetries occur only when sending the HTTP request returns a transport error.\nThey reuse the same signed envelope and idempotency header, with bounded\nexponential delays starting at 50 ms. A returned HTTP response, malformed body,\noversized body, or failed peer verification is not transport-retried by this\nloop.\n\nConnector dispatch adds a complete security.connectorroute and verifies\nadditional assignment fences at both ends. See the connector fleet HTTP\nAPI (connector-fleet-api.md) for those fields and central callback ingress.\n\nNative SSE in getaip-server\n\nSet follow=true on one of these bearer-authenticated native routes:\n\n| Route | Stream scope |\n\n| /aip/v1/events | Events visible to the authenticated identity |\n| /aip/v1/actions/{actionid}/events | One action's events and optional chunks |\n| /aip/v1/actions/{actionid}/chunks | One action's durable chunks |\n\nThe response uses text/event-stream. A query cursor takes precedence over\nLast-Event-ID; otherwise the header becomes the resume cursor. Persist only a\ncursor returned by the same route and authorization context.\n\nThe daemon emits these frame forms:\n\n| Event name | id | JSON data |\n\n| An event's kind | Event ID | {\"event\": ...} |\n| aip.stream.chunk | chunk:{sequence} | {\"chunk\": ...} |\n| aip.stream.cursor | Returned cursor | {\"nextcursor\": \"...\"} |\n| aip.stream.terminal | Current cursor when present | {\"terminal\": true, \"actionid\": \"...\"} |\n| aip.error | None | {\"error\": ...} followed by stream termination |\n\nAction-scoped follow ends after a terminal response. Global follow continues\nuntil disconnect or error. The current loop polls the durable view every\n500 ms and emits an SSE keep-alive every 15 seconds.\n\nSSE is delivery, not storage. A disconnect does not cancel the action. Resume\nwith the retained cursor, accept possible duplicate delivery, and confirm\nterminal business state through the durable action or transaction view.\n\nFramework-neutral SSE codec\n\nThe lower-level aip-transport-sse crate has profile\naip.sse.stream.v1. It serializes an entire envelope in each data field and\nuses generic event names such as ack, chunk, done, result,\ndelegationrequest, delegationresult, heartbeat, heartbeatack,\nerror, or message.\n\nIts SseCursor is an in-memory zero-based index rendered as sse{index}. The\nembedded SseTransport groups messages by correlation ID and closes a stream\nafter a done chunk, action result, delegation result, or error. These helpers\ndo not describe the durable cursor or data shape returned by the deployed\ngetaip-server follow routes.\n\nNative WebSocket in getaip-server\n\nGET /aip/v1/ws upgrades through the native-auth middleware. A client text\nframe can use either of two forms:\n• one complete AIP Envelope, which receives one response envelope; or\n• a JSON object with \"type\": \"subscribe\", which requests an action-scoped\n  or global event page.\n\nA subscription object accepts subscriptionid, actionid, sessionid,\ntenantid, cursor, limit, kind, kinds, includechunks, and\nfollow. With actionid, the daemon issues an action-events query. Without\nit, the daemon issues a global event query. tenantid is used only by the\naction-scoped request at this revision. Responses remain complete AIP envelopes\nand include WebSocket cursor and terminal details in trace.\n\nfollow=true repeats the query every 500 ms until an action becomes terminal,\nan error occurs, or the connection closes. The daemon allows at most 16 active\nsubscriptions per connection and buffers eight outbound frames. If a slow\nconsumer exhausts that buffer, delivery stops rather than growing memory\nwithout a bound.\n\nPing receives Pong with the same payload. Close is echoed when capacity allows.\nBinary application frames and inbound Pong frames are ignored by the daemon.\nAfter a disconnect, reconnect with a durable cursor or use native HTTP reads;\nconnection state is not a recovery record.\n\nFramework-neutral WebSocket codec\n\nThe lower-level codec uses profile aip.websocket.stream.v1. It encodes one\nenvelope per text frame, rejects non-text application frames, maps Ping to\nPong, and groups its in-memory queues by session ID. Its subscription trait\ntracks correlation IDs only inside that transport object. The daemon's\n\"type\": \"subscribe\" control object is an application adapter above this\ncodec.\n\nNative NATS\n\nThe native NATS profile is aip.native.nats.v1. A request or publish subject\nhas this form:\n\naip.v1.{trustdomain}.{service}.{version}.{messagetype}\n\nDots, spaces, forward slashes, and backslashes in every component are replaced\nwith underscores. For example, message type aip.core.v1.action becomes\naipcorev1action in the subject. A daemon listens on the service wildcard:\n\naip.v1.{trustdomain}.{service}.{version}.>\n\nThe library also defines a correlation-scoped stream subject:\n\naip.v1.{trustdomain}.{service}.{version}.stream.{correlationid}\n\nThe payload is JSON TransportMessage. For compatibility at the receive\nboundary, the decoder also accepts a raw envelope and wraps NATS headers as\ntransport metadata. Outbound request, response, and publish operations use the\nwrapped form.\n\nEvery outbound frame sets these NATS headers:\n\n| Header | Source |\n\n| AIP-Version | envelope.aipversion |\n| AIP-Message-Type | Exact unsanitized message type |\n| AIP-Message-Id | Message ID |\n| AIP-Session-Id | Session ID when present |\n| AIP-Correlation-Id | Correlation ID when present |\n\nThe default request timeout is 30 seconds. The getaip-server listener processes both\nordinary and queue subscriptions. It returns one TransportMessage only when\nthe NATS message has a reply subject; a publish without a reply is still sent\nthrough the gateway. Decode failure produces a typed NATS transport-error\nenvelope when a reply is possible.\n\nA native NATS delegation route validates the broker destination against its\nendpoint policy, signs the request envelope, and performs one request/reply\nexchange. It applies the same peer-DID, signature, principal, recipient,\ncorrelation, request-reference, and clock checks used by signed HTTP. The HTTP\nclient's retry-budget loop is not applied to this NATS request path.\n\nOptional username/password authentication is attached only at connection time;\nthe password is omitted from serialized configuration and redacted from debug\noutput. Broker accounts, TLS, subject ACLs, availability, and retention remain\ndeployment responsibilities. The current transport uses Core NATS APIs and\ndoes not configure JetStream persistence or durable consumers.\n\nA queue group distributes requests among daemon listeners. It does not replace\nAIP action leases, idempotency reservations, replay protection, or durable\nterminal reads. When a configured listener is not running, daemon readiness is\nfalse.\n\nCompatibility-profile boundary\n\nDo not apply native frame rules to MCP Streamable HTTP, legacy MCP HTTP/SSE, or\nA2A JSON-RPC and streaming. Use AIP through MCP (../guides/use-aip-through-mcp.md)\nand AIP through A2A (../guides/use-aip-through-a2a.md) for their media types,\nsession headers, protocol versions, and errors.\n\nDelivery and recovery decisions\n\n| Observation | Safe next step |\n\n| HTTP request was rejected with a typed error | Follow its retry fields and the capability's side-effect contract |\n| Signed peer send failed before a response | Let the bounded peer client reuse the same signed request and idempotency header; then query durable state |\n| HTTP, WebSocket, or NATS outcome is uncertain | Do not create a new mutation identity; read the existing action, transaction, or receipt |\n| SSE or WebSocket disconnected | Resume from the last retained route cursor and tolerate replay |\n| NATS subscriber changed because of queue-group rebalance | Continue from runtime state; do not infer completion from broker delivery |\n| Peer signature, principal, recipient, correlation, or request reference failed | Reject the response and investigate the trust boundary; do not retry it as a valid result |\n\nSee errors and retry decisions (errors.md) for the complete taxonomy,\nactions and sessions (../concepts/actions-and-sessions.md) for durable recovery,\nand identity and trust (../concepts/identity-and-trust.md) for principal binding.\n\nRelated documentation\n• Configure getaip-server (configuration.md)\n• Use native AIP (../guides/use-native-aip.md)\n"
  },
  "integrity": {
    "algorithm": "sha256",
    "sourceDigest": "ff1bcdc63151684bf17eb07a999781f42fd7c75c7a702c83cc5f3740fb00f80e"
  }
}
