Skip to main content
Closed Beta Accept Apple Pay and Google Pay in your web application with just a few lines of code. RinneJS is fully typed, PCI compliant, and handles all the complexity of wallet payments for you.

Zero PCI Scope

Card data is tokenized client-side. Your servers never touch sensitive data.

Simple Integration

Initialize the SDK, create a transaction, and mount payment buttons with minimal setup.

Native UX

Real Apple Pay and Google Pay buttons with native wallet experience.

Live Demo

Explore the SDK in action. Switch between code tabs to see initialization, transaction creation, and event handlers and button mounting—then try the live payment buttons:
checkout.tsx
// Initialize RinneJS
import { Rinne } from '@rinnebr/js'

const rinne = new Rinne({
  merchantId: 'your-merchant-id',
  environment: 'sandbox'
})
This demo runs in sandbox mode—no real charges will occur. RinneJS currently supports 3DS-authenticated transactions only, ensuring the highest level of payment security. See browser support for compatibility details.

Installation

npm install @rinnebr/js

Quick start

Get Apple Pay and Google Pay running in under 5 minutes:
1

Initialize RinneJS

Import and configure RinneJS with your merchant credentials:
import { Rinne } from '@rinnebr/js'

const rinne = new Rinne({
  merchantId: 'your-merchant-id',
  environment: 'sandbox' // or 'production'
})
2

Create a transaction

Define the payment amount and details. Currency defaults to 'BRL' and country defaults to 'BR':
const transaction = await rinne.transaction.create({
  amount: 2500, // Amount in cents (R$ 25.00)
  lineItems: [
    { label: 'Premium Plan', amount: 2000 },
    { label: 'Tax', amount: 500 }
  ]
})
3

Mount payment buttons

Create and display the wallet payment buttons:
const applePay = await rinne.elements.applePay(transaction, {
  button: { color: 'black', type: 'buy' },
  onCapture: async (payload, fail) => {
    try {
      await processPayment(payload.card_data)
    } catch (error) {
      fail({ message: 'Payment failed' })
    }
  }
})

await applePay.mount('#apple-pay-button')

Usage examples

import { Rinne } from '@rinnebr/js'

const rinne = new Rinne({
  merchantId: 'your-merchant-id',
  environment: 'sandbox'
})

const transaction = await rinne.transaction.create({
  amount: 1999,
  currency: 'BRL',
  lineItems: [{ label: 'Demo Product', amount: 1999 }]
})

const applePay = await rinne.elements.applePay(transaction, {
  button: { color: 'black', type: 'buy', locale: 'en' },
  onCapture: async (payload, fail) => {
    try {
      await processPayment(payload.card_data)
    } catch (error) {
      fail({ message: error.message })
    }
  },
  onCancel: () => console.log('Cancelled')
})

await applePay.mount('#apple-pay-button')

API reference

Rinne class

The main entry point for the SDK.
const rinne = new Rinne(options: Options)
merchantId
string
required
Merchant ID from the merchant owner of the transaction
environment
'sandbox' | 'production'
default:"production"
Environment to use for API calls
rinneUrl
string
Custom API base URL (for advanced use cases)

Transaction

Create a transaction before mounting payment elements.
const transaction = await rinne.transaction.create(params)
amount
number
required
Payment amount in cents (e.g., 1000 = $10.00)
currency
string
default:"BRL"
ISO 4217 currency code (e.g., 'BRL', 'USD')
country
string
default:"BR"
ISO 3166 country code (e.g., 'BR', 'US')
lineItems
array
Itemized breakdown displayed in wallet UI
lineItems: [
  { label: 'Product', amount: 800 },
  { label: 'Shipping', amount: 200 }
]

Payment elements

Apple Pay

const applePay = await rinne.elements.applePay(transaction, options)
await applePay.mount('#container')

Google Pay

const googlePay = await rinne.elements.googlePay(transaction, options)
await googlePay.mount('#container')

Mount options

Both applePay() and googlePay() accept the same options:
button
object
onCapture
function
Called when payment is authorized. You must call fail() if processing fails.
onCapture: async (payload, fail) => {
  try {
    await processPayment(payload.card_data)
  } catch (error) {
    fail({ message: error.message })
  }
}
onError
function
Called when an error occurs (wallet unavailable, config error, etc.)
onError: (error) => {
  console.error(error.code, error.message)
}
onCancel
function
Called when user closes the wallet dialog without paying
onCancel: () => {
  console.log('Payment cancelled')
}

Button customization

Black button

button: {
  color: 'black',
  type: 'buy',
  locale: 'en'
}

White button

button: {
  color: 'white',
  type: 'checkout',
  locale: 'pt'
}

Custom size

button: {
  size: {
    width: '300px',
    height: '56px'
  },
  borderRadius: 12
}

Subscribe button

button: {
  type: 'subscribe',
  color: 'black',
  locale: 'en'
}

Button types

