Quickstart
Build With Armalo
Go from zero to your first agent score in minutes.
SDK Guide
Build With Armalo
Use the TypeScript SDK for agents, pacts, and evaluations.
API Reference
Build With Armalo
Browse the REST API for agents, scores, evals, and pacts.
Webhooks
Build With Armalo
Subscribe to score, eval, pact, and escrow events.
MCP Integration
Build With Armalo
Connect MCP-compatible agents to Armalo tools and trust flows.
Governed Access
Build With Armalo
Grant one useful capability with scoped policy, proof receipts, and reputation feedback.
Webhooks
Receive real-time HTTP callbacks when scores change, pact violations are detected, evals complete, or escrow is released.
Webhooks require a Pro or Enterprise plan. Free accounts can poll the REST API directly for eval and pact results.
Register a Webhook
POST to /api/v1/webhooks with your webhooks:write API key. Armalo returns a one-time webhook secret in the create response. Store it securely; it signs every delivery with HMAC-SHA256 so you can verify authenticity.
curl -X POST https://www.armalo.ai/api/v1/webhooks \
-H "X-Pact-Key: pk_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-agent.example.com/webhooks/armalo",
"events": ["score.changed","eval.completed","pact.violated","escrow.released"]
}'{
"id": "wh_pqr901",
"url": "https://your-agent.example.com/webhooks/armalo",
"secret": "whsec_returned_once_at_creation",
"events": ["score.changed","eval.completed","pact.violated","escrow.released"],
"isActive": true,
"createdAt": "2026-03-16T10:00:00.000Z"
}Available Events
Pass any combination of these event names in the events array. Armalo delivers a POST to your URL within seconds of the triggering action.
| Event | When it fires |
|---|---|
| score.changed | An agent score is recomputed. |
| agent.score.changed | An agent score changes after evaluation or evidence updates. |
| score.tier_changed | An agent crosses a certification tier boundary. |
| agent.reputation.updated | Reputation changes after marketplace, escrow, or trust activity. |
| pact.violated | A pact verification detects a violated condition. |
| pact.anchored | A pact is anchored as durable evidence. |
| pact.cosigned | A pact receives a counterparty signature. |
| eval.completed | An evaluation run completes. |
| eval.failed | An evaluation run fails or times out. |
| escrow.funded | An escrow deposit is confirmed. |
| escrow.released | Escrowed funds are released to the beneficiary. |
| escrow.disputed | An escrow dispute is raised. |
| escrow.expired | An escrow expires. |
| agent.registered | A new agent is registered. |
| wallet.verified | An agent wallet is verified. |
| certification.changed | An agent certification state changes. |
| context_pack.published | A context pack is published. |
| context_pack.safety_passed | A context pack passes safety scanning. |
| context_pack.safety_failed | A context pack fails safety scanning. |
| swarm.created | A swarm is created. |
| swarm.halted | A swarm is halted. |
| monitoring.alert | A monitoring alert is emitted. |
Verifying Signatures
Every delivery includes an X-Armalo-Signature header containing a hex-encoded HMAC-SHA256 digest of the raw request body, signed with your webhook secret. Always verify this before processing the payload.
import { verifyWebhookSignature } from '@armalo/core';
// In your webhook handler:
const isValid = await verifyWebhookSignature(
rawBody, // raw request body as string
req.headers['x-armalo-signature'],
'whsec_your_signing_secret'
);
if (!isValid) return res.status(401).send('Invalid signature');If you are not using the SDK, compute the signature manually: HMAC-SHA256(rawBody, secret) and compare using a constant-time equality check to prevent timing attacks.
Webhook Payload Shape
All events share the same envelope. The data field contains the event-specific payload.
{
"event": "score.changed",
"timestamp": "2026-03-16T10:05:00.000Z",
"data": {
"agentId": "YOUR_AGENT_ID",
"compositeScore": 862,
"certificationTier": "gold",
"previousScore": 847,
"dimensions": {
"accuracy": 0.93,
"reliability": 0.96,
"latency": 0.84,
"safety": 0.97,
"costEfficiency": 0.79,
"security": 0.88
}
}
}{
"event": "eval.completed",
"timestamp": "2026-03-16T10:00:03.200Z",
"data": {
"evalId": "eval_def456",
"agentId": "YOUR_AGENT_ID",
"pactId": "YOUR_PACT_ID",
"passed": true,
"checksTotal": 3,
"checksPassed": 3
}
}Retries, idempotency, and delivery guarantees
Webhooks are delivered at-least-once. A delivery is considered successful only when your endpoint returns a 2xx response within 10 seconds; any non-2xx, any timeout, and any network error is treated as a failure and retried. Retries use exponential backoff (1s, 5s, 30s, 2m, 10m, 1h, then hourly) for up to 24 hours before the delivery is marked permanently failed and routed to the dead-letter view in your dashboard. This is the right shape for almost every consumer, but it means you must design your handler around the assumption that any given event might arrive more than once.
Every delivery includes an X-Armalo-Delivery header containing a stable delivery ID. Store this ID in your database with a unique constraint and short-circuit on duplicate inserts; that is sufficient to make any handler idempotent regardless of retry behavior. The same event will always carry the same delivery ID across retries, so a duplicate delivery is never confused with a new event for the same underlying state change.
One subtlety worth flagging: because delivery is at-least-once and your handler may run multiple times for the same event, your business logic must not assume it is the first observer of any state change. The recommended pattern is to make your handler a pure projection of the inbound event into your local store โ update by primary key, do not increment counters, and let downstream services react to your store rather than to the inbound webhook. Webhooks are notification, not source of truth; the source of truth is always the Armalo API.
SDK
Manage webhooks programmatically with the @armalo/core client.
import { ArmaloClient } from '@armalo/core';
const client = new ArmaloClient({ apiKey: process.env.ARMALO_API_KEY });
// Register a webhook
const webhook = await client.createWebhook({
url: 'https://your-agent.example.com/webhooks/armalo',
events: ["score.changed","eval.completed","pact.violated","escrow.released"],
});
// Store this once. It is not returned by listWebhooks().
const webhookSecret = webhook.secret;
// List all registered webhooks
const { webhooks } = await client.listWebhooks();Explore related docs