Getting Started
This guide is the fastest path for a technical evaluator who wants to see Mandaitor work end to end in one sitting. You set up a hosted SAP sandbox, register an agent, and give it a mandate. The agent then asks Mandaitor to release four purchase requisitions. Mandaitor reads each one from the sandbox and decides on what it read. It writes the one within the mandate, asks you to approve the one above the threshold, and refuses the other two. It signs a receipt of each write.
Executions and the MCP server are in Preview. Today:
- The SAP tool cannot be enabled yet. Its business action,
procurement.requisition.release, comes from the procurement taxonomy, which is not loaded yet. Until it is, step 3 lists the tool as unavailable, and step 5's editor does not offer the action.
Beta Limitations lists the rest.
What you will achieve
| Step | Outcome |
|---|---|
| 1–2 | Know the inputs, and have a tenant administrator's access |
| 3 | A hosted SAP sandbox, with its tool enabled |
| 4 | An agent registered with a key only it holds |
| 5 | A mandate for the agent, with a person behind it |
| 6–7 | The agent connected over MCP, and four requests with four outcomes |
| 8 | The request above the threshold approved, and written |
| 9–10 | The receipts checked, and the evidence reviewed |
Turn Academy outputs into the first evaluator run
The Academy helps stakeholders agree on why delegated authority matters. This guide turns that agreement into a sandbox run: one business operation, one mandate, and the outcomes and evidence a reviewer must be able to explain. Use the bridge below before you start, so the technical test stays aligned with the pilot scope.
Carry over the learning route
- Academy output
- A founder, builder, reviewer, or implementation-lead route with the lessons and artifact each role owns.
- Evaluator action
- Assign who will judge the evaluator run: product value, technical fit, evidence quality, or pilot operations.
Use the capstone boundary
- Academy output
- One bounded operation with principal, agent, approver, reviewer, allowed request, denied request, and a request that needs approval.
- Evaluator action
- Translate those fields into the agent, business action, records, limits and approver used in this guide.
Preserve maturity assumptions
- Academy output
- A shared understanding of whether the capability is a preview, beta, stable surface, or operational assurance candidate.
- Evaluator action
- Document what the first run proves, what remains experimental, and what must be reviewed before pilot expansion.
- A one-paragraph pilot use-case statement.
- Principal, agent, approver, reviewer, business action, records and limits.
- At least one request that is written, one that is denied, and one that needs approval.
- The evidence a reviewer must be able to explain after the run.
Evaluation model in one paragraph
Mandaitor carries out an agent's business operations within the mandates people gave it. You do not give the agent the target system's credential and trust it to check first. The agent asks, and Mandaitor reads the record, decides on what it read, asks the mandate's approver where the amount calls for it, performs the write with its own credential, and signs a receipt. What you evaluate is whether the outcome of each request matches the mandate, and whether the evidence explains it.
1. Gather the minimum inputs
| Input | In this guide | Why it matters |
|---|---|---|
| Principal and approver | You, signed in to the dashboard | A person must stand behind the mandate, and approves above the threshold |
| Agent | procurement-agent | The agent that asks, registered with its own key |
| Business action | procurement.requisition.release | What the mandate grants, from the procurement taxonomy |
| Records | procurement:plant:1000/requisition:* | Which records the mandate covers: plant 1000's requisitions |
| Limits | Approval above EUR 10,000; nothing above EUR 100,000 | When a person must approve, and the hard cap no approval overrides |
For your own pilot, replace these with your operation, sites and limits. The first run is for learning how decisions, approvals and receipts behave.
2. Get access
Mandaitor is in invite-only beta, so access is reviewed before it is granted: request it via the Mandaitor trust site, and you will hear back within five business days. The issued access is for sandbox or pilot evaluation; see Beta Limitations for what is stable and what is not.
You need a tenant administrator's account on the dashboard. Steps 3 to 5 are a person's: an API key cannot provision a sandbox, register an agent or enable a tool, and a mandate an API key creates on its own never lets an agent act.
Keep these open while you test:
| Asset | What it gives you | Link |
|---|---|---|
| Interactive API Reference | Every endpoint, schema and example response | /api-reference |
| OpenAPI specification | The full machine-readable contract for your own tooling | /downloads/mandaitor-openapi.yaml |
| Postman collection | The API without writing a client first | /downloads/mandaitor-api.postman_collection.json |
3. Create a SAP sandbox and enable its tool
On the dashboard's Connectors page, choose Create demo sandbox for SAP S/4HANA. Mandaitor hosts an emulation of SAP's purchase requisition service for 30 days, seeded with the requisitions this guide uses, and creates a connector to it. Nobody is shown its credential: only Mandaitor's executor writes to the sandbox.
Under Registered tools on the same page, enable sap.purchase_requisition.release, version 1, on the sandbox's connector. Your tenant's agents can now ask for that operation, and only on that sandbox.
Through the API, both are a person's calls with tenant:write; Setting up shows them.
4. Register the agent with its own key
The agent authenticates as itself, with a key pair whose private half only it holds. Make one, ECDSA on P-256:
import { generateKeyPairSync } from "node:crypto";
import { writeFileSync } from "node:fs";
const { publicKey, privateKey } = generateKeyPairSync("ec", { namedCurve: "P-256" });
// The agent's secret: keep it where the agent runs, never in Mandaitor.
writeFileSync("agent-key.pem", privateKey.export({ format: "pem", type: "pkcs8" }));
// The public half, for the registry.
console.log(JSON.stringify(publicKey.export({ format: "jwk" })));
On the Agent Registry page, choose Register agent, name it procurement-agent, and paste the printed JWK as Its public key (JWK). The agent gets a DID, such as did:web:agents.mandaitor.io:agt_01HXYZ. Note it: the agent names itself by it.
5. Write the agent's mandate
On the Governance page, choose Create mandate:
- Delegate:
procurement-agent. - Business action:
procurement.requisition.release. - Resources:
procurement:plant:1000/requisition:*. - Limits: at most EUR 100,000 per release, and an approval above EUR 10,000.
- Tick Bind it to procurement-agent too, so the agent can open a session under it.
You create it from your own session, so it counts at once. The editor names you as its principal, which makes you its approver. Its delegate, scope and limits, as the editor writes them:
{
"delegate": { "type": "AGENT", "subject_id": "did:web:agents.mandaitor.io:agt_01HXYZ" },
"scope": {
"actions": ["procurement.requisition.release"],
"resources": ["procurement:plant:1000/requisition:*"],
"effect": "ALLOW"
},
"constraints": {
"transaction_limits": { "max_amount": { "currency": "EUR", "value": "100000.00" } },
"escalation_rules": { "amount_above": { "currency": "EUR", "value": "10000.00" } }
}
}
The mandate never names SAP. It names the business action and the plant, so the same mandate would govern a release in any system with a tool for it. A mandate written for executions lists every limit an execution reads.
6. Connect the agent
The agent connects to Mandaitor's MCP server as to any remote MCP server. The dashboard's MCP connection page, under "Govern agents", shows the addresses and checks whether the agent is ready to connect. With the official TypeScript SDK (npm install @modelcontextprotocol/sdk), the agent needs only its DID and its key:
import { readFileSync } from "node:fs";
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
import { PrivateKeyJwtProvider } from "@modelcontextprotocol/sdk/client/auth-extensions.js";
const authProvider = new PrivateKeyJwtProvider({
clientId: "did:web:agents.mandaitor.io:agt_01HXYZ", // the agent's DID
privateKey: readFileSync("agent-key.pem", "utf8"),
algorithm: "ES256",
expectedIssuer: "https://api.mandaitor.io/v1",
});
const client = new Client({ name: "procurement-agent", version: "1.0.0" });
await client.connect(
new StreamableHTTPClientTransport(new URL("https://api.mandaitor.io/v1/mcp"), { authProvider }),
);
const { tools } = await client.listTools();
console.log(tools.map((tool) => tool.name));
// [ "sap_purchase_requisition_release", "get_execution" ]
The client finds out how to authenticate on its own, and gets a session for the MCP server alone, signed for with the agent's key. tools/list shows the tools a mandate naming the agent could back: here the SAP release, and the server's own get_execution.
7. Ask for four releases
The agent names the requisition, nothing else:
type Outcome = { execution_id: string; state: string; state_reason: string };
for (const purchase_requisition of ["10000123", "10000124", "10000125", "10000126"]) {
const result = await client.callTool({
name: "sap_purchase_requisition_release",
arguments: { purchase_requisition, purpose: "Getting started" },
});
const outcome = result.structuredContent as Outcome;
console.log(purchase_requisition, outcome.state, outcome.state_reason);
}
| Requisition | In the sandbox | Outcome |
|---|---|---|
10000123 | Plant 1000, EUR 4,850.00 | SUCCEEDED, APPLIED: within the mandate. Mandaitor released it and read it back. |
10000124 | Plant 1000, EUR 38,500.00 | AWAITING_APPROVAL, APPROVAL_REQUIRED: above the EUR 10,000 threshold. Nothing is written yet. |
10000125 | Plant 1000, EUR 240,000.00 | DENIED, AMOUNT_ABOVE_LIMIT: above the cap, which no approval overrides. |
10000126 | Plant 2000, EUR 3,200.00 | DENIED, NO_COVERING_MANDATE: the mandate covers plant 1000 only. |
The agent never stated an amount or a plant. Mandaitor read both from the sandbox, so an agent cannot get a release through by understating either. A denial is an answer, not an error: it is recorded like every other outcome.
Each requisition can be released once. To run the scenarios again, choose Reset demo data on the sandbox's row of the Connectors page. A repeat of the same call within 10 minutes of its execution's end answers with that execution, so wait that long before you ask again.
8. Approve the release above the threshold
You are the approver of 10000124. Its card is in the dashboard's Consent inbox, and on the execution's page under Executions. It shows the requisition at the version Mandaitor read, its facts, why approval is needed, the digest you approve and when the approval expires. Approve it.
Mandaitor reads the requisition again, and approves only if nothing the approval covered has changed. It then writes the release and reads it back. The agent learns the outcome by asking:
const result = await client.callTool({
name: "get_execution",
arguments: { execution_id: "exe_01J9ZK3Q7V8D2M5N6P4R1S0T9W" }, // 10000124's
});
console.log((result.structuredContent as Outcome).state); // "SUCCEEDED"
Had the requisition changed while it waited, a new approval would replace yours. Had it changed so that it no longer needed one, the execution would be denied with RECORD_CHANGED, and the agent would ask again. An approval is never spent on a record nobody approved.
9. Check the receipts
Each written release carries a receipt: Mandaitor's signed statement of what the write did. It names the record, its version before and after, when the release was decided, sent and completed, who approved it, and the Proof-of-Mandate the write was made on. Check one with the SDK:
import { verifyReceiptForExecution, type Execution } from "@mandaitor/sdk"; // 5.1.0 or later
const result = await client.callTool({
name: "get_execution",
arguments: { execution_id: "exe_…" }, // 10000123's
});
const check = await verifyReceiptForExecution(result.structuredContent as Execution, {
allowedIssuers: ["did:web:api.mandaitor.io:v1"],
});
console.log(check.valid, check.claims?.target);
The SDK checks that the token is a receipt, signed with Mandaitor's receipt key, and that it says what the execution says: its id, its request, its outcome and its result. Receipts gives the same check without the SDK.
10. Review the evidence
| Artifact | Where | What a reviewer should be able to explain |
|---|---|---|
| The four executions | Executions page | Each outcome, and its state_reason, follows from the mandate and the record |
| The approval | The execution's page | Who approved what, at which version of the record |
| The receipts | The executions, through the API | Which record was written, and from which version to which |
| The evidence pack | GET /mandates/{id}/evidence-pack | The mandate's hash-chained audit trail, with its Proofs-of-Mandate and receipts |
If your pilot also needs an approval rejected, or one left to expire, reset the sandbox, ask for 10000124 again, and decide differently: the execution ends DENIED, with APPROVAL_REJECTED or APPROVAL_EXPIRED.
11. Variations
| Variation | What to do |
|---|---|
| Faults at the target | Ask for 10000127: the sandbox makes the release, then times out. The execution is UNKNOWN until Mandaitor reads the record back, then SUCCEEDED. 10000128 answers 503 and changes nothing: FAILED. |
| One mandate, two systems | Create a ServiceNow demo sandbox, enable servicenow.requested_item.approve, and add the Munich plant to the mandate's resources. See A mandate written for executions. |
| Without MCP | The agent sends POST /executions itself, or uses the SDK's executions client. See Requesting an execution. |
| Your own system acts | Your enforcement point asks for a single-use authorization and redeems it before it writes. See Request-bound Decisions. |
12. Next steps
| Next step | Why to read it |
|---|---|
| Executions | The full contract: setup, states, approvals, receipts and errors |
| MCP Server | Connecting MCP clients, the tools list, and how calls answer |
| Proof-of-Mandate and Receipt | What each signed statement says, and how they relate |
| Capstone Pilot Workbook | Turn this run into a reviewer-ready pilot brief with ownership and rollout gates |
| /api-reference | The exact request and response schemas |
If an agent of yours can ask for one operation, and you can explain each outcome and check its receipt, you have the core of a Mandaitor pilot.