Integration Guide

Microservices

An AI agent calling your microservice is different from a human calling your microservice. The agent might be acting on a forged instruction, outside its delegated scope, or after its authority was revoked. AGP gives every service call a provenance — a signed, policy-cleared action envelope that proves the call was authorized before it was made.

AI agent │ │ 1. Registers AGP task + gets action envelope │ (capability check, policy evaluation, human approval if needed) │ ▼ AGP server → issues signed action envelope → agent │ │ 2. Agent calls your microservice, presents action envelope │ ▼ API gateway / service ├─ Verifies envelope is valid, unrevoked, scoped to this service ├─ Rejects if missing, expired, revoked, or wrong scope └─ Forwards to microservice if valid ↓ Microservice executes → result logged to AGP ledger

AGP is language and framework agnostic. The pattern works the same whether your services are Python FastAPI, Node.js Express, Go, Java Spring, or anything else. All that's required is that the service — or something in front of it — can make an HTTP call to the AGP verification endpoint.


Three patterns

Choose based on how much control you have over the infrastructure layer:

Recommended

Gateway

Verify at the API gateway before any request reaches your services. One integration point covers all services.

Per-service

Middleware

Verification middleware inside each service. More granular — each service checks its own required scope.

Minimal

Direct

Service calls the AGP verification endpoint directly in its handler. No infrastructure changes needed.


Pattern 1 — Gateway verification

The agent attaches the AGP action envelope ID as a request header. The gateway calls the AGP verification endpoint before routing. If verification fails, the request is rejected at the edge — your services never see it.

Agent side — obtain and attach the envelope

from agp import AGPClient

agent = AGPClient("https://your-agp-server", client_id="my-agent", client_secret="...")

# Run the AGP pipeline to obtain a signed action envelope
with agent.task_session(
    principal_id="my-agent",
    requested_outcome="Fetch customer records for Q3 analysis",
    risk_tier="medium",
) as session:
    session.bind(sponsoring_entity="analytics-team",
                 accountable_owner="lead@example.com", jurisdiction="EU")
    session.issue_capability(subject_agent="my-agent", issuer="analytics-team",
                              principal_id="my-agent",
                              permitted_actions=["customer_records.read"])
    session.decide(agent_id="my-agent", selected_action="customer_records.read",
                   rationale="Q3 analysis, read-only, no PII export",
                   uncertainty_score=0.05)
    receipt = session.execute(agent_id="my-agent", tool_id="customer-service",
                              operation={"query": "q3_cohort"},
                              capability_token_ref=session.capability_token.capability_id)

# Call the microservice — attach the action ID as a header
import httpx
response = httpx.get(
    "https://api.internal/customer-service/records",
    params={"query": "q3_cohort"},
    headers={"X-AGP-Action-ID": receipt.action_id},
)

Gateway side — verify before routing

Example using nginx with a Lua auth subrequest, or any gateway that supports external auth (Kong, AWS API Gateway, Envoy, Traefik):

-- nginx + lua-resty-http: external auth subrequest
access_by_lua_block {
    local http = require("resty.http")
    local action_id = ngx.req.get_headers()["X-AGP-Action-ID"]

    if not action_id then
        ngx.status = 401
        ngx.say('{"error":"X-AGP-Action-ID header required"}')
        ngx.exit(401)
    end

    local httpc = http.new()
    local res = httpc:request_uri(
        "https://your-agp-server/agp/action-envelopes/" .. action_id,
        { method = "GET",
          headers = { ["Authorization"] = "Bearer " .. agp_token } }
    )

    if res.status ~= 200 then
        ngx.status = 403
        ngx.say('{"error":"AGP envelope invalid or revoked"}')
        ngx.exit(403)
    end
}
One integration, all services. Verify at the gateway and every service behind it is automatically protected — without touching any service code. Add a new service and it's covered immediately.

Pattern 2 — Per-service middleware

Verification middleware in each service gives you per-route scope enforcement. Different endpoints can require different AGP scopes — a write endpoint requires a write-scoped envelope, a read endpoint accepts a read-scoped one.

Python (FastAPI)
TypeScript (Express)
# FastAPI dependency — verifies the AGP action envelope on each request
import httpx
from fastapi import Depends, Header, HTTPException

AGP_SERVER = "https://your-agp-server"
AGP_TOKEN  = "..."  # service's own AGP bearer token


async def require_agp_envelope(
    action_id: str = Header(alias="X-AGP-Action-ID"),
    required_action: str = "*",
):
    """Verify the AGP action envelope and confirm the action is in scope."""
    async with httpx.AsyncClient() as client:
        r = await client.get(
            f"{AGP_SERVER}/agp/action-envelopes/{action_id}",
            headers={"Authorization": f"Bearer {AGP_TOKEN}"},
        )

    if r.status_code != 200:
        raise HTTPException(403, detail="AGP envelope invalid or revoked")

    envelope = r.json()

    # Verify the action matches what this endpoint expects
    if required_action != "*" and envelope["tool_id"] != required_action:
        raise HTTPException(403, detail=f"Envelope scoped to '{envelope['tool_id']}', not '{required_action}'")

    return envelope