TypeApple PayGoogle Pay
plainPayPay
buyBuy with Apple PayBuy with Google Pay
bookBook with Apple PayBook with Google Pay
checkoutCheck out with Apple PayCheck out with Google Pay
donateDonate with Apple PayDonate with Google Pay
orderOrder with Apple PayOrder with Google Pay
payPay with Apple PayPay with Google Pay
subscribeSubscribe with Apple PaySubscribe with Google Pay

Handling payments

The onCapture callback

Critical: Always call fail() if your backend processing fails. This notifies the wallet dialog to show an error state and allows the user to retry.
onCapture: async (payload, fail) => {
  try {
    // payload contains card_data, payment_method, and transaction
    const response = await fetch('/api/process-payment', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        cardData: payload.card_data,
        paymentMethod: payload.payment_method,
        transactionId: payload.transaction.id
      })
    })

    if (!response.ok) {
      throw new Error('Payment processing failed')
    }

    // Success! Wallet dialog closes automatically
    window.location.href = '/order-confirmation'

  } catch (error) {
    // MUST call fail() to notify the wallet
    fail({ message: error.message || 'Unable to process payment' })
  }
}

Capture payload structure

The payload object in onCapture contains:
{
  card_data: CardData      // Encrypted payment token and card details
  payment_method: 'CREDIT_CARD' | 'DEBIT_CARD'  // Card funding type
  transaction: Transaction // Original transaction object
}
The payment_method is automatically determined from the card’s funding type. If the funding type is not available in the wallet response, it defaults to 'CREDIT_CARD'.

Card data structure

The payload.card_data object contains:
{
  cryptogram: string       // Payment cryptogram for authorization
  expiry_month: string     // Card expiry month
  expiry_year: string      // Card expiry year
  wallet_type: 'APPLE_PAY' | 'GOOGLE_PAY'
  last_digits?: string     // Last 4 digits of card
  brand?: string           // Card brand (Visa, Mastercard, etc.)
  network_token?: string   // Network tokenized PAN
  eci?: string             // E-commerce indicator
}

Error handling

onError: (error) => {
  switch (error.code) {
    case 'PROVIDER_ERROR':
      // Apple Pay or Google Pay service issue
      showMessage('Payment service unavailable')
      break
    case 'VALIDATION_ERROR':
      // Invalid configuration
      console.error('Config error:', error.details)
      break
    case 'CONFIGURATION_ERROR':
      // Merchant setup issue
      console.error('Setup error:', error.message)
      break
    default:
      console.error('Unknown error:', error)
  }
}

TypeScript support

RinneJS is written in TypeScript and exports all type definitions:
import type {
  Options,
  Environment,
  TransactionCreateParams,
  WalletSuccessPayload,
  WalletError,
  WalletButtonOptions,
  CardData,
  ApplePayElement,
  GooglePayElement,
  MountedElement
} from '@rinnebr/js'

Requirements

Both Apple Pay and Google Pay require your website to be served over HTTPS. Payment buttons will not function on insecure HTTP connections.
To accept Apple Pay, you must verify your domain with Rinne. Contact support to complete the verification process.
If your website uses CSP headers, add these directives:
script-src https://js.evervault.com;
connect-src https://keys.evervault.com https://api.evervault.com https://api.rinne.com.br https://api-sandbox.rinne.com.br;
frame-src https://ui-components.evervault.com;
For payments to work, users must:
  • Have at least one card added to their Apple Wallet or Google Pay
  • Use a supported browser and device
  • Be located outside Mainland China (Apple Pay restriction)

Browser support

BrowserApple PayGoogle Pay
Safari (iOS 10+, macOS 10.12+)
Chrome
Firefox
Edge

Complete example

import { useEffect, useRef } from 'react'
import { Rinne } from '@rinnebr/js'

export function CheckoutButton({ amount, onSuccess }) {
  const applePayRef = useRef(null)
  const googlePayRef = useRef(null)

  useEffect(() => {
    const rinne = new Rinne({
      merchantId: process.env.RINNE_MERCHANT_ID,
      environment: 'production'
    })

    async function setup() {
      const transaction = await rinne.transaction.create({
        amount,
        currency: 'BRL',
        country: 'BR'
      })

      const handlers = {
        onCapture: async (payload, fail) => {
          try {
            await fetch('/api/charge', {
              method: 'POST',
              body: JSON.stringify({ cardData: payload.card_data })
            })
            onSuccess()
          } catch (e) {
            fail({ message: e.message })
          }
        }
      }

      const applePay = await rinne.elements.applePay(transaction, {
        button: { type: 'pay' },
        ...handlers
      })
      await applePay.mount(applePayRef.current)

      const googlePay = await rinne.elements.googlePay(transaction, {
        button: { type: 'pay' },
        ...handlers
      })
      await googlePay.mount(googlePayRef.current)
    }

    setup()
  }, [amount])

  return (
    <div className="payment-buttons">
      <div ref={applePayRef} />
      <div ref={googlePayRef} />
    </div>
  )
}

Next steps