# Payment Lifecycle

This page describes the complete flow from session creation to payment confirmation.

## Flow overview

```
Your Server                    ZevPay API                  Customer
    │                              │                          │
    │  POST /initialize            │                          │
    │─────────────────────────────▶│                          │
    │  { session_id, checkout_url }│                          │
    │◀─────────────────────────────│                          │
    │                              │                          │
    │  Return checkout_url or      │                          │
    │  pass public key to SDK      │                          │
    │─────────────────────────────────────────────────────────▶│
    │                              │                          │
    │                              │  POST /payment-method    │
    │                              │◀─────────────────────────│
    │                              │  { account_number, ... } │
    │                              │─────────────────────────▶│
    │                              │                          │
    │                              │      Customer pays       │
    │                              │◀─────────────────────────│
    │                              │                          │
    │  Webhook: charge.success     │                          │
    │◀─────────────────────────────│                          │
    │                              │                          │
    │  GET /verify (optional)      │                          │
    │─────────────────────────────▶│                          │
    │  { status: "completed" }     │                          │
    │◀─────────────────────────────│                          │
```

## Step-by-step

### 1. Initialize session

Your server calls `POST /v1/checkout/session/initialize` with your **secret key**, the amount, and customer email.

### 2. Customer selects payment method

The checkout UI (inline modal or standard page) presents the available payment methods. When the customer selects one, the SDK calls `POST /v1/checkout/session/:id/payment-method`.

For **bank transfer**, this returns a virtual account number. For **PayID**, this returns a dynamic PayID.

### 3. Customer completes payment

The customer transfers money (via bank or ZevPay app). ZevPay detects the transfer automatically.

### 4. Payment confirmed

ZevPay:
- Marks the session as `completed`
- Sends a `charge.success` webhook to your server
- The checkout UI detects the completion via polling and shows a success screen

### 5. You verify and fulfill

Your server verifies the payment via the webhook or the `/verify` endpoint, then fulfills the order.

## Polling

Both the inline and standard checkout SDKs poll the `/verify` endpoint every 5 seconds after the customer selects a payment method. When the status changes to `completed`, the success screen is shown automatically.

## Idempotency

- Each session can only be completed once
- Duplicate bank transfers to the same virtual account are rejected
- The `reference` parameter on initialization helps you prevent duplicate sessions

## Error handling

| Scenario | What happens |
|----------|-------------|
| Session expires (30 min) | Status set to `expired`, customer shown expiry screen |
| Transfer amount mismatch | Transfer may not be matched to the session |
| Network error during polling | SDK retries silently on next poll interval |
| Webhook delivery fails | Logged in dashboard, you should poll `/verify` as backup |
