THE CURRENT NEED
Two valid artifacts do not automatically prove a valid transformation
A signed payment mandate can be valid while a later provider request contains a changed amount, payee, connected account, PaymentMethod or body. A valid Stripe result proves what Stripe processed; by itself it does not prove that this was the checkout approved in a separate authority protocol.
MandateShield preserves one canonical envelope across strict authority verification, durable budget reservation, the provider-bound permit and the Stripe form-body digest. A single-winner MandateShield claim authorizes the exclusive executor to attempt the idempotent operation. It does not guarantee exactly-once provider delivery.
SUPPORTED SCOPE
Deliberately narrower than complete AP2 or complete Stripe commerce
MandateShield checks
- One disclosed
mandate.payment.1projection - RFC 9901 holder KB-JWT and account-pinned issuer
- Exact amount, currency, payee and checkout reference
- Registered per-attempt and cumulative authority limits
- Stripe connected account and merchant-account binding
- Exact PaymentIntent form-body SHA-256 digest
- Fresh online permit claim before the executor attempts
- Configured PaymentIntent outcome without trusting the caller report
The integration still owns
- Full AP2 checkout and delegate chain validation
- AP2 issuer registry and external trust-chain decisions
- Stripe credentials, PaymentMethod and customer handling
- Stripe SPT or other credential-token lifecycle
- Fraud, sanctions, SCA, disputes, refunds and settlement
- Globally linearizable customer Gate storage
- Blocked alternate provider egress from the agent runtime
ONE SERVER-SIDE PATH
Project, verify, bind, claim, execute idempotently, reconcile
npm install \
https://mandateshield.com/packages/npm/1.13.0/mandateshield-sdk-1.13.0.tgz \
pgimport { Pool } from "pg"
import { MandateShield } from "@mandateshield/sdk"
import {
createMandateShieldGateway
} from "@mandateshield/sdk/gateway"
import {
createPostgresGatewayJournal
} from "@mandateshield/sdk/gateway/postgres"
import {
createStripePaymentIntentsAdapter,
STRIPE_PAYMENT_INTENTS_AUDIENCE
} from "@mandateshield/sdk/gateway/stripe-payment-intents"
const verifier = new MandateShield({
apiKey: process.env.MANDATESHIELD_VERIFY_KEY
})
const processor = new MandateShield({
apiKey: process.env.MANDATESHIELD_PROCESSOR_KEY
})
const database = new Pool({
connectionString: process.env.GATEWAY_DATABASE_URL,
ssl: { rejectUnauthorized: true }
})
const journal = createPostgresGatewayJournal({
database,
namespace: "ap2-stripe.production"
})
await journal.checkReadiness()
const stripeAccountId = process.env.STRIPE_CONNECTED_ACCOUNT
const merchantId = process.env.MANDATESHIELD_MERCHANT_ID
const stripe = createStripePaymentIntentsAdapter({
secretKey: process.env.STRIPE_SECRET_KEY,
stripeAccountId,
merchantId,
processorAudience: STRIPE_PAYMENT_INTENTS_AUDIENCE,
apiVersion: process.env.STRIPE_API_VERSION
})
const stripeGateway = createMandateShieldGateway({
journal,
mandateShield: processor,
provider: stripe
})
export async function executeApprovedAp2Checkout({
compactClosedPaymentProjection,
registeredMandateId,
agentId,
checkoutAttemptId,
pinnedKeyThumbprint,
trustedServerSidePaymentMethodId,
signExactClosedPaymentAuthority
}) {
// Projection only: this never authorizes payment.
const projected = await verifier.normalizePaymentProtocol({
adapter: "AP2_CLOSED_PAYMENT_SD_JWT",
source: compactClosedPaymentProjection,
context: {
mandate_id: registeredMandateId,
agent_id: agentId,
idempotency_key: checkoutAttemptId
}
})
if (
projected.assurance.enforcement_authorized !== false ||
projected.protocol !== "AP2"
) throw new Error("Unsafe protocol projection")
if (projected.envelope.merchant_id !== merchantId) {
throw new Error("Projected AP2 payee is not the configured merchant")
}
// Add the exact Stripe destination before signing. Never mutate it later.
const finalEnvelope = structuredClone({
...projected.envelope,
payee_identity: {
profile: "MANDATESHIELD_PAYEE_IDENTITY_V1",
provider: "STRIPE",
merchant_id: merchantId,
binding: {
connected_account_id: stripeAccountId,
merchant_account_id: stripeAccountId
},
verification: {
method: "STRIPE_ACCOUNT_CONFIGURATION",
verifier: "customer-stripe-gateway",
evidence_ref:
`urn:stripe:connected-account:${stripeAccountId}`
}
}
})
const challenge = await verifier.createChallenge({
mandate_id: registeredMandateId,
protocol: "AP2",
key_thumbprint: pinnedKeyThumbprint
})
if (challenge.audience !== STRIPE_PAYMENT_INTENTS_AUDIENCE) {
throw new Error("Pinned authority audience is not the Stripe profile")
}
// Customer-owned signer: issue the AP2 SD-JWT + holder KB-JWT over this
// exact finalEnvelope, challenge nonce, issuer and audience.
const signedEvidence = await signExactClosedPaymentAuthority({
envelope: finalEnvelope,
challenge
})
const reservation = await verifier.verifyAuthority({
envelope: finalEnvelope,
evidence: {
...signedEvidence,
expected_nonce: challenge.nonce,
expected_audience: challenge.audience
}
})
if (
reservation.decision !== "ALLOW" ||
reservation.mode !== "live" ||
reservation.persisted !== true ||
reservation.enforcement_authorized !== true ||
reservation.assurance?.authority_valid !== true ||
reservation.assurance?.key_trust !== "ACCOUNT_PINNED" ||
reservation.execution_authorization?.state !== "RESERVED" ||
reservation.execution_authorization?.consumable !== true ||
!reservation.signed_receipt?.receipt_id ||
!reservation.signed_receipt?.compact
) throw new Error("No consumable strict live reservation")
// CONSUME → fresh permit claim → exact Stripe POST → reconciliation.
return stripeGateway.execute({
receipt_id: reservation.signed_receipt.receipt_id,
compact: reservation.signed_receipt.compact,
expected_envelope: finalEnvelope,
expected_audience: STRIPE_PAYMENT_INTENTS_AUDIENCE,
provider_input: {
payment_method_id: trustedServerSidePaymentMethodId
}
})
}The normalization call is intentionally non-executable and always reports enforcement_authorized=false. Production authority begins only after strict verification succeeds with the registered mandate, fresh challenge, account-pinned key and the supported signed evidence. The Stripe credential remains inside the customer's exclusive executor.
FAIL-CLOSED RESULT
A timeout never recreates spendable authority
The executor uses the idempotency key bound into the fresh permit. MandateShield then retrieves the exact configured PaymentIntent through a separately restricted lookup connection and checks its account, amount, received amount, currency, PaymentMethod, capture and confirmation modes, card method, request ID, payee metadata and permit-bound request-body digest. Pending, unavailable, not-found and conflicting results remain reserved. They do not authorize a blind retry.
The legacy independent_verification response field means independent of the caller's asserted result. It is not an independent organization, Stripe attestation, certification or audit.
HONEST BOUNDARY
No AP2, Stripe or payment-network adoption is implied
This is a first-party MandateShield integration profile, not an AP2 certification, Google partnership, Stripe partnership or claim that either ecosystem requires MandateShield. It is useful only when a customer deliberately makes its credential-isolated executor require the MandateShield handoff.