Skip to content
Metamynd
Developers · Example

A procurement agent in 10 minutes

An AI agent that raises purchase orders, bounded by an approved vendor list, a RM10,000 ceiling and a human signature above RM5,000 — enforced when it acts, not asked of it in a prompt.

The problem

A prompt is not a control

You can tell a purchasing agent to use approved vendors and stay under RM10,000. It will usually comply. But 'usually' is not a control you can show an auditor, and an agent that can be argued out of a rule was never bounded by it — it was only asked.

The four outcomes below are decided by a server the agent does not control, against authority someone issued it deliberately. The agent is not consulted about whether it may proceed. That is the whole difference.

Step 1

Issue the authority

A mandate is a verifiable credential: which action, which vendors, how much per order, how much in total. It is issued by a legal entity — KYC/KYB-verified for mainnet, with its verification status disclosed on every verdict — and the delegation chain ends at a person, never at another agent.

mandate.sh
# The authority. Approved vendors and the ceiling live HERE, not in a prompt —
# the agent cannot talk its way past them because it never evaluates them.
curl -X POST https://metamynd.ai/api/v1/policy/mandate \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "agentDid":  "did:hedera:testnet:...your-agent...",
    "scope":     "purchase-order",
    "currency":  "MYR",
    "perTxnMax": 10000,
    "maxAmount": 100000,
    "merchants": ["acme-supplies", "nusantara-office", "kl-industrial"]
  }'
Step 2

Add the approval threshold

The ceiling is authority; the threshold is policy. Keeping them apart matters: your finance team edits the threshold in the dashboard without redeploying anything, and nobody can raise the ceiling by editing a rule.

approval-threshold.sh
# The rule. A purchase order over RM5,000 is not refused — it waits for a human.
curl -X POST https://metamynd.ai/api/v1/sop \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Procurement approval thresholds",
    "documentJson": {
      "molecules": [{
        "id": "threshold",
        "name": "Over RM5,000 needs a human",
        "combinator": "any",
        "atoms": [{ "id": "a1", "predicate": "amount-over", "config": { "limit": 5000 } }],
        "decision": "escalate",
        "reasonCode": "PROCUREMENT_APPROVAL_REQUIRED"
      }]
    }
  }'

# Then bind it to the agent:
curl -X POST https://metamynd.ai/api/v1/sop/agents/$IDENTITY_ID/assign \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{ "sopId": "'"$SOP_ID"'" }'
Step 3

Wrap the function

Three lines around code you already have. The guard signs each request, and refuses to run your function unless the gate allows it — including when the gate is unreachable, which fails closed.

procurement-agent.ts
import { createGuardFromConfig } from "@metamynd/agentsafe-guard";

const guard = await createGuardFromConfig("./agent.metamynd.json");

// Your existing function. Unchanged, and unaware it is governed.
async function rawRaisePO({ vendor, amount, items }) { /* ... */ }

// The governed one. It runs only on allow; a block or an escalate throws.
export const raisePO = guard.guardTool("purchase-order", rawRaisePO, (po) => ({
  amount: po.amount,
  currency: "MYR",
  merchant: po.vendor,
}));
Step 4

What the agent gets back

Every one of these is a reason code the gate actually returns, carried into the audit record.

RM2,400 to acme-suppliesallowAUTHORIZED

An approved vendor, under both the cap and the approval threshold. The PO is raised.

RM8,000 to acme-suppliesescalatePROCUREMENT_APPROVAL_REQUIRED

Over the RM5,000 threshold. The agent stops and waits; a human approves, and only then does it proceed.

RM24,000 to acme-suppliesblockSPEND_LIMIT_EXCEEDED

Over the RM10,000 ceiling in the mandate. No human can wave this through — it is beyond the authority that was delegated.

RM2,400 to a substituted vendorblockMERCHANT_NOT_ALLOWED

The classic procurement fraud: same amount, same description, different payee. The vendor is not on the list, so it never happens.

Step 5

The record afterwards

Every decision above — including the refusals — is signed, batched into a Merkle tree and anchored. Refusals matter most: they are the evidence a control was working on the days nothing went wrong.

  • Who acted, under whose authority, and against which rules
  • The reason code, from a published set of 64
  • An inclusion proof checkable against the anchored root
  • Verifiable offline — an auditor does not have to trust us, or ask us

What you need. This one needs an account, because you are issuing your own mandate against your own principal — verified, or on the free tier (1 agent, 5 mandates) if you haven't completed KYC/KYB yet. The no-account sandbox agent is scoped to flight bookings, so a purchase-order against it returns NO_MANDATE. If you want to see the gate answer before signing up, the quickstart runs live in your browser with no account at all.

Govern your own agents

Issue a mandate, bind your rules, and get an audit trail your auditor can check without asking you for anything.