# Apply per-route — different endpoints can require different scopes
from fastapi import FastAPI
app = FastAPI()

@app.get("/records")
async def get_records(
    envelope = Depends(lambda: require_agp_envelope(required_action="customer_records.read"))
):
    # Only reached if envelope is valid and scoped to customer_records.read
    ...

@app.post("/records")
async def create_record(
    envelope = Depends(lambda: require_agp_envelope(required_action="customer_records.write"))
):
    # Requires a write-scoped envelope — a read envelope is rejected here
    ...
// TypeScript / Express — AGP envelope middleware
import express, { Request, Response, NextFunction } from "express";

const AGP_SERVER = "https://your-agp-server";

function requireAGPEnvelope(requiredAction?: string) {
  return async (req: Request, res: Response, next: NextFunction) => {
    const actionId = req.headers["x-agp-action-id"] as string;

    if (!actionId) {
      return res.status(401).json({ error: "X-AGP-Action-ID header required" });
    }

    const r = await fetch(`${AGP_SERVER}/agp/action-envelopes/${actionId}`, {
      headers: { Authorization: `Bearer ${process.env.AGP_TOKEN}` },
    });

    if (!r.ok) {
      return res.status(403).json({ error: "AGP envelope invalid or revoked" });
    }

    const envelope = await r.json();

    if (requiredAction && envelope.tool_id !== requiredAction) {
      return res.status(403).json({ error: `Envelope scoped to '${envelope.tool_id}'` });
    }

    res.locals.agpEnvelope = envelope;
    next();
  };
}

// Apply per-route
const router = express.Router();
router.get("/records",  requireAGPEnvelope("customer_records.read"),  getRecords);
router.post("/records", requireAGPEnvelope("customer_records.write"), createRecord);

Pattern 3 — Direct verification

The simplest integration: the service handler calls the AGP verification endpoint directly, with no middleware or gateway changes. Good for adding governance to a single high-risk endpoint without broader infrastructure changes.

# Minimal: verify inline in the handler
import httpx

def approve_payment(vendor: str, amount_usd: float, agp_action_id: str):
    # Verify the action envelope before doing anything
    r = httpx.get(
        f"https://your-agp-server/agp/action-envelopes/{agp_action_id}",
        headers={"Authorization": f"Bearer {AGP_TOKEN}"},
    )
    if r.status_code != 200:
        raise PermissionError("No valid AGP action envelope")

    envelope = r.json()
    if envelope["tool_id"] != "approve_payment":
        raise PermissionError("Envelope not scoped for approve_payment")
    if envelope.get("operation", {}).get("amount_usd", 0) < amount_usd:
        raise PermissionError("Amount exceeds what was authorized in the envelope")

    # All checks pass — proceed
    _do_approve_payment(vendor, amount_usd)

The AGP server as a microservice

The AGP reference server is itself a microservice — deploy it alongside your existing services. It has no external dependencies beyond a database for storing governance objects. The Python SDK and TypeScript SDK handle authentication and connection management for your agent-side code.

# docker-compose.yml — AGP alongside your services
services:
  agp-server:
    image: python:3.12-slim
    command: uvicorn main:app --host 0.0.0.0 --port 8099
    working_dir: /app
    volumes: [./server:/app]
    environment:
      AGP_AUTH_SECRET:   ${AGP_AUTH_SECRET}
      AGP_CLIENT_ID:     ${AGP_CLIENT_ID}
      AGP_CLIENT_SECRET: ${AGP_CLIENT_SECRET}
    ports: ["8099:8099"]

  payment-service:
    build: ./payment-service
    environment:
      AGP_SERVER_URL: http://agp-server:8099
      AGP_TOKEN:      ${PAYMENT_SERVICE_AGP_TOKEN}

  customer-service:
    build: ./customer-service
    environment:
      AGP_SERVER_URL: http://agp-server:8099
      AGP_TOKEN:      ${CUSTOMER_SERVICE_AGP_TOKEN}
One AGP server governs the whole estate. Every agent, every microservice, every action envelope goes through the same AGP server. One place to check the audit ledger. One place to revoke capability tokens. One policy engine to update when your rules change.

What you get

1
Every service call has provenance
The action envelope proves the call was policy-cleared and capability-checked before the agent made it. Services don't have to trust the agent — they verify the envelope. If it's valid, the action was authorized.
2
Scope enforcement at the service boundary
An agent's action envelope is scoped to a specific tool_id. A read-scoped envelope is rejected by a write endpoint — even if the agent presents a valid token. Scope is checked at verification time, not at issuance time.
3
Distributed audit in one place
Every service call that passes through the AGP gate is logged to the audit ledger. No log aggregation across services — one ledger replay shows the full sequence of agent actions across your entire microservice estate.
4
Revocation propagates instantly
Revoke a capability token and any subsequent service call presenting an envelope from that token is immediately rejected — at the gateway or in the middleware. No cache to flush, no services to notify individually.

Next steps

Integration Guide

MCP

Govern tool calls from any MCP-compatible agent runtime. Works with Claude, LangChain, AutoGen, and custom runtimes.

Integration Guide

Agent-to-Agent (A2A)

Sub-token delegation, liability chains, and cascade revocation across orchestrator and worker agents.