INTEGRATION GUIDE

Put a fresh provider-bound claim in front of the operation.

The recommended path separates customer reservation, signed permit issuance, one fresh server-side claim, the executor's idempotent provider call, and outcome checking that does not trust the caller report.

REGISTRY-INDEPENDENT SDKs

Install from the MandateShield origin in one command.

The exact Node.js, Python and Go clients are published at immutable, versioned URLs. No npm, PyPI, GitHub or public Go proxy account is required, and every package is covered by an adjacent SHA-256 checksum.

# Node.js
npm install https://mandateshield.com/packages/npm/1.13.0/mandateshield-sdk-1.13.0.tgz

# Python 3.9+
python3 -m pip install --index-url \
  https://mandateshield.com/packages/python/simple \
  --no-deps mandateshield==1.13.0

# Go 1.21+
GONOSUMDB=github.com/mandateshield/mandateshield-go \
GOPROXY=https://mandateshield.com/packages/go \
go get github.com/mandateshield/mandateshield-go@v1.13.0

PUBLICATION BOUNDARY

Hosted now; no registry claim.

These commands install directly from mandateshield.com. They do not imply that the same package names have been accepted by npm, PyPI, GitHub or the public Go module proxy.

Node.js checksum →Python checksum →Go checksum →

ZERO-DEPENDENCY JAVASCRIPT

Vendor one ESM file.

The client uses the runtime's built-in fetch and AbortController. It has no install script, transitive packages or telemetry. Commit the downloaded file so upgrades are explicit and reviewable.

mkdir -p vendor/mandateshield
curl --proto '=https' --tlsv1.2 -fsSLo \
  vendor/mandateshield/mandateshield.mjs \
  https://mandateshield.com/sdk/v1.13.0/mandateshield.mjs
curl --proto '=https' --tlsv1.2 -fsSLo \
  vendor/mandateshield/SHA256SUMS \
  https://mandateshield.com/sdk/v1.13.0/SHA256SUMS
(
  cd vendor/mandateshield
  if command -v sha256sum >/dev/null 2>&1; then
    grep '  mandateshield.mjs$' SHA256SUMS | sha256sum -c -
  else
    grep '  mandateshield.mjs$' SHA256SUMS | shasum -a 256 -c -
  fi
)

OFFICIAL POSTGRESQL JOURNAL

Replace the production journal placeholder.

Run the first-party DurableGatewayJournal against one customer-controlled PostgreSQL primary. The explicit migration, atomic compare-and-set adapter and readiness check keep database credentials outside MandateShield. All Gate workers must share the same writable, linearizable topology; split-brain remains unsafe.

Open PostgreSQL journal guide →

PRIMARY LAST-MILE PROFILE

Supported AP2 approval facts to one exact Stripe request.

Project the supported closed-payment fields without treating that projection as authority, verify the account-pinned signed approval, and preserve the exact envelope through the Stripe account, payee, amount, currency and form-body digest.

Open AP2-to-Stripe seam guide →

FIRST-PARTY PAYMENT ADAPTER

Stripe PaymentIntents, behind the same durable gate.

Run the gateway and adapter inside your server. Exact amount, merchant, audience and provider idempotency are bound without sending Stripe credentials or PaymentMethod IDs to MandateShield.

Open Stripe adapter guide →

OPTIONAL X402 COMPATIBILITY PROFILE

Add a shared evidence lifecycle without replacing x402.

Native x402 exact/EIP-3009 already supplies value, payee, validity and nonce binding, while payment identifiers and facilitators can provide idempotency, verification and settlement. This optional profile adds the MandateShield reserve, interlock and receipt lifecycle for teams operating both supported paths. Signed payloads, wallet keys and paid content remain customer-side. No facilitator adoption or primary differentiation is claimed.

Open x402 adapter guide →

EXECUTION CONTRACT

A reserved ALLOW is not yet a provider call.

