> ## Documentation Index
> Fetch the complete documentation index at: https://docs.paynext.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Integrate PayNext SDK to accept payments with minimal code.

PayNext SDK automatically supports all payment methods and 3D Secure authentication configured in your dashboard, including cards, Apple Pay, Google Pay, PayPal, and more.

## Prerequisites

* Create a one-time or subscription plan in **Dashboard → Plans**
* Enable desired payment methods in **Dashboard → Checkout**
* Configure workflows for each enabled payment method in **Dashboard → Workflows**
* **PayNext API Key**: Available in **Dashboard → Developers → API Keys**

<Warning>
  Never expose your API key in client-side code. Always create client sessions on your server.
</Warning>

## How It Works

|                 |                                                                                 |
| :-------------- | :------------------------------------------------------------------------------ |
| **Server-side** | Create a session using the PayNext API. Pass the session `id` to your frontend. |
| **Client-side** | Mount the SDK checkout using the session `id`.                                  |

## Integration Steps

<Steps>
  <Step title="Create Session">
    Call the PayNext API from your server. See the [API Reference](/api-reference/v2.0.0/client-session/create-a-client-session) for details.

    **POST** `/client-session`

    ```json Example Request theme={"system"}
    {
      "customer": {
        "email": "jane.doe@example.com",
        "external_id": "cust_123",
        "address": { "country": "US" }
      },
      "plan": {
        "id": "plan_7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d"
      }
    }
    ```

    ```json Example Response theme={"system"}
    {
      "id": "cs_d3b07384-d9a5-4d16-a5b1-3fa3d9b0b123",
      "expiry_date": "2025-08-12T16:14:08Z",
      ...
    }
    ```

    Use the `id` from the response as your `clientToken` in the frontend.

    <Warning>
      Note the `expiry_date` in the response — sessions expire after this time. If your session expires, create a new one before mounting checkout. For more details, see [Handle Expired Sessions](/sdk-reference/use-cases/handle-expired-sessions).
    </Warning>
  </Step>

  <Step title="Install SDK">
    <CodeGroup>
      ```bash npm theme={"system"}
      npm install @paynext/sdk
      ```

      ```bash yarn theme={"system"}
      yarn add @paynext/sdk
      ```

      ```bash pnpm theme={"system"}
      pnpm add @paynext/sdk
      ```
    </CodeGroup>
  </Step>

  <Step title="Preload SDK (Optional)">
    The SDK uses a CDN-based architecture with a small initial bundle. You can optionally preload the SDK when you anticipate checkout usage (e.g., on pricing pages):

    ```tsx theme={"system"}
    import { PayNextSDK } from '@paynext/sdk'

    useEffect(() => {
      if (typeof window !== 'undefined') {
        PayNextSDK.preload('production').catch(console.error)
      }
    }, [])
    ```

    <Tip>
      Preloading is recommended as this will speed up how fast payment buttons will load. Without it, the SDK loads on-demand when you call `mount`.
    </Tip>
  </Step>

  <Step title="Configure Return URL">
    Required for redirect-based payment methods (Cash App, Venmo, etc.). Without it, customers cannot complete checkout.

    * Point to a page where the checkout is rendered
    * Optionally, use a URL query parameter (e.g., `?scrollTo=paynext-checkout`) to scroll users back to checkout if it's not at the top of the page

    ```typescript theme={"system"}
    returnUrl: 'https://your-site.com/checkout?scrollTo=paynext-checkout'
    ```

    <Warning>
      **Avoid using hash fragments** (e.g., `#paynext-checkout`) in your `returnUrl` — they are not supported by all alternative payment methods (APM). Use query parameters instead (e.g., `?scrollTo=paynext-checkout`).
    </Warning>
  </Step>

  <Step title="Mount Checkout">
    Initialize the SDK with your `clientToken` and mount the checkout form.

    <CodeGroup>
      ```tsx Next.js (Client Component) theme={"system"}
      'use client'

      import { useEffect, useState } from 'react'
      import {
        PayNextCheckout,
        type PaymentResult,
        type AttemptResult,
        type LoadedResult,
        type CheckoutError,
      } from '@paynext/sdk'
      import '@paynext/sdk/styles'

      const CheckoutForm: React.FC = () => {
        const [clientToken, setClientToken] = useState('')

        useEffect(() => {
          let checkout: PayNextCheckout | undefined

          const mountCheckout = async (token: string) => {
            if (!token) return

            checkout = new PayNextCheckout()

            await checkout.mount('paynext-checkout', {
              clientToken: token, // The id from the client session response
              environment: 'sandbox', // 'sandbox' or 'production'
              apiVersion: '1.0.0', // PayNext API version
              returnUrl: 'https://your-site.com/checkout?scrollTo=paynext-checkout', // Your checkout page where user returns after redirect
              locale: 'en',
              onCheckoutLoaded: (result: LoadedResult) => {
                if (!result.success) {
                  console.error('Checkout loading failed:', result.error?.status_reason?.message)
                  return
                }
                console.info('Checkout loaded successfully')
              },
              onCheckoutAttempt: ({ paymentMethod, cardType }: AttemptResult) => {
                console.info('Payment attempt:', paymentMethod, cardType || '')
              },
              onCheckoutComplete: (result: PaymentResult) => {
                console.log('Payment completed', result)
                window.location.href = '/payment-success'
              },
              onCheckoutFail: (error: CheckoutError) => {
                console.error('Payment failed:', error.status, error.status_reason?.message)
              },
            })
          }

          if (!clientToken) {
            fetch('/api/client-session', { method: 'POST', body: JSON.stringify(payload) })
              .then((r) => r.json())
              .then((data) => setClientToken(data.id))
              .catch(console.error)
          } else {
            mountCheckout(clientToken)
          }

          return () => {
            checkout?.unmount()
          }
        }, [clientToken])

        return <div id='paynext-checkout' />
      }

      export default CheckoutForm
      ```

      ```typescript Vanilla TypeScript theme={"system"}
      import {
        PayNextCheckout,
        type PaymentResult,
        type AttemptResult,
        type LoadedResult,
        type CheckoutError,
      } from '@paynext/sdk'
      import '@paynext/sdk/styles'

      async function init() {
        const res = await fetch('/api/client-session', { method: 'POST', body: JSON.stringify(payload) })
        const { id: clientToken } = await res.json()

        const checkout = new PayNextCheckout()

        await checkout.mount('paynext-checkout', {
          clientToken, // The id from the client session response
          environment: 'sandbox', // 'sandbox' or 'production'
          apiVersion: '1.0.0', // PayNext API version
          returnUrl: 'https://your-site.com/checkout?scrollTo=paynext-checkout', // Your checkout page where user returns after redirect
          locale: 'en',
          onCheckoutLoaded: (result: LoadedResult) => {
            if (!result.success) {
              console.error('Checkout loading failed:', result.error?.status_reason?.message)
              return
            }
            console.info('Checkout loaded successfully')
          },
          onCheckoutAttempt: ({ paymentMethod, cardType }: AttemptResult) => {
            console.info('Payment attempt', paymentMethod, cardType || '')
          },
          onCheckoutComplete: (result: PaymentResult) => {
            console.info('Success', result)
          },
          onCheckoutFail: (error: CheckoutError) => {
            console.error('Payment failed:', error.status, error.status_reason?.message)
          },
        })
      }

      init()
      ```
    </CodeGroup>
  </Step>

  <Step title="Test">
    Use the sandbox environment and test payment details available for your payment method and processor to validate your setup.

    <Tip>
      Track test payments in **Dashboard → Payments**. For Apple Pay and Google Pay, ensure your browser and device meet eligibility requirements.
    </Tip>
  </Step>

  <Step title="Go Live">
    1. Change `environment` to `'production'` in your SDK config
    2. Use production API keys on your backend
    3. Test with real payment methods before launch
    4. Set up [webhooks](/webhooks/introduction/getting-started) for payment confirmations
  </Step>
</Steps>

<Warning>
  `onCheckoutComplete` is a client-side UX signal, not a settlement confirmation — and it is not guaranteed to run. It fires in the customer's browser, so a closed or backgrounded tab or a lost connection can prevent it, on any payment method (seen on PayPal and Apple Pay); for asynchronous methods such as [Pix](/integrations/payment-methods/pix-automatico) the payment can also still be settling when it fires. Grant access and fulfill orders from [payment webhooks](/webhooks/introduction/getting-started) — the source of truth for the final payment status.
</Warning>
