Agent-to-Secure Payload Authorization
A2SPA is the cryptographic firewall for AI agents, ensuring that every autonomous action is signed, verified, authorized, and monitored. Build secure agent-to-agent communication with enforced permissions, replay protection, and comprehensive audit trails.
A2SPA (Agent-to-Secure Payload Authorization) is a secure protocol that enables verified, cryptographically signed payloads between AI agents. This platform allows developers and non-technical users to create, manage, and monitor modular AI agents, all protected by A2SPA.
/A2SPA/register/A2SPA/login/A2SPA/forgotIf you want browser AI assistants or coding agents to wire existing agents into A2SPA, use the public API Integration Pack. It teaches AI how to create agents through the dashboard Builder Pack and how to add runtime code that still routes through the A2SPA API instead of bypassing it.
POST /A2SPA/api/verify_payload.
POST /A2SPA/api/verify_payload for sending and
GET /A2SPA/api/inbox_for_agent for polling received
messages. Use GET /A2SPA/api/logs_for_agent for audit
history and troubleshooting.
Use the dashboard to create agents. Choose an agent name, decide whether it can send and/or receive, and keep the generated private key in a secure location. If you use a browser-based AI assistant, open the dashboard's Agent Builder Pack for the same flow in a machine-readable format.
{
"agent_name": "calendarAgent",
"permissions": {
"send": true,
"receive": false
},
"enabled": true
}
| Permission | Description |
|---|---|
send |
Can initiate actions or payloads |
receive |
Can be a target agent and receive payloads |
š Helps prevent abuse even if an agent is compromised.
To send a message (payload), you need to create it, hash it, sign it, and send it to A2SPA for verification. Here's how it works:
What You Need:
import json, uuid, requests, hashlib
from datetime import datetime, timezone
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
# ============ Settings ============
API_BASE = "https://aimodularity.com/A2SPA"
API_KEY = "YOUR_API_KEY_HERE" # Get from dashboard
USER_ID = "your_user_id"
SENDER_AGENT_ID = f"{USER_ID}_my_agent_send"
RECEIVER_AGENT_ID = f"{USER_ID}_my_agent_receive"
PRIVATE_KEY_PATH = "your_sender_agent.priv.pem"
# ============ Helper Function ============
def sha256_hex(obj):
"""Create a hash of the message, excluding 'hash' and 'signature' fields"""
clean = {k: v for k, v in obj.items() if k not in ["hash", "signature"]}
data = json.dumps(clean, sort_keys=True).encode()
return hashlib.sha256(data).hexdigest()
# ============ Step 1: Create Message ============
payload = {
"agent_id": SENDER_AGENT_ID,
"target_agent_id": RECEIVER_AGENT_ID,
"timestamp": datetime.now(timezone.utc).isoformat(),
"nonce": str(uuid.uuid4()), # Unique code to prevent reuse
"input": {"message": "Hello from sender agent!"},
"output": {"status": "ready"}
}
print("ā
Step 1: Message created")
# ============ Step 2: Hash the Message ============
payload["hash"] = sha256_hex(payload)
print(f"ā
Step 2: Hash created: {payload['hash'][:16]}...")
# ============ Step 3: Sign the Message ============
with open(PRIVATE_KEY_PATH, "rb") as f:
PRIVATE_KEY_PEM = f.read()
private_key = serialization.load_pem_private_key(
PRIVATE_KEY_PEM,
password=None
)
clean_for_sign = {k: v for k, v in payload.items()
if k not in ["hash", "signature"]}
message = json.dumps(clean_for_sign, sort_keys=True).encode()
signature_hex = private_key.sign(
message,
padding.PKCS1v15(),
hashes.SHA256()
).hex()
print(f"ā
Step 3: Signature created: {signature_hex[:16]}...")
# ============ Step 4: Send to A2SPA ============
resp = requests.post(
f"{API_BASE}/api/verify_payload",
headers={
"Content-Type": "application/json",
"x-api-key": API_KEY
},
json={
"payload": payload,
"signature": signature_hex
}
)
print(f"\nšÆ Result:")
print(f"Status Code: {resp.status_code}")
print(f"Response: {resp.text}")
if resp.status_code == 200:
print("\nā
Success! Message verified and logged.")
else:
print("\nā Error: Check the response message.")
curl -H "x-api-key: YOUR_API_KEY_HERE" "https://aimodularity.com/A2SPA/api/inbox_for_agent?agent_id=YOUR_RECEIVER_AGENT_ID&limit=25"
Use the inbox endpoint when an existing agent needs to poll for received
messages through the A2SPA API. Use /api/logs_for_agent
when you want audit history or troubleshooting detail.
| Field | Required? | Description | Example |
|---|---|---|---|
| agent_id | Yes | Sender's agent ID | abc123_myAgent |
| target_agent_id | Yes | Receiver's agent ID | def456_otherAgent |
| timestamp | Yes | UTC time of message | 2025-10-07T14:30:00Z |
| nonce | Yes | Unique code to prevent reuse | a1b2c3d4-e5f6-... |
| input | Yes | Data sent to agent | {"task": "process"} |
| output | Yes | Agent's response | {"result": "done"} |
| hash | Yes | Message fingerprint | a3f8e2b9c1d... |
| Error | Cause | Fix |
|---|---|---|
| Signature verification failed | Wrong hash or private key | Hash first, then sign with correct key. |
| Agent not found | Wrong agent ID | Copy ID exactly from dashboard. |
| Timestamp too old | Message older than 2 minutes | Send immediately using datetime.now(timezone.utc). |
| Replay attack detected | Reused nonce | Use a new str(uuid.uuid4()). |
POST /A2SPA/api/verify_payload: 120 requests per minute per client IP by defaultGET /A2SPA/api/inbox_for_agent: 60 requests per minute per client IP by defaultGET /A2SPA/api/logs_for_agent: 60 requests per minute per client IP by defaultPOST /A2SPA/login: 10 requests per 15 minutes per IPPOST /A2SPA/register: 5 requests per hour per IPPOST /A2SPA/forgot: 5 requests per hour per IPPOST /A2SPA/billing/topup: 10 requests per 15 minutes per signed-in userHTTP 429
plus a Retry-After header. This helps protect the
platform against abuse while keeping dashboard and API usage
predictable for customers.
/A2SPA/api/toggle_agent_status
| Mistake | Fix |
|---|---|
| Reusing a nonce or timestamp | Use uuid4() and datetime.utcnow() |
| Sending wrong agent_id | Match dashboard agent exactly |
| Forgetting to hash the payload | Call compute_payload_hash() |
| Signing before adding the hash | Always hash first, then sign |
| Payload too old (>2 min) | Send immediately, use NTP-synced clocks |
| Agent is toggled OFF | Go to dashboard and toggle it ON |
| Term | What It Means | Why It Matters |
|---|---|---|
| Nonce | One-time string (UUID) | Stops replay attacks |
| Hash | Fingerprint of the payload | Proves nothing changed |
| Signature | Encrypted proof of identity | Proves you sent it |
| API Key | Your account-level API token for calling A2SPA endpoints | Authenticates API requests and tracks usage |
The A2SPA dashboard provides comprehensive monitoring and management capabilities for your agents:
Each log entry contains:
| Status | Balance | Indicator | API Access |
|---|---|---|---|
| Normal | >10 tokens | Green status | Full access |
| Warning | <10 tokens | ā ļø Yellow banner | Full access |
| Critical | 0 tokens | š“ Red banner | API disabled |
A2SPA uses a simple, transparent pay-as-you-go model:
Verification logs can include ROI values from an agent's stored ROI profile. If no ROI profile is stored, A2SPA uses a default fallback.
{
"roi": {
"time_saved_minutes": 3,
"value_usd": 0.08
}
}
Default ROI fallback if not provided:
{
"time_saved_minutes": 2,
"value_usd": 0.05
}
send permission and the target has
receive permission. Delivery threading is added to the
dashboard automatically.