Skip to content
LogoLogo

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.