# InflowPay SDK v2

Accept card payments with a secure, iframe-based payment form. This version delivers **enhanced security** and **automatic 3D Secure handling** - all with just a few lines of code.

## What's Best in This Version

- 🔒 **Iframe Architecture**: Card data never touches your server (PCI compliant)
- ✨ **Built-in Success UI**: Beautiful success screen automatically shown after payment - fully customizable or replaceable
- 🎯 **Auto 3D Secure**: SDK handles authentication modals automatically
- 🚀 **Zero Configuration**: Works out of the box with sensible defaults
- 🎨 **Fully Customizable**: Match your brand with comprehensive styling options

## Installation

```bash
npm install @inflow_pay/sdk
```

**CDN Option** (vanilla HTML pages only):

```html
<script src="https://cdn.jsdelivr.net/npm/@inflow_pay/sdk@1.1.0/dist/sdk.umd.js"></script>
```

## Complete Example

### Backend: Create Payment

```javascript
// backend/api/create-payment.js
app.post("/api/create-payment", async (req, res) => {
  const response = await fetch("https://api.inflowpay.xyz/api/server/payment", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-Inflow-Api-Key": process.env.INFLOW_PRIVATE_KEY,
    },
    body: JSON.stringify({
      products: [{ name: "Product", price: 4999, quantity: 1 }],
      currency: "EUR",
      customerEmail: "customer@example.com",
      firstName: "John",
      lastName: "Doe",
      billingCountry: "FR",
      postalCode: "75001",
    }),
  });

  const data = await response.json();
  res.json({ paymentId: data.payment.id });
});
```

### Frontend: React

```tsx
import {
  InflowPayProvider,
  CardElement,
  PaymentResultStatus,
} from "@inflow_pay/sdk/react";

export default function CheckoutPage() {
  const [paymentId, setPaymentId] = useState<string | null>(null);

  useEffect(() => {
    fetch("/api/create-payment", { method: "POST" })
      .then((res) => res.json())
      .then((data) => setPaymentId(data.paymentId));
  }, []);

  if (!paymentId) return <div>Loading...</div>;

  return (
    <InflowPayProvider config={{ publicKey: "inflow_pub_xxx" }}>
      <CardElement
        paymentId={paymentId}
        onComplete={(result) => {
          if (result.status === PaymentResultStatus.SUCCESS) {
            setTimeout(() => (window.location.href = "/confirmation"), 2000);
          }
        }}
        style={{
          fontFamily: "Inter",
          button: { backgroundColor: "#0070F3", textColor: "#FFFFFF" },
        }}
      />
    </InflowPayProvider>
  );
}
```

### Frontend: Vanilla JavaScript

```html
<div id="card-container"></div>

<script src="https://cdn.jsdelivr.net/npm/@inflow_pay/sdk@1.1.0/dist/sdk.umd.js"></script>
<script>
  const provider = new InflowPaySDK.InflowPayProvider({
    config: { publicKey: "inflow_pub_xxx" },
  });

  fetch("/api/create-payment", { method: "POST" })
    .then((res) => res.json())
    .then((data) => {
      const cardElement = provider.createCardElement({
        paymentId: data.paymentId,
        container: "#card-container",
        onComplete: (result) => {
          if (result.status === InflowPaySDK.PaymentResultStatus.SUCCESS) {
            setTimeout(() => (window.location.href = "/confirmation"), 2000);
          }
        },
      });
      cardElement.mount();
    });
</script>
```

## Built-in Success UI Explained

The SDK includes a polished success screen that appears automatically after successful payment:

**What it shows:**

- ✅ Success icon and "Payment successful!" message
- 💳 Payment amount (when available from your payment data)

**Default vs custom:**

- **Default UI** (default): Built-in success screen shows automatically. You don't need to do anything — quick integration, looks great out of the box.
- **Custom UI:** Set `showDefaultSuccessUI: false` and add your own success UI. Manage the logic in `onComplete`. Full control for custom branding or additional information. Examples below:

_Vanilla JS:_

```javascript
const cardElement = provider.createCardElement({
  paymentId: "pay_xxx",
  container: "#card-container",
  showDefaultSuccessUI: false,
  onComplete: (result) => {
    if (result.status === PaymentResultStatus.SUCCESS) {
      document.getElementById("card-container").innerHTML = `
        <div class="custom-success">
          <h2>Thank you for your purchase!</h2>
          <p>Order ID: ${result.paymentId}</p>
        </div>
      `;
    }
  },
});
```

_React:_

```tsx
const [result, setResult] = useState<PaymentResult | null>(null);

return (
  <>
    {result ? (
      <div className="custom-success">
        <h2>Thank you for your purchase!</h2>
        <p>Your payment was successful.</p>
      </div>
    ) : (
      <InflowPayProvider config={{ publicKey: "inflow_pub_xxx" }}>
        <CardElement
          paymentId="pay_xxx"
          showDefaultSuccessUI={false}
          onComplete={(res) => {
            if (res.status === PaymentResultStatus.SUCCESS) {
              setResult(res);
            }
          }}
        />
      </InflowPayProvider>
    )}
  </>
);
```

## Payment Flow

1. Backend creates payment → returns `paymentId`
2. Frontend initializes SDK with `paymentId` and public key
3. User enters card details in secure iframe
4. SDK tokenizes card and processes payment
5. 3D Secure authentication (if required) - automatic modal
6. `onComplete` callback fires → redirect or update UI

