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​