Skip to main content

HTTP Transport

HTTP is the default ANIP transport binding, implemented across all five runtimes: Python, TypeScript, Go, Java, and C#.

It maps native ANIP protocol operations to standard HTTP endpoints. The HTTP binding does not change ANIP semantics: capabilities, permissions, approval grants, structured failures, budget enforcement, lineage, audit, and checkpoints are carried directly as protocol operations. HTTP and stdio are the complete generated transport paths today; gRPC currently covers the Python/Go core binding and trails the newest approval-grant workflow.

Endpoint reference

An ANIP HTTP service exposes the following endpoints:

EndpointMethodAuthDescription
/.well-known/anipGETNoDiscovery document
/.well-known/jwks.jsonGETNoJSON Web Key Set
/anip/manifestGETNoSigned capability manifest
/anip/tokensPOSTBearerIssue delegation token
/anip/permissionsPOSTBearerDiscover permissions
/anip/invoke/{capability}POSTBearerInvoke a capability
/anip/approval_grantsPOSTBearerIssue approval grant for an approved continuation
/anip/auditPOSTBearerQuery audit log
/anip/checkpointsGETNoList checkpoints
/anip/checkpoints/{id}GETNoGet checkpoint detail

/anip/approval_grants is required only for services that can emit approval_required failures.

Some implementations may expose optional development, health, or adapter endpoints. A service should only advertise endpoints it actually implements in discovery.

Discovery

curl https://service.example/.well-known/anip
{
"anip_discovery": {
"version": "0.24.4",
"service_id": "travel-service",
"endpoints": {
"manifest": "/anip/manifest",
"tokens": "/anip/tokens",
"permissions": "/anip/permissions",
"invoke": "/anip/invoke/{capability}",
"approval_grants": "/anip/approval_grants",
"audit": "/anip/audit",
"checkpoints": "/anip/checkpoints"
},
"capabilities": {
"search_flights": {
"description": "Search available flights",
"side_effect": { "type": "read" },
"minimum_scope": ["travel.search"],
"financial": false
},
"book_flight": {
"description": "Book a flight reservation",
"side_effect": { "type": "irreversible" },
"minimum_scope": ["travel.book"],
"financial": true
}
},
"trust": {
"level": "signed"
}
}
}

Discovery is intentionally lightweight. Agents fetch /anip/manifest for the full signed capability declarations.

Token issuance

curl -X POST https://service.example/anip/tokens \
-H "Authorization: Bearer <api-key-or-oidc-token>" \
-H "Content-Type: application/json" \
-d '{
"scope": ["travel.search"],
"capability": "search_flights",
"subject": "agent-007",
"purpose_parameters": { "task_id": "planning-trip" }
}'

Returns a signed JWT delegation token scoped to the requested capability, scope, purpose, and optional budget.

{
"issued": true,
"token_id": "tok_root_001",
"token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9...",
"scope": ["travel.search"],
"capability": "search_flights",
"task_id": "planning-trip",
"expires_at": "2026-03-28T12:00:00Z"
}

Root issuance uses a bootstrap credential such as an API key or OIDC token. Delegated issuance uses an existing ANIP delegation token and includes parent_token.

Permission discovery

Before invoking, an agent can ask what its token is allowed to do:

curl -X POST https://service.example/anip/permissions \
-H "Authorization: Bearer <delegation-token>" \
-H "Content-Type: application/json" \
-d '{}'
{
"available": [
{
"capability": "search_flights",
"scope_match": "travel.search",
"constraints": {}
}
],
"restricted": [
{
"capability": "book_flight",
"reason": "missing scope: travel.book",
"reason_type": "insufficient_scope",
"grantable_by": "human:[email protected]",
"resolution_hint": "request_broader_scope"
}
],
"denied": []
}

Permission discovery is not a substitute for invocation-time checks. Invocation still validates inputs, purpose, budget, approval grants, bindings, and runtime policy.

Invocation

curl -X POST https://service.example/anip/invoke/search_flights \
-H "Authorization: Bearer <delegation-token>" \
-H "Content-Type: application/json" \
-d '{
"parameters": {
"origin": "SEA",
"destination": "SFO"
},
"client_reference_id": "task:abc/step-3",
"task_id": "planning-trip",
"stream": false
}'

Success response (HTTP 200)