## API Reference

### InflowPayProvider

```javascript
const provider = new InflowPayProvider({
  config: {
    publicKey: "inflow_pub_xxx", // Required
    locale: "en", // Optional - defaults to browser language
  },
});
```

**Supported locales:** `en`, `de`, `es`, `fr`, `it`, `nl`, `pl`, `pt`

### CardElement

```javascript
const cardElement = provider.createCardElement({
  paymentId: "pay_xxx", // Required - from your backend
  container: "#card-container", // Required - CSS selector or HTMLElement

  // Callbacks
  onComplete: (result) => {
    if (result.status === PaymentResultStatus.SUCCESS) {
      // Payment successful
    } else if (result.status === PaymentResultStatus.FAILED) {
      // Payment failed - result.error contains details
    }
  },

  onReady: () => {
    // Card element mounted and ready
  },

  onChange: (state) => {
    // state.complete - whether form is valid
  },

  onError: (error) => {
    // SDK-level errors
  },

  // Styling (optional)
  style: {
    fontFamily: "Inter",
    button: {
      backgroundColor: "#0070F3",
      textColor: "#FFFFFF",
    },
  },

  // Custom text (optional)
  buttonText: "Pay Now",
  placeholders: {
    cardNumber: "1234 5678 9012 3456",
    expiry: "MM/YY",
    cvc: "CVC",
  },
});

cardElement.mount();
```

### Payment Result

```typescript
interface PaymentResult {
  status: "SUCCESS" | "FAILED";
  paymentId: string;
  error?: {
    code: string; // Error code (e.g., 'THREE_DS_FAILED')
    message: string; // User-friendly message
    retryable: boolean; // Can retry?
  };
}
```

### CardElement Methods

```javascript
cardElement.mount(); // Mount to DOM
cardElement.destroy(); // Cleanup and unmount
```

## Styling

Customize the payment form to match your brand:

```javascript
style: {
  fontFamily: 'Inter',  // 'DM Sans' | 'Inter' | 'Poppins' | 'Nunito' | etc.
  fillParent: true,

  // Input container
  inputContainer: {
    backgroundColor: '#F5F5F5',
    borderRadius: '8px',
    borderEnabled: true,
    borderColor: '#E0E0E0'
  },

  // Input fields
  input: {
    textColor: '#1A1A1A',
    placeholderColor: '#999999',
    backgroundColor: 'transparent'
  },

  // Button
  button: {
    backgroundColor: '#0070F3',
    textColor: '#FFFFFF',
    borderRadius: '8px',
    fontSize: '16px',
    fontWeight: 600,
    hover: {
      backgroundColor: '#0051CC'
    },
    disabled: {
      opacity: 0.5
    }
  },

  // Success screen (shown by default; customize with successUI)
  successUI: {
    backgroundColor: '#F5F5F5',
    primaryTextColor: '#1A1A1A',   // title and amount
    secondaryTextColor: '#999999'   // subtitle
  },

  // Dark mode
  dark: {
    inputContainer: {
      backgroundColor: '#1A1A1A',
      borderColor: '#333333'
    },
    input: {
      textColor: '#FFFFFF',
      placeholderColor: '#959499'
    },
    button: {
      backgroundColor: '#0066CC'
    },
    successUI: {
      backgroundColor: '#1A1A1A',
      primaryTextColor: '#FFFFFF',
      secondaryTextColor: '#959499'
    }
  }
}
```

**Available style properties:** `inputContainer`, `input`, `button`, `successUI`, `generalError`, `disclaimerColor`, `fieldErrorColor`, `dark` (for dark mode overrides)

See full TypeScript types in the package for all styling options.

## Error Handling

```javascript
import { PaymentResultStatus, PaymentResultErrorCode } from "@inflow_pay/sdk";

onComplete: (result) => {
  if (result.status === PaymentResultStatus.FAILED && result.error) {
    console.log(result.error.code); // e.g., 'THREE_DS_FAILED'
    console.log(result.error.message); // User-friendly message
    console.log(result.error.retryable); // Can user retry?
  }
};
```

**Common error codes:** `THREE_DS_FAILED`, `PAYMENT_PROCESSING_ERROR`

## 3D Secure

3DS is handled automatically by the SDK. When required, a modal opens for bank authentication, then closes automatically. No setup needed.

## Migration from React SDK

**For React apps:** Import from `@inflow_pay/sdk/react` instead. The component API is similar, but the styling structure has changed (see [Styling](#styling) section).

**For non-React apps:** Use the vanilla JavaScript API shown in the examples above.

## TypeScript

Full type definitions included:

```typescript
import { InflowPayProvider, PaymentResultStatus } from "@inflow_pay/sdk";
import type { PaymentResult, PaymentError } from "@inflow_pay/sdk";

const provider = new InflowPayProvider({
  config: { publicKey: "inflow_pub_xxx" },
});
```

## Features

- ✅ Dynamic height adjustment
- ✅ Skeleton loader with shimmer effect
- ✅ Dark mode support
- ✅ Responsive design
- ✅ WCAG compliant
- ✅ Multi-language support

## Support

- **Docs:** https://docs.inflowpay.com/v0/reference/createpayment
- **Email:** support@inflowpay.com
- **GitHub:** https://github.com/inflowpay/sdk
- **Changelog:** [CHANGELOG.md](./CHANGELOG.md)

## License

MIT - See [LICENSE](./LICENSE)