isPolicyAllow is useful for sandbox evaluation. requireAllowed accepts only a live, persisted, account-pinned ALLOW with a consumable RESERVED authorization. The trusted gateway must then use a separate PROCESSOR key, bound to the exact relying-party audience, to CONSUME with an exact provider binding. That creates a prepared durable submission and signed permit but returns provider submission permission false. Only a customer-deployed exclusive executor may obtain the fresh MandateShield claim by redeeming the exact permit online. The executor must attempt the provider operation idempotently; MandateShield does not guarantee exactly-once provider delivery or claim provider or facilitator adoption.

PURCHASE ENVELOPE

Send final, normalized facts—not payment credentials.

Production loads limits and consent from the immutable mandate registry. The execution envelope carries final transaction facts and a new account-wide idempotency key that remains stable for one attempt. Bind the same final envelope to every transition. The hosted MandateShield service never submits or deduplicates the provider charge. A customer-side Gate adapter may prepare one bound request after CONSUME. In the recommended provider-bound path, it may transmit only after the permit is freshly redeemed at the customer-deployed exclusive executor.

{
  "protocol": "CUSTOM",
  "mandate_id": "mnd_2048",
  "agent_id": "agent_travel_07",
  "merchant_id": "merchant_rail",
  "amount": { "value": 124.90, "currency": "USD" },
  "payee_identity": {
    "profile": "MANDATESHIELD_PAYEE_IDENTITY_V1",
    "provider": "STRIPE",
    "merchant_id": "merchant_rail",
    "binding": {
      "connected_account_id": "acct_connected_12345",
      "merchant_account_id": "acct_connected_12345"
    },
    "verification": {
      "method": "STRIPE_ACCOUNT_CONFIGURATION",
      "verifier": "customer-stripe-gateway",
      "evidence_ref": "urn:stripe:connected-account:acct_connected_12345"
    }
  },
  "created_at": "<current ISO-8601 timestamp>",
  "idempotency_key": "checkout_9f22a1",
  "checkout_hash": "sha256:final-checkout-digest",
  "intent_hash": "sha256:..."
}

JAVASCRIPT SDK

Use the pinned client for challenge and reservation.

The v1.7 client covers provider binding, advisory permit verification, exact online redemption and execution-receipt verification. The example first stops at the reservation handoff so the PROCESSOR credential stays in the separate trusted edge. Never infer support beyond a client's published feature surface.

import {
  createClient,
  requireAllowed
} from "./vendor/mandateshield/mandateshield.mjs"

const verifier = createClient({
  apiKey: process.env.MANDATESHIELD_VERIFY_KEY,
  timeoutMs: 10_000
})

const challenge = await verifier.createChallenge({
  mandate_id: purchase.mandate_id,
  protocol: purchase.protocol,
  key_thumbprint: process.env.MANDATESHIELD_KEY_THUMBPRINT
})

// Your trusted issuer signs the canonical purchase digest, challenge nonce,
// and the exact issuer/audience returned for the selected account pin.
const evidence = await trustedIssuer.sign(purchase, {
  nonce: challenge.nonce,
  issuer: challenge.issuer,
  audience: challenge.audience,
  issuedAt: new Date().toISOString(),
  expiresAt: challenge.expires_at_iso
})
const reservation = requireAllowed(await verifier.verifyAuthority({
  envelope: purchase,
  evidence
}))
await handToProviderBoundGateway({
  compact: reservation.signed_receipt.compact,
  receiptId: reservation.signed_receipt.receipt_id,
  envelope: purchase,
  audience: challenge.audience
})

PROVIDER-BOUND EXECUTION

Issue, redeem, submit with the signed key, then reconcile.

The redeem call belongs inside the customer-deployed exclusive executor—not in the agent, browser, merchant page or ordinary checkout worker. That executor must be the sole holder of the provider credential and permitted egress path. A permit lives for at most 60 seconds. A fresh redemption admits one MandateShield claimant; the exact provider operation must still be idempotent. Offline signature verification remains advisory and returns provider submission permission false.

const base = {
  compact: reservation.signed_receipt.compact,
  expected_envelope: purchase,
  expected_audience: processorAudience
}

