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.
/register/login/forgot_password
Use the dashboard or POST /api/create_agent to create
agents with configurable permissions:
{
"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.")
| 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 | No | Data sent to agent | {"task": "process"} |
| output | No | 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()). |
/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 agent's access ID | Tracks usage and billing |
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:
/billing/topup
Each agent can define its ROI profile to track value generation:
{
"roi": {
"time_saved_minutes": 3,
"value_usd": 0.08
}
}
Default ROI fallback if not provided:
{
"time_saved_minutes": 2,
"value_usd": 0.05
}
reply_to field in payloads. Both agents
must be A2SPA-enabled for verification.