The Only AgentCore Middleware AWS Shipped Is About Payments. That Is Not Why You Should Care.
AgentCore's only first-party LangChain middleware is payments, and it is less interesting as a billing feature than as the published template for every adapter you will write at the middleware seam.

AgentCore Payments middleware is the published template for every LangGraph and DeepAgents adapter you will write: config, class, list item, done.
You keep being told to put extensions in middleware, then never get a worked example of what a good one looks like. The payments middleware is the template, not the product pitch.
In this article: You will learn how AgentCore Payments middleware handles HTTP 402 (x402) with zero wrapper code, why the same middleware drops into DeepAgents unchanged, and how to copy its three-step shape for Gateway rebinding and custom spans. By the end you will treat payments as a worked extension seam, and you will know why a budget must ship in the same commit.
The series keeps pointing at a seam and then walking past it. DeepAgents exposes a middleware parameter: the slot where you extend the harness without forking it. Dynamic Gateway tool rebinding belongs there. Your own observability spans belong there. Both times the advice is the same: write middleware, pass it in the list, move on.
Nobody shows you the shape.
Amazon Bedrock AgentCore ships exactly one first-party middleware for the LangChain family, and it is the payments one. Most readers will not need agent payments tomorrow. You still need thirty minutes with this package, because it is the only example AWS has published of what a well-made adapter at this seam looks like. The feature meters an agent per action. The lesson is the template.
What AgentCore Payments middleware does
bedrock_agentcore.payments.integrations.langgraph handles HTTP 402 responses, the x402 Payment Required protocol, automatically. The SDK's own README frames it as zero wrapper code: build the middleware, pass middleware=[payments] to create_agent, and the harness handles payment-required responses without you wrapping ainvoke.
The shape is three steps: a config dataclass, a middleware instance built from it, and that instance in the middleware list.

from langchain.agents import create_agent
from bedrock_agentcore.payments.integrations.langgraph import (
AgentCorePaymentsConfig, AgentCorePaymentsMiddleware,
)
config = AgentCorePaymentsConfig( # ①
payment_manager_arn="arn:aws:bedrock-agentcore:us-east-1:123456789012:payment-manager/pm-123",
user_id="user-123",
payment_instrument_id="instrument-456",
region="us-east-1",
auto_session=True,
)
payments = AgentCorePaymentsMiddleware(config) # ②
agent = create_agent(model="claude-sonnet-4-6", tools=[], middleware=[payments]) # ③
① AgentCorePaymentsConfig holds the payment-manager ARN, user, instrument, and region; identifiers only, no call-site glue.
② AgentCorePaymentsMiddleware is constructed from that config and becomes the list item you pass in.
③ create_agent receives middleware=[payments] with no wrapper around the agent constructor.
Note: The full extracted listing at code/agent-core/appendix-b-payments-middleware/listings/01-create-agent-payments.py shows the runnable form.
Under the hood, when a tool or data source returns 402, the middleware completes the payment flow against the AgentCore payment manager and retries. The model is not asked nicely to "please pay." Protocol handling is mechanical.

Why the same middleware works with DeepAgents
Here is the actual point of this appendix.
DeepAgents is built on LangChain's create_agent and accepts the same middleware=[...] list. So the first-party middleware AWS wrote for create_agent works with create_deep_agent with no adapter, no wrapper, and no special permission:
from langchain_aws import ChatBedrockConverse
from deepagents import create_deep_agent
from bedrock_agentcore.payments.integrations.langgraph import (
AgentCorePaymentsConfig, AgentCorePaymentsMiddleware,
)
payments = AgentCorePaymentsMiddleware( # ①
AgentCorePaymentsConfig(
payment_manager_arn="arn:aws:bedrock-agentcore:us-east-1:123:payment-manager/pm-123",
user_id="user-123",
payment_instrument_id="instrument-456",
region="us-east-1",
auto_session=True,
)
)
agent = create_deep_agent( # ②
model=ChatBedrockConverse(model="us.anthropic.claude-sonnet-4-6"), # ③
tools=[],
system_prompt="You are a market analyst. Some data sources charge per query.",
middleware=[payments], # ④
)
① Same config-plus-middleware construction as the create_agent path; nothing DeepAgents-specific in the payments object.
② create_deep_agent is the DeepAgents entry point, and it still accepts a middleware list.
③ The model is a Bedrock Converse chat model, orthogonal to the payments wiring.
④ middleware=[payments] is the same slot and the same instance: no adapter and no wrapper.
Note: The full extracted listing at code/agent-core/appendix-b-payments-middleware/listings/02-deep-agent-payments.py shows the runnable form.

