Integrate an existing facilitator
Developer Preview
Keep your existing x402 verifier and wrap it with the package's root export:
// [!include ../../../../examples/gateway-facilitator/verify.mjs:gateway-wrap]withGuardian(theirVerify, config) first calls theirVerify. If that result is
invalid, it returns the base result without contacting Guardian. If it is valid,
the wrapper runs the common verifyPayment primitive and returns valid only for
an approved Guardian result.
The complete placeholder pattern is in
examples/gateway-facilitator/verify.mjs.
It does not contact any service when imported.
Common primitive
Use verifyPayment directly when you need the normalized result before adapting
it to your facilitator response:
import { verifyPayment } from '@navalabs/x402-guardian';
const result = await verifyPayment(
{ paymentPayload, paymentRequirements },
guardianConfig,
{ intervalMs: 1_000, maxAttempts: 20 },
);
const outcome = result.verdict?.outcome;
if (outcome === 'approved') {
// Continue to your existing settlement path.
} else if (outcome === 'rejected') {
return {
isValid: false,
invalidReason: result.verdict.humanReason,
reasonCode: result.verdict.reasonCode,
};
} else {
// Missing verdict, timeout, or error: fail closed.
return { isValid: false, invalidReason: result.reason ?? 'Guardian unavailable' };
}outcome is authoritative. Pass reasonCode through as an opaque string; do not
approve or reject using a locally maintained reason-code list. This keeps an
integration fail-closed while preserving new diagnostic codes.
Key and prompt handling
Guardian is payer-scoped. verifyPayment reads
paymentPayload.navaApiKey first and falls back to GuardianConfig.apiKey.
Both are sensitive bearer credentials. Redact them before logging payloads or
errors, never return them in responses, and do not persist them with payment
records.
The payer key currently rides in the unsigned x402 envelope. That channel does not authenticate the key to the signed payer and is an explicit preview limitation. A capable intermediary could observe/replay it or rewrite it to force fallback. Authenticated Guardian-key binding remains unresolved.
Leave allowPromptOverride unset or false. The default prompt is derived from
the signed payment action. The payer-supplied arbiterUserPrompt is descriptive
only and should not be trusted across this unsigned channel.
Settlement boundary
verifyPayment and withGuardian never settle. After an approved outcome, your
facilitator remains responsible for its normal exact-payment and one-time
settlement controls. A timeout, malformed response, transport failure, or
rejected outcome must not reach settlement.