Integrations
Every integration follows the same pattern: call Guard before you call the gateway. If the verdict is disposable or invalid, block the checkout.
Stripe
Section titled “Stripe”import express from 'express';import Stripe from 'stripe';import { AyzalGuard } from '@ayzalai/risk-guard';
const app = express();app.use(express.json());const guard = new AyzalGuard({ apiKey: process.env.AYZAL_GUARD_KEY });const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
app.post('/checkout', async (req, res) => { const { email } = req.body; const clientIp = (req.headers['x-forwarded-for'] || '').split(',')[0] || req.ip;
const risk = await guard.check(email, { clientIp }); if (risk.verdict === 'disposable' || risk.verdict === 'invalid') { return res.status(400).json({ error: 'Please use a real email address' }); }
const session = await stripe.checkout.sessions.create({ mode: 'subscription', customer_email: email, line_items: [{ price: 'price_xxx', quantity: 1 }], success_url: 'https://yourapp.com/success', cancel_url: 'https://yourapp.com/cancel', }); res.json({ url: session.url });});PayPal
Section titled “PayPal”Call Guard before paypal.orders.create(). Same pattern as Stripe.
import os, requestsfrom paypalcheckoutsdk.core import PayPalHttpClient, SandboxEnvironmentfrom paypalcheckoutsdk.orders import OrdersCreateRequest
def create_order(email: str, client_ip: str): risk = requests.post( "https://email.ayzalai.com/v1/check/email", headers={"X-API-Key": os.environ["AYZAL_GUARD_KEY"]}, json={"email": email, "client_ip": client_ip}, timeout=5, ).json()
if risk["verdict"] in ("disposable", "invalid"): raise ValueError("Please use a real email address")
env = SandboxEnvironment( client_id=os.environ["PAYPAL_CLIENT_ID"], client_secret=os.environ["PAYPAL_SECRET"], ) client = PayPalHttpClient(env) req = OrdersCreateRequest() req.prefer("return=representation") req.request_body({ "intent": "CAPTURE", "purchase_units": [{ "amount": {"currency_code": "USD", "value": "49.00"} }], }) return client.execute(req).resultCall Guard before POST /v1/payments or POST /v1/sessions.
Custom gateway
Section titled “Custom gateway”Any gateway — Braintree, Square, Chargebee, custom auth. Same pattern:
def check_before_payment(email, client_ip): r = requests.post( "https://email.ayzalai.com/v1/check/email", headers={"X-API-Key": os.environ["AYZAL_GUARD_KEY"]}, json={"email": email, "client_ip": client_ip}, timeout=5, ) if r.status_code != 200: return {"verdict": "unknown", "allowed": True} result = r.json() return { "verdict": result["verdict"], "allowed": result["verdict"] not in ("disposable", "invalid"), }Getting the client IP correctly
Section titled “Getting the client IP correctly”| Framework | How to read |
|---|---|
| Express | (req.headers[‘x-forwarded-for’] or ‘’).split(‘,’)[0].trim() or req.socket.remoteAddress |
| Flask | request.headers.get(‘X-Forwarded-For’, ‘’).split(‘,’)[0].strip() or request.remote_addr |
| FastAPI | request.headers.get(‘x-forwarded-for’, ‘’).split(‘,’)[0].strip() or request.client.host |
| PHP | $_SERVER[‘HTTP_X_FORWARDED_FOR’] or $_SERVER[‘REMOTE_ADDR’] |
| Rails | request.headers[‘X-Forwarded-For’].to_s.split(‘,’).first or request.remote_ip |
If you send a private IP (10.x, 172.16-31.x, 192.168.x, 127.0.0.1), Guard skips IP lookups and returns ip_risk: null. You lose the IP reputation signal.
Fail-open policy
Section titled “Fail-open policy”If Guard returns 5xx, 429, or times out: let the payment through. Log the failure, flag the order for manual review. See /guard/errors for the full policy.