That is harness externalization in its most literal form. DeepAgents exposes its harness as constructor arguments; middleware is one of them. An extension written for a different framework in the same family drops in untouched.
Compare that to a harness that only offers framework-private hooks. The equivalent payment behavior would be a hand-written hook against that SDK's own taxonomy, with no possibility of reusing AWS's middleware object. That is not a criticism of either design. It is the cost side of "the harness is invisible until you need it": when the harness hides inside the product, extensions are product-shaped too.
Copy the template, do not invent a wrapper
When you write the next adapter, this is the shape:
- A config dataclass with the identifiers and the region (or endpoint, tracer, refresh interval).
- A middleware class constructed from it.
- Pass it in the list. No wrapper code at the call site.
For dynamic Gateway rebinding, that means a GatewayToolRefreshConfig for gateway endpoint, token provider, and refresh interval, plus a GatewayToolRefreshMiddleware that re-queries tools/list and rebinds per turn. For your own spans, a config with a tracer and a middleware that wraps node execution. Same shape both times.

Copy the shape rather than invent one because middleware composes. middleware=[payments, gateway_refresh, tracing] works. A pile of ad-hoc wrappers around ainvoke does not. Composition is the reason the three-step pattern is not cosmetic; it is how multiple independent concerns stay independent at the call site.
The harness engineering beat: protocol is not a budget
One observation is not about payments at all.
An agent that can pay for things has a new failure mode, and it is an old failure mode. Hosted, unattended loops already need spend limits on tokens; frameworks that expose something like max_budget_usd are valuable because an hours-long session can burn money without anyone watching. That was about model usage.
Now the agent can also spend money on data. A market-intelligence agent with a payment instrument and a 402-handling middleware, running unattended, iterating on a research task, is a loop whose cost function includes third-party charges it authorizes itself. The middleware makes the payment work. It has no opinion about whether the fortieth paid query was a good idea.
So if you wire payments, wire a budget with it, in the same commit. Not because payments are uniquely dangerous, but because "the harness handles it automatically" and "somebody bounded it" are different sentences. The whole craft of harness engineering lives in the gap between them.
Pattern check: the payments middleware is mechanical enforcement of a protocol. A 402 gets handled correctly, every time, without the model being asked nicely. It is not mechanical enforcement of a limit. The limit is yours. It is a stopping condition you own, and it belongs next to the other stopping conditions you already set for time, turns, and token spend.

Do this today
- Install or upgrade the AgentCore SDK and open
bedrock_agentcore.payments.integrations.langgraph; readAgentCorePaymentsConfigandAgentCorePaymentsMiddlewareas a shape study even if you never enable payments. - Paste the
create_agentwiring above into a scratch file, then swapcreate_agentforcreate_deep_agentand confirm the samepaymentsobject still type-checks and constructs. - Sketch one non-payments adapter in the same three steps: config dataclass, middleware class, list item. Gateway refresh or span wrapping is enough; do not implement the body yet.
- If you do enable payments, add a hard budget or max-paid-calls stopping condition in the same commit as the middleware list entry.
- Prefer
middleware=[...]composition over wrappingainvokewhen two concerns both want to sit around the agent loop.
The template is the product
AgentCore Payments middleware is a real feature: x402 handling, payment manager ARNs, instruments, sessions. That is useful when an agent must buy data per query.
The reason this appendix exists is narrower. AWS shipped one first-party LangChain-family middleware, and it demonstrates a portable contract: identifiers in a config, behavior in a class, call site reduced to a list. DeepAgents accepts that list because it externalized the harness. Your Gateway refresh middleware and your tracing middleware should look the same so they compose instead of nesting.
Automatic protocol handling is not the same as a bound. Wire the payment path if you need it. Wire the limit either way. The seam was always the point; payments just happened to be the example that shipped.