{
"success": true,
"invocation_id": "inv-7f3a2b4c5d6e",
"client_reference_id": "task:abc/step-3",
"task_id": "planning-trip",
"result": {
"flights": [
{ "flight_number": "AA100", "price": 420 },
{ "flight_number": "DL310", "price": 280 }
]
},
"cost_actual": {
"financial": {
"currency": "USD",
"amount": 0
}
}
}

Failure response (HTTP 4xx)

Transport-level authentication failures can still be HTTP 401. Once a request reaches the ANIP invocation boundary, authorization, budget, purpose, approval, and capability failures are returned as structured ANIP failure objects:

{
"success": false,
"invocation_id": "inv-8b2f4a7c9d0e",
"client_reference_id": "task:abc/step-3",
"task_id": "planning-trip",
"failure": {
"type": "budget_exceeded",
"detail": "Capability cost $487 exceeds delegated budget of $200",
"retry": false,
"resolution": {
"action": "request_budget_increase",
"recovery_class": "redelegation_then_retry",
"requires": "delegation token with higher budget",
"grantable_by": "human:[email protected]",
"estimated_availability": "immediate"
}
},
"budget_context": {
"budget_currency": "USD",
"budget_max": 200,
"cost_check_amount": 487,
"cost_certainty": "fixed",
"within_budget": false
}
}

Approval continuation

Capabilities that require confirmation before mutation return approval_required instead of performing the side effect.

{
"success": false,
"invocation_id": "inv-9c1e2f3a4b5d",
"failure": {
"type": "approval_required",
"detail": "Posting this message requires approval.",
"retry": false,
"resolution": {
"action": "request_approval",
"recovery_class": "wait_then_retry"
},
"approval_required": {
"approval_request_id": "apr_123",
"preview_digest": "sha256:...",
"requested_parameters_digest": "sha256:...",
"grant_policy": {
"allowed_grant_types": ["one_time", "session_bound"],
"default_grant_type": "one_time",
"expires_in_seconds": 900,
"max_uses": 1
}
}
}
}

After an authorized approver issues a grant through /anip/approval_grants, the agent continues by invoking the same capability with the grant ID:

{
"approval_grant": "grant_456",
"parameters": {
"channel_id": "C0123456789",
"text": "Approved incident update"
}
}

Authentication

ANIP HTTP uses bearer token authentication via the Authorization header:

Authorization: Bearer <token>

The token can be:

  • An API key (for bootstrap/human access)
  • An OIDC/OAuth2 JWT (for federated identity)
  • An ANIP delegation token (for agent access)

The service's authenticate function resolves the bearer to a principal identity.

Manifest signature

The manifest response includes a cryptographic signature. Clients verify this signature using the service JWKS:

GET /anip/manifest

HTTP/1.1 200 OK
Content-Type: application/json
X-ANIP-Signature: eyJhbGciOiJFZERTQSJ9...

{ "manifest_metadata": { ... }, "capabilities": { ... } }

The manifest is the signed source of capability truth. Generated REST, GraphQL, and MCP surfaces should be treated as derived interfaces, not as replacements for the manifest.

Audit and checkpoints

HTTP audit queries use POST /anip/audit with bearer auth and optional query parameters:

curl -X POST "https://service.example/anip/audit?task_id=planning-trip&limit=10" \
-H "Authorization: Bearer <delegation-token>" \
-H "Content-Type: application/json" \
-d '{}'

Checkpoints are public verification endpoints:

curl https://service.example/anip/checkpoints
curl https://service.example/anip/checkpoints/chk-2026-05-23T00:00:00Z

Audit answers what happened. Checkpoints help prove that audit history was not silently rewritten.

Generated HTTP hosts

anip generate emits HTTP runners for all five targets by default:

anip generate \
--package [email protected] \
--target python \
--transport http \
--output ./generated/my-service

Framework variants are generation-time choices:

TargetHTTP frameworks
PythonFastAPI
TypeScriptHono, Express, Fastify
Gonet/http, Gin
JavaSpring Boot, Quarkus
C#ASP.NET Core

The framework affects host code, not capability semantics.

CORS

When ANIP Studio or other browser-based clients access the service from a different origin, the service must enable CORS:

from starlette.middleware.cors import CORSMiddleware

app.add_middleware(
CORSMiddleware,
allow_origins=["https://studio.example.com"],
allow_methods=["*"],
allow_headers=["*"],
expose_headers=["X-ANIP-Signature"],
)

Next steps