Stop Guessing Who's Calling Your Agents: Cryptographic Contracts in E-Commerce

The "Trust Me" Problem
You've built a beautiful multi-agent e-commerce system. The payment agent processes charges. The inventory agent manages stock. The fulfillment agent talks to an LLM. Everything works perfectly in your test environment.
Then you deploy to production, and suddenly your payment agent is accepting POST requests to /charge from... who exactly?
Without cryptographic verification, your payment agent is secured by hope, not by trust. Any service on your network — or anyone who can guess your API shape — can call it. That's not fear-mongering. That's how unauthenticated HTTP works.
Here's the practical fix using signed contracts between every agent pair, with about 30 lines of code total.
The Architecture
Four agents, four risk profiles:
┌────────┐ ┌────────┐ ┌────────┐
│ Order │ ──▶│ Inventory │ │ Payment. │
│ Agent │ │ Agent │ │ Agent │
│ (Low risk) │ │ (Med risk) │ │ (High risk) │
└────────┘ └────────┘ └────────┘
│ │
│ ┌────────┐ │
└────────▶│ Fulfillment │◀──────┘
│ Agent │
│ (Med risk) │
└────────┘
Each arrow in that diagram becomes a cryptographically signed contract. No contract = no call.
The Implementation (The Interesting Part)
1. Agent registration and contract issuance
from codios import CodiosClient
codios = CodiosClient(api_key="codios_sk_...")
order = codios.agents.register(name="order-agent")
payment = codios.agents.register(name="payment-agent")
contract = codios.contracts.issue(
caller_did=order.did,
callee_did=payment.did,
scopes=["payment:charge:max_10000usd"], # No refund permission here
ttl_seconds=3600
)
The key insight: refund scope is deliberately excluded. If the order agent tries to call /refund, it physically cannot because the contract token doesn't include that scope. There's no runtime permission escalation possible.
2. Attaching the contract to every call
async def charge_customer(order_id: str, amount: float):
resp = await httpx.post(
"http://payment-agent/charge",
json={"order_id": order_id, "amount": amount},
headers={"X-Codios-Contract": contract.token},
)
return resp.json()
3. Verification on the receiving side (no network call, just crypto)
@app.post("/charge")
async def charge(request: Request, body: dict):
contract = verify_contract(
token=request.headers.get("X-Codios-Contract"),
required_scope="payment:charge",
platform_public_key=CODIOS_PUBLIC_KEY,
)
if body["amount"] > contract.scope_limit("payment:charge"):
raise HTTPException(403, "Exceeds contract limit")
return await process_payment(body["order_id"], body["amount"])
That verify_contract call checks:
- Ed25519 signature (tamper-proof)
- Nonce (replay attack protection)
- Scope (permission boundary)
- Expiry (time-limited access)
All in about 10 microseconds. No round-trip to a central service.
The Two Bonus Protections
Human approval for high-risk actions
Refunds over $500 require a real person to click Approve:
if body["amount"] > 500:
decision = await approval.request(
action="process_refund",
details={"order_id": body["order_id"], "amount": f"${body['amount']:,.2f}"},
notify=["ops-team@yourcompany.com"],
timeout_seconds=600,
)
if not decision.approved:
return {"status": "rejected"}
LLM prompt injection firewall
Customer-supplied addresses can contain injection attacks. Scan before the LLM sees anything:
scan = await fw.scan(content=body["address"], context="shipping_address")
if scan.threat_detected:
raise HTTPException(400, "Invalid shipping address")
Why This Matters for Your Stack
| Without contracts | With contracts |
|---|---|
Any service can call /charge |
Only callers with valid signed tokens |
| Permissions are runtime-configurable (risky) | Permissions are cryptographically bound |
| No proof of who approved what | Full audit trail of every agent action |
| Replay attacks possible | Nonce checking prevents replays |
| LLM prompt injection vulnerabilities | Pre-LLM scanning blocks injection |
The Bottom Line
~30 lines of instrumentation. Free tier covers 5 agents. Runs entirely locally after contract issuance.
Multi-agent systems are powerful, but they multiply your attack surface. Cryptographic contracts are how you turn that surface into a feature instead of a liability.
Full tutorial with all code blocks: Codios Blog
Try Codios → codios.midlantics.com
Try A2A → a2a.midlantics.com