// Customer gateway: bind one exact request. This does not permit submission.
const consumed = await post("/api/v2/execution-authorizations", {
  ...base,
  action: "CONSUME",
  idempotency_key: `${attemptId}:consume`,
  provider_binding: {
    profile: "STRIPE_PAYMENT_INTENTS_V1",
    environment: "live",
    account: purchase.payee_identity.binding.merchant_account_id,
    request_id: providerRequestId,
    payee_destination:
      purchase.payee_identity.binding.connected_account_id,
    method: "POST",
    resource: "https://api.stripe.com/v1/payment_intents",
    body_digest: providerBodyDigest
  }
}, process.env.MANDATESHIELD_PROCESSOR_KEY)

if (
  consumed.provider_submission_permitted !== false ||
  consumed.provider_redemption_required !== true
) throw new Error("Unsafe CONSUME result")

// Customer-deployed exclusive executor: keep the dedicated PROCESSOR and
// provider credentials here, with alternate provider egress blocked.
const permit = consumed.execution_permit
const checked = await post("/api/v2/execution-permits/verify", {
  compact: permit.compact,
  expected_audience: processorAudience
})
if (checked.provider_submission_permitted !== false) {
  throw new Error("Signature verification must remain advisory")
}

const redeemed = await post("/api/v2/execution-permits/redeem", {
  compact: permit.compact,
  idempotency_key: `${attemptId}:redeem`,
  expected_request: {
    provider: checked.claims.provider,
    payee: checked.claims.payee,
    amount: checked.claims.amount,
    resource: checked.claims.resource
  }
}, process.env.MANDATESHIELD_PROVIDER_PROCESSOR_KEY)

if (
  redeemed.provider_submission_permitted !== true ||
  redeemed.status !== "CLAIMED" ||
  redeemed.idempotent_replay !== false
) throw new Error("No fresh redemption")

// The MandateShield claim is single-winner; provider delivery is not exactly-once.
const outcome = await provider.submit({
  ...providerRequest,
  idempotencyKey: redeemed.provider_idempotency_key
})

const report = await post("/api/v2/provider-submissions", {
  provider_submission_id: redeemed.provider_submission_id,
  permit_id: redeemed.permit_id,
  claim_id: redeemed.claim_id,
  payment_reference: outcome.reference,
  outcome: outcome.status,
  occurred_at: outcome.occurredAt,
  provider_observation: outcome.boundedObservation
}, process.env.MANDATESHIELD_PROVIDER_PROCESSOR_KEY)

if (
  report.terminal_transition_permitted !== true ||
  report.independent_verification !== true ||
  !["PROVIDER_API_VERIFIED", "CHAIN_FINALIZED"].includes(
    report.evidence_class
  ) ||
  report.authorization_finalized !== true ||
  !report.execution_receipt?.compact
) {
  await queueProviderReconciliation(redeemed.provider_submission_id)
  throw new Error("Provider outcome remains fail-closed")
}
const terminal = report.execution_receipt

RAW HTTP

Use the complete safe path in any language.

# provider_binding is mandatory for accounts created at or after
# 2026-07-26T12:01:24.000Z; older accounts alone retain legacy omission.
# New integrations must always send the exact binding.
#
# VERIFY key: strict ALLOW creates a RESERVED authorization.
curl --fail-with-body \
  https://mandateshield.com/api/v2/verify \
  -X POST \
  -H "content-type: application/json" \
  -H "authorization: Bearer $MANDATESHIELD_VERIFY_KEY" \
  --data @strict-verification.json

# Validate the full ALLOW invariant and state == RESERVED, then:
# PROCESSOR key: CONSUME with an exact provider_binding issues a permit.
curl --fail-with-body \
  https://mandateshield.com/api/v2/execution-authorizations \
  -X POST \
  -H "content-type: application/json" \
  -H "authorization: Bearer $MANDATESHIELD_PROCESSOR_KEY" \
  --data @consume.json

# CONSUME must return provider_submission_permitted=false and a signed permit.
# Signature-only verification never grants:
curl --fail-with-body \
  https://mandateshield.com/api/v2/execution-permits/verify \
  -X POST -H "content-type: application/json" --data @verify-permit.json

