# Passing Customer Metadata to Stripe

> How to include email, IP, and enhanced metadata in Stripe payments for better chargeback risk scoring.

**Category:** chargeback-prevention | **Last updated:** March 14, 2026

---

Fidro reads customer metadata from your Stripe PaymentIntent to improve chargeback risk scoring. Without metadata, Fidro analyses card, billing, AVS/CVC, and Stripe Radar data automatically. With metadata, you unlock email validation, IP intelligence, geo-mismatch detection, and behavioural checks on top.

## Metadata fields

Add these to your PaymentIntent's `metadata` object:

### Core fields (recommended)

| Key | Value | Purpose |
|-----|-------|---------|
| `customer_email` | Customer's email address | Disposable email detection, blocklist matching |
| `customer_ip` | Customer's IP address | VPN/proxy/Tor detection, geo-mismatch |

### Enhanced fields (optional)

These unlock additional fraud checks. All are optional — pass whichever ones you have available.

| Key | Value | Purpose |
|-----|-------|---------|
| `customer_account_age_minutes` | Minutes since account was created | Flags very new accounts (< 30 min) making purchases |
| `customer_order_count` | Number of previous orders | Distinguishes first-time buyers from returning customers |
| `customer_phone` | Customer's phone number | Absence of phone is a minor risk signal |
| `device_fingerprint_id` | Unique device/browser identifier | Detects same device across multiple accounts |
| `session_duration_seconds` | Seconds spent on checkout page | Flags unusually fast checkouts (< 30s, likely bots) |
| `checkout_referrer` | HTTP referrer of the checkout page | Stored for analysis |

## Where to add metadata

Metadata must be set when you **create** the PaymentIntent (or before it's confirmed). You can't add metadata after the payment succeeds.

### Stripe Checkout Sessions

```javascript
const session = await stripe.checkout.sessions.create({
  line_items: [{ price: 'price_xxx', quantity: 1 }],
  mode: 'payment',
  payment_intent_data: {
    metadata: {
      customer_email: customerEmail,
      customer_ip: customerIp,
      // Enhanced (optional)
      customer_account_age_minutes: String(accountAgeMinutes),
      customer_order_count: String(user.orderCount),
      customer_phone: user.phone || '',
      device_fingerprint_id: deviceId,
      session_duration_seconds: String(sessionDuration),
    },
  },
  success_url: 'https://example.com/success',
  cancel_url: 'https://example.com/cancel',
});
```

### Stripe Elements / Custom Payment Flow

```javascript
const paymentIntent = await stripe.paymentIntents.create({
  amount: 4999,
  currency: 'usd',
  metadata: {
    customer_email: 'jane@example.com',
    customer_ip: '203.0.113.45',
    // Enhanced (optional)
    customer_account_age_minutes: String(
      Math.floor((Date.now() - user.createdAt) / 60000)
    ),
    customer_order_count: String(user.orderCount),
    customer_phone: user.phone || '',
    device_fingerprint_id: req.body.deviceId,
    session_duration_seconds: String(req.body.sessionDuration),
  },
});
```

### Stripe Subscriptions

For recurring payments, set metadata on the subscription. Stripe copies subscription metadata to each invoice's PaymentIntent:

```javascript
const subscription = await stripe.subscriptions.create({
  customer: 'cus_xxx',
  items: [{ price: 'price_xxx' }],
  payment_settings: {
    payment_method_options: {
      card: { request_three_d_secure: 'automatic' },
    },
  },
  metadata: {
    customer_email: 'jane@example.com',
    customer_ip: '203.0.113.45',
    customer_account_age_minutes: String(accountAgeMinutes),
    customer_order_count: String(user.orderCount),
  },
});
```

> **Note:** For subscriptions, the IP and session data may change over time. Consider updating the subscription metadata when the customer logs in or updates their payment method.

### Laravel Cashier

```php
// One-time charge
$user->charge(4999, $paymentMethod, [
    'metadata' => [
        'customer_email' => $user->email,
        'customer_ip' => request()->ip(),
        // Enhanced (optional)
        'customer_account_age_minutes' => (string) $user->created_at->diffInMinutes(now()),
        'customer_order_count' => (string) $user->orders()->count(),
        'customer_phone' => $user->phone ?? '',
        'device_fingerprint_id' => request()->input('device_id', ''),
        'session_duration_seconds' => request()->input('session_duration', ''),
    ],
]);

// Subscription
$user->newSubscription('default', 'price_xxx')
    ->withMetadata([
        'customer_email' => $user->email,
        'customer_ip' => request()->ip(),
        'customer_account_age_minutes' => (string) $user->created_at->diffInMinutes(now()),
        'customer_order_count' => (string) $user->orders()->count(),
    ])
    ->create($paymentMethod);
```

## What Fidro analyses automatically (no metadata needed)

Even without any metadata, Fidro extracts and analyses these signals directly from the Stripe charge object:

- **Card funding type** — Prepaid/virtual cards flagged (2–4x higher chargeback rate)
- **AVS results** — Address and postal code verification from the card network
- **CVC check** — Card security code validation result
- **Stripe Radar risk level** — Stripe's own fraud assessment (normal/elevated/highest)
- **Card country** — Issuing country of the card
- **Billing country** — Country from billing address
- **Amount and currency** — High-value transaction detection
- **Transaction velocity** — Repeat charge patterns (requires email or IP metadata)

Adding email and IP metadata typically improves risk score accuracy by 30–40%, because it enables the full suite of email and network checks. Adding enhanced metadata (account age, order count, device fingerprint) can improve accuracy by an additional 15–20%.

## Verifying metadata is being sent

After a test payment, check the [Transactions page](/app/transactions) in your Fidro dashboard. The transaction detail view shows:
- **Customer Email** — should show the email you passed
- **Customer IP** — should show the IP you passed
- **Account Age** — should show minutes since account creation
- **Device ID** — should show the fingerprint you passed

If these show "—", the metadata isn't being included in the PaymentIntent.

> **Important:** Stripe metadata values must be strings. Convert numbers with `String()` (JavaScript) or `(string)` (PHP) before passing them.