Connect an agent
One proposed purchase. Three ways to ask.
An agent wants to spend €184.50 with Northstar Office Supply on office supplies, against cost centre OPS-2026-04. Below is that exact request through the MCP tool, over REST, and from the TypeScript SDK. The same Zod schema validates all three, the same engine decides them, and all three land in the same Activity record.
None of these can move money. A spend request is a question. The answer is recorded and returned; no supplier is contacted, no approver is asked and no rail is called. Execution does not exist in Shadow Mode.
1 — MCP: observe_spend_request
For an agent that speaks the Model Context Protocol. The server exposes six tools; this is the one that asks a policy question.
The MCP server acts for the agent configured by the operator through PAYGENTE_AGENT_EXTERNAL_ID. The tool caller cannot override that identity, and the tool takes no agent parameter.
→ tool: observe_spend_request
{
"recipientId": "rcp_01JQ8F7Z9K3M4N5P6Q7R8S9T0V",
"amount": "184.50",
"category": "office",
"commitmentType": "MERCHANT_ORDER",
"purpose": "Desk chairs and monitor arms for the
two new research hires.",
"projectReference": "OPS-2026-04"
}← result
Your policy would have let this through without
asking anyone.
WITHIN_POLICY — within every limit the policy sets.
Nothing was paid, ordered or reserved. This request
was observed, not authorized.
https://…/app/activity/spi_01JQ…2 — REST: POST /api/v1/spend-intents
The decision comes back in the same response. An agent that had to poll for the answer would have acted before it arrived.
POST /api/v1/spend-intents
Content-Type: application/json
X-Paygente-Demo: <token from POST /api/v1/demo/sessions>
Idempotency-Key: procurement-2026-04-02-0031
{
"agentId": "agt_01JQ8F7Z9K3M4N5P6Q7R8S9T0V",
"recipientId": "rcp_01JQ8F7Z9K3M4N5P6Q7R8S9T0V",
"asset": "EUR",
"amount": "184.50",
"category": "office",
"commitmentType": "MERCHANT_ORDER",
"purpose": "Desk chairs and monitor arms for the two new research hires.",
"projectReference": "OPS-2026-04"
}201 Created
{
"intent": {
"id": "spi_01JQ8F7Z9K3M4N5P6Q7R8S9T0V",
"mode": "SHADOW",
"money": {
"asset": "EUR",
"amountMinor": "18450",
"amount": "184.50",
"amountDisplay": "€184.50"
},
"category": "office",
"commitmentType": "MERCHANT_ORDER",
"projectReference": "OPS-2026-04"
},
"decision": {
"outcome": "ALLOW",
"explanation": "Your policy would have let this through
without asking anyone.",
"reasons": [
{ "code": "WITHIN_POLICY",
"message": "Within every limit the policy sets." }
],
"engineVersion": "policy-engine@1.0.0"
},
"url": "https://…/app/activity/spi_01JQ…"
}3 — TypeScript SDK
Provide a stable idempotency key for each logical request and reuse that same key when retrying it. Paygente replays the original result for the same key and payload, and rejects reuse with a different payload. The client forwards the key you give it and never invents one — a value minted per attempt would be new on every retry, which protects nothing.
import { PaygenteClient } from '@paygente/sdk';
const paygente = new PaygenteClient({
baseUrl: process.env.PAYGENTE_API_URL!,
// Demo sessions only. Production authentication is not built yet.
demoToken: process.env.PAYGENTE_DEMO_TOKEN!,
});
const { decision, url } = await paygente.submitSpendIntent(
{
agentId,
recipientId,
asset: 'EUR',
amount: '184.50',
category: 'office',
commitmentType: 'MERCHANT_ORDER',
purpose: 'Desk chairs and monitor arms for the two new research hires.',
projectReference: 'OPS-2026-04',
},
// Stable across retries of this same order — not a fresh value each attempt.
{ idempotencyKey: 'procurement-2026-04-02-0031' },
);
if (decision.outcome === 'DENY') {
// Do not buy it. Nothing was charged either way — Shadow Mode
// records the answer, it does not act on it.
console.error(decision.explanation, url);
}Authentication, honestly
What works today
An anonymous demo session. POST /api/v1/demo/sessions returns a token; send it as X-Paygente-Demo. The token is shown once, it is scoped to one throwaway organization, and it expires.
What does not exist yet
API keys, service accounts, scopes and production authentication are not built. A demo session is not a production credential and must not be treated as one. Do not put real supplier data in the sandbox.