# Customer-deployed exclusive executor: redeem exact bindings with its live
# audience-bound PROCESSOR credential. Only one fresh MandateShield claim returns true.
curl --fail-with-body \
  https://mandateshield.com/api/v2/execution-permits/redeem \
  -X POST \
  -H "content-type: application/json" \
  -H "authorization: Bearer $MANDATESHIELD_PROVIDER_PROCESSOR_KEY" \
  --data @redeem-permit.json

# Use the signed provider_idempotency_key for the provider operation.
# Report the exact submission, permit, claim, reference and bounded caller hint.
curl --fail-with-body \
  https://mandateshield.com/api/v2/provider-submissions \
  -X POST \
  -H "content-type: application/json" \
  -H "authorization: Bearer $MANDATESHIELD_PROVIDER_PROCESSOR_KEY" \
  --data @provider-submission.json

# Only provider-API or finalized-chain evidence checked without trusting the caller may auto-finalize.
# PENDING, UNKNOWN and conflicting evidence remains fail-closed for reconciliation.

STRICT CRYPTOGRAPHIC PROFILE

Verify signed authority before evaluating policy.

Caller-supplied public keys prove mathematical consistency, not a trusted identity. A live reservation requires an account-pinned key, followed by a separate processor-side CONSUME transition.

const decision = await client.verifyAuthority({
  envelope: purchase,
  evidence: {
    format: "jws",
    compact: signedAuthority,
    public_key: issuerPublicJwk,
    expected_audience: challenge.audience,
    expected_nonce: challenge.nonce
  }
})

// Confirms a live RESERVED authorization. It does not submit payment.
const reservation = requireAllowed(decision)
await handReservationToTrustedGateway({
  compact: reservation.signed_receipt.compact,
  envelope: purchase,
  audience: challenge.audience
})

STANDALONE CLI

Use the same fail-closed gate in scripts and CI.

The CLI is one executable JavaScript file with no package install. It reads JSON from a file or standard input and never prints the API key.

curl --proto '=https' --tlsv1.2 -fsSLo ./mandateshield \
  https://mandateshield.com/sdk/v1.13.0/mandateshield-cli.mjs
curl --proto '=https' --tlsv1.2 -fsSLo ./SHA256SUMS \
  https://mandateshield.com/sdk/v1.13.0/SHA256SUMS
if command -v sha256sum >/dev/null 2>&1; then
  grep '  mandateshield-cli.mjs$' SHA256SUMS | \
    sed 's/mandateshield-cli.mjs/mandateshield/' | sha256sum -c -
else
  grep '  mandateshield-cli.mjs$' SHA256SUMS | \
    sed 's/mandateshield-cli.mjs/mandateshield/' | shasum -a 256 -c -
fi
chmod 0755 ./mandateshield

export MANDATESHIELD_API_KEY="$MANDATESHIELD_VERIFY_KEY"
./mandateshield challenge challenge.json
./mandateshield verify strict-verification.json

# Trusted gateway: bind the exact provider request and issue a signed permit.
MANDATESHIELD_API_KEY="$MANDATESHIELD_GATEWAY_PROCESSOR_KEY" \
  ./mandateshield transition consume.json

# Advisory inspection is anonymous and never unlocks submission.
env -u MANDATESHIELD_API_KEY \
  ./mandateshield permit-verify verify-permit.json

# Customer-deployed exclusive executor: only this fresh claim may exit 0.
MANDATESHIELD_API_KEY="$MANDATESHIELD_PROVIDER_PROCESSOR_KEY" \
  ./mandateshield permit-redeem redeem-permit.json

# Terminal execution evidence remains historical and non-executable.
env -u MANDATESHIELD_API_KEY \
  ./mandateshield execution-receipt verify-execution-receipt.json

SAFE AUTOMATION

Branch on the exit status.

VERIFY exit 0 means a consumable reservation exists; it is not a payment submission. The pinned v1.7 CLI includes permit verification, fresh online redemption and execution-receipt verification; keep its PROCESSOR key only in the customer-deployed exclusive executor. Exit 2 includes sandbox/test ALLOW, REVIEW, BLOCK, caller-supplied trust and partially authorized batches.

