# JavaScript SDK quickstart

> Install @boltpay/bolt-js and open a Bolt checkout link from your web game.

Source: https://help.boltapp.com/gaming/platforms/javascript/intro/quickstart

Install the SDK, open a payment link your backend created, and read the transaction reference the player's purchase returns.

## Prerequisites [#prerequisites]

* A web game or web app built with React, Vue, Angular, or plain JavaScript.
* A backend server that can call the Bolt Gaming API with your secret API key.
* A sandbox merchant account and API keys. Follow [Checkout quickstart](/gaming/guide/quickstart) first if you do not have them.

## 1. Install the SDK [#1-install-the-sdk]

<CodeGroup>
  <CodeBlockTabs defaultValue="npm">
    <CodeBlockTabsList>
      <CodeBlockTabsTrigger value="npm">
        npm
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="pnpm">
        pnpm
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="yarn">
        yarn
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="bun">
        bun
      </CodeBlockTabsTrigger>
    </CodeBlockTabsList>

    <CodeBlockTab value="npm">
      ```bash
      npm install @boltpay/bolt-js
      ```
    </CodeBlockTab>

    <CodeBlockTab value="pnpm">
      ```bash
      pnpm add @boltpay/bolt-js
      ```
    </CodeBlockTab>

    <CodeBlockTab value="yarn">
      ```bash
      yarn add @boltpay/bolt-js
      ```
    </CodeBlockTab>

    <CodeBlockTab value="bun">
      ```bash
      bun add @boltpay/bolt-js
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

**Expected result:** `@boltpay/bolt-js` appears in your dependencies. The package ships TypeScript definitions, so no separate types package is needed.

## 2. Create a payment link on your backend [#2-create-a-payment-link-on-your-backend]

The SDK opens a link; it does not create one. Your backend calls `POST /v1/gaming/payment_links` with your secret API key and returns the `link` value to your client. Never put the API key in browser code.

```bash title="Request"
curl --location 'https://api-sandbox.boltapp.com/v1/gaming/payment_links' \
--header 'X-API-KEY: YOUR_API_KEY' \
--header 'X-PUBLISHABLE-KEY: YOUR_PUBLISHABLE_KEY' \
--header 'Content-Type: application/json' \
--data '{
    "game_id": "YOUR_GAME_ID",
    "user_id": "USER_ID",
    "redirect_url": "yourgame://bolt-webcheckout/success",
    "item": {
        "price": 699,
        "name": "Gems Pack",
        "image_url": "https://yourcdn.example.com/gems.png",
        "currency": "USD"
    }
}'
```

The response carries the URL your client opens:

```json title="Response"
{
  "id": "CyzZV9Zh45t2rLE3ubG75x",
  "link": "https://your-store.c-sandbox.boltapp.com/o?order_token=...&payment_link_id=...&publishable_key=..."
}
```

See [Create payment link](/gaming/guide/bolt-api/create-payment-link) for every parameter.

## 3. Open checkout from your app [#3-open-checkout-from-your-app]

Initialize the SDK once when your app starts. `gameId` and `publishableKey` come from the sandbox dashboard:

```ts title="TypeScript"
import { BoltSDK } from '@boltpay/bolt-js'