Download CLI client →Verify SHA-256 checksum →

REMOTE MCP

Call the discovered tool through the JavaScript client.

The server is stateless Streamable HTTP at https://mandateshield.com/api/mcp. It exposes normalize_agent_payment_protocol, check_ai_payment_authority and verify_cryptographic_payment_authority.

Current clients may use the stateless MCP 2026-07-28 discovery and call shape. The same endpoint retains initialize-based compatibility for 2025-11-25, 2025-06-18 and 2025-03-26. Both eras expose the same safety boundary: no PROCESSOR transition, permit redemption or payment execution tool.

import {
  createClient,
  decisionFromMcp,
  requireAllowed
} from "./vendor/mandateshield/mandateshield.mjs"

const client = createClient({
  apiKey: process.env.MANDATESHIELD_VERIFY_KEY
})

const result = await client.callMcpTool(
  "verify_cryptographic_payment_authority",
  { envelope: purchase, evidence }
)

const decision = decisionFromMcp(result)
const reservation = requireAllowed(decision)
await trustedGateway.enqueueProviderBoundPermitFlow(reservation)

IMPORTANT BOUNDARY

Tool discovery is not enforcement.

Giving a model the MCP tool helps it plan safely, but prompts cannot authorize money movement. MCP provides analysis or a strict verification projection; it exposes no provider-enforcement action and the model must never receive the PROCESSOR key. Only a customer-deployed exclusive executor may consume and redeem before its idempotent provider operation.

Inspect MCP server metadata →

OPENAI AGENTS SDK

Attach the remote Streamable HTTP server.

This uses the SDK's published MCPServerStreamableHttp lifecycle. It is framework connectivity, not a MandateShield-specific package.

npm install @openai/agents zod

import {
  Agent,
  MCPServerStreamableHttp,
  run
} from "@openai/agents"

const server = new MCPServerStreamableHttp({
  name: "MandateShield",
  url: "https://mandateshield.com/api/mcp",
  cacheToolsList: true,
  errorFunction: null,
  requestInit: {
    headers: {
      authorization:
        `Bearer ${process.env.MANDATESHIELD_VERIFY_KEY}`
    }
  }
})

await server.connect()
try {
  const agent = new Agent({
    name: "Checkout planner",
    instructions:
      "Use MandateShield to inspect the final purchase. Never claim that a payment executed.",
    mcpServers: [server]
  })
  const result = await run(agent, checkoutRequest)
  console.log(result.finalOutput)
} finally {
  await server.close()
}

OpenAI Agents MCP documentation ↗

VERCEL AI SDK

Convert remote MCP tools into AI SDK tools.

The official HTTP transport discovers both schemas. Close short-lived clients after the model run.

npm install ai @ai-sdk/mcp

import { createMCPClient } from "@ai-sdk/mcp"
import { generateText } from "ai"

const mcp = await createMCPClient({
  transport: {
    type: "http",
    url: "https://mandateshield.com/api/mcp",
    headers: {
      authorization:
        `Bearer ${process.env.MANDATESHIELD_VERIFY_KEY}`
    }
  }
})

try {
  const tools = await mcp.tools()
  const result = await generateText({
    model, // your configured AI SDK model
    tools,
    prompt: checkoutRequest
  })
  console.log(result.text)
} finally {
  await mcp.close()
}

AI SDK MCP documentation ↗

LANGCHAIN JAVASCRIPT

Let the model reserve; keep execution in the gateway.

There is no claimed first-party LangChain adapter here. This is a standard LangChain tool around the public JavaScript client, with the verification gate in the callback. The PROCESSOR key and provider call remain outside the model tool.

npm install langchain zod

import { createAgent, tool } from "langchain"
import * as z from "zod"
import {
  createClient,
  requireAllowed
} from "./vendor/mandateshield/mandateshield.mjs"

const client = createClient({
  apiKey: process.env.MANDATESHIELD_VERIFY_KEY
})