await BoltSDK.initialize({
  gameId: 'YOUR_GAME_ID',
  publishableKey: 'YOUR_PUBLISHABLE_KEY',
  environment: 'sandbox',
})
```

Then pass the `link` value to `BoltSDK.gaming.openCheckout()`. It resolves with a `PaymentLinkSession` carrying the link's `paymentLinkId` and `status`.

<CodeGroup>
  <CodeBlockTabs defaultValue="React">
    <CodeBlockTabsList>
      <CodeBlockTabsTrigger value="React">
        React
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="Vue">
        Vue
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="JavaScript">
        JavaScript
      </CodeBlockTabsTrigger>
    </CodeBlockTabsList>

    <CodeBlockTab value="React">
      ```tsx
      import { BoltSDK } from '@boltpay/bolt-js'
      import { useState } from 'react'

      function CheckoutButton({ checkoutUrl }: { checkoutUrl: string }) {
        const [loading, setLoading] = useState(false)

        const handlePayment = async () => {
          setLoading(true)
          try {
            const session = await BoltSDK.gaming.openCheckout(checkoutUrl)
            console.log('Checkout session:', session?.paymentLinkId, session?.status)
          } finally {
            setLoading(false)
          }
        }

        return (
          <button onClick={handlePayment} disabled={loading}>
            {loading ? 'Processing...' : 'Pay with Bolt'}
          </button>
        )
      }
      ```
    </CodeBlockTab>

    <CodeBlockTab value="Vue">
      ```vue
      <template>
        <button @click="handlePayment" :disabled="loading">
          {{ loading ? 'Processing...' : 'Pay with Bolt' }}
        </button>
      </template>

      <script setup>
      import { ref } from 'vue'
      import { BoltSDK } from '@boltpay/bolt-js'

      const props = defineProps(['checkoutUrl'])
      const loading = ref(false)

      const handlePayment = async () => {
        loading.value = true
        try {
          const session = await BoltSDK.gaming.openCheckout(props.checkoutUrl)
          console.log('Checkout session:', session?.paymentLinkId, session?.status)
        } finally {
          loading.value = false
        }
      }
      </script>
      ```
    </CodeBlockTab>

    <CodeBlockTab value="JavaScript">
      ```js
      import { BoltSDK } from '@boltpay/bolt-js'

      async function buyItem(checkoutUrl) {
        const session = await BoltSDK.gaming.openCheckout(checkoutUrl)
        console.log('Checkout session:', session?.paymentLinkId, session?.status)

        // The purchase is confirmed by the webhook your backend received.
        // Re-read the player's entitlements from your backend rather than
        // granting them in the browser.
        await syncPlayerData()
      }

      document.getElementById('buy-button')?.addEventListener('click', async () => {
        const checkoutUrl = await fetchCheckoutUrlFromYourBackend()
        await buyItem(checkoutUrl)
      })
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

**Expected result:** Bolt checkout opens over your game. On completion the promise resolves with a transaction object.

## 4. Grant the purchase from your backend [#4-grant-the-purchase-from-your-backend]

`openCheckout()` resolves with a `PaymentLinkSession`:

```ts title="TypeScript"
import type { PaymentLinkSession } from '@boltpay/bolt-js'

interface PaymentLinkSession {
  paymentLinkId: string
  paymentLinkUrl: string
  status: 'pending' | 'successful' | 'expired' | 'abandoned'
  createdAt: Date
  updatedAt: Date
  completedAt?: Date
}
```

Treat the session as a client-side record to display or log, not as proof of payment. Bolt sends a transaction webhook to your backend, so grant items there and have the client re-read the player's state. See [Validate webhook authenticity](/gaming/guide/bolt-webhooks/validate-authenticity).

## 5. Verify the flow [#5-verify-the-flow]

1. Run your app against a sandbox payment link and complete a purchase.

   **Expected result:** The promise resolves and your console logs the payment link id and status.

2. Open **Transactions** in the [sandbox Merchant Dashboard](https://merchant-sandbox.boltapp.com/).

   **Expected result:** The transaction appears with the item and amount from your payment link.

3. Confirm your backend received the transaction webhook and granted the item.

## Show a reward ad [#show-a-reward-ad]

The SDK can also open an ad and tell you when the player claims the reward.

```tsx title="React"
import { BoltSDK } from '@boltpay/bolt-js'

function AdButton() {
  const handleAdDisplay = async () => {
    await BoltSDK.gaming.openAd({
      onClaim: () => {
        console.log('Reward claimed')
      },
    })
  }

  return <button onClick={handleAdDisplay}>Watch ad</button>
}
```

## Next steps [#next-steps]

* [Check payment link status](/gaming/guide/bolt-api/check-payment-link)
* [Consume payment link](/gaming/guide/bolt-api/consume-payment-link)
* [Check transaction status](/gaming/guide/bolt-api/check-transaction)