const reservePaymentAuthority = tool(async ({
  purchase,
  evidence,
  processorAudience
}) => {
  const decision = await client.verifyAuthority({
    envelope: purchase,
    evidence: {
      ...evidence,
      expected_audience: processorAudience
    }
  })
  const reservation = requireAllowed(decision)
  // The model receives no PROCESSOR key. A trusted gateway owns
  // CONSUME -> redeem -> provider submission -> hosted reconciliation.
  await trustedGateway.enqueueReservation({
    compact: reservation.signed_receipt.compact,
    envelope: purchase,
    audience: processorAudience
  })
  return {
    state: "RESERVED",
    expires_at: reservation.execution_authorization.expires_at
  }
}, {
  name: "reserve_payment_authority",
  description:
    "Reserve final purchase authority for a trusted payment gateway.",
  schema: z.object({
    purchase: z.record(z.string(), z.unknown()),
    evidence: z.record(z.string(), z.unknown()),
    processorAudience: z.string().url()
  })
})

const agent = createAgent({
  model, // your configured LangChain model
  tools: [reservePaymentAuthority]
})

LangChain tool documentation ↗

A2A CLIENT

Delegate one structured authority task.

Discover the public agent card, then send the purchase envelope as a structured parts.data value. The helper returns the A2A task; extract its decision artifact before enforcement.

import {
  createClient,
  decisionFromA2aTask,
  requireAllowed
} from "./vendor/mandateshield/mandateshield.mjs"

const client = createClient({
  apiKey: process.env.MANDATESHIELD_VERIFY_KEY
})

const task = await client.sendA2a({ envelope: purchase, evidence })
const decision = decisionFromA2aTask(task)
const reservation = requireAllowed(decision)
await trustedGateway.enqueueProviderBoundPermitFlow(reservation)

WIRE CONTRACT

JSON-RPC with negotiated A2A versions.

The preferred profile accepts only SendMessage with A2A-Version: 1.0. A separately parsed compatibility profile accepts only message/send when the version is 0.3 or absent, as required for legacy A2A clients. Clients may negotiate through the version header or the documented query parameter; conflicting values fail closed. Neither profile exposes streaming, processor transitions or push notifications.

Open A2A agent card →

A2A WIRE EXAMPLE

Send the exact final envelope as message data.

POST https://mandateshield.com/a2a
content-type: application/json
a2a-version: 1.0
authorization: Bearer ms_live_...

{
  "jsonrpc": "2.0",
  "id": "checkout_9f22a1",
  "method": "SendMessage",
  "params": {
    "message": {
      "role": "ROLE_USER",
      "messageId": "msg_9f22a1",
      "parts": [{ "data": { "...": "purchase envelope" } }]
    }
  }
}

OPERATING RULES

One fresh MandateShield claim; provider idempotency remains mandatory.

VERIFY reserves cumulative headroom. Provider-bound CONSUME issues a signed execution permit and deliberately returns provider_submission_permitted=false. Only online atomic redemption with exact signed bindings may return true, and only on the first non-replayed claim. That is a single-winner MandateShield state transition, not exactly-once provider delivery. The customer-deployed exclusive executor must attempt the exact provider operation with the returned signed idempotency key. Reporting the resulting submission records the caller observation as CALLER_ASSERTED, then MandateShield checks the configured Stripe PaymentIntent or x402 chain state without trusting that observation. Only exact, non-conflicting PROVIDER_API_VERIFIED or CHAIN_FINALIZED evidence may autonomously COMMIT or RELEASE with independent_verification=true. Pending, unknown and conflicting outcomes stay fail-closed for reconciliation and are never automatically retried.

The legacy independent_verification field means independent of the caller report, not an independent organization, provider attestation, certification or audit.

Direct manual COMMIT and RELEASE still accept a processor_result authenticated by the PROCESSOR key and exact audience binding. That evidence remains CALLER_ASSERTED with independent_verification=false. MandateShield claims no current provider or facilitator adoption and cannot reject a permitless operation on an alternate customer egress path.

START IN SANDBOX, ENFORCE IN LIVE

Test the policy, then create a live server-side key.

Open dashboard →