Skip to main content
This quickstart builds a checkout that supports Apple Pay, Google Pay, and card entry with 3D Secure — all from one SDK instance.

Goal

In this guide, you will:
  • Initialize the SDK
  • Mount wallet buttons and card fields
  • Run 3D Secure when required
  • Forward encrypted payment data to your backend

1. Initialize Rinne

checkout.ts
import { Rinne } from '@rinnebr/js'

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

2. Mount Payment Elements

Mount wallet buttons for Apple Pay and Google Pay, and a card element for manual entry.
checkout.ts
const transaction = await rinne.transaction.create({
  amount: 2500,
  lineItems: [
    { label: 'Premium Plan', amount: 2000 },
    { label: 'Tax', amount: 500 }
  ]
})

const walletHandlers = {
  onCapture: async (payload, fail) => {
    try {
      await submitToBackend(payload)
    } catch (error) {
      fail({ message: error instanceof Error ? error.message : 'Payment failed' })
    }
  }
}

const applePay = await rinne.elements.applePay(transaction, {
  button: { type: 'pay', color: 'black', locale: 'pt' },
  ...walletHandlers
})
await applePay.mount('#apple-pay-button')

const googlePay = await rinne.elements.googlePay(transaction, {
  button: { type: 'pay', color: 'black', locale: 'pt' },
  ...walletHandlers
})
await googlePay.mount('#google-pay-button')

const cardElement = await rinne.elements.card({
  theme: 'material',
  locale: 'pt',
  fields: ['number', 'expiry', 'cvc'],
  onChange: (state) => {
    submitButton.disabled = !state.isComplete || !state.isValid
  }
})

const mountedCard = await cardElement.mount('#card-element')
If you omit currency and country, the SDK defaults to BRL and BR.
Always call fail() inside onCapture when backend processing fails. This lets the wallet UI show a proper failure state and allows retry.

3. Handle Card Submission with 3DS

This example follows the session-first pattern: create a 3DS session, authenticate, then create the transaction. When the customer submits the card form, read the encrypted values, run the challenge if the issuer requires it, and create the transaction after authentication succeeds.
checkout.ts
async function submitCardPayment(amountInCents: number) {
  if (!mountedCard.isComplete || !mountedCard.isValid) return

  const cardValues = mountedCard.values

  const session = await create3DSSession({
    amount: amountInCents,
    currency: 'BRL',
    card: {
      number: cardValues.card.number,
      expiry: { month: cardValues.card.expiry_month, year: cardValues.card.expiry_year }
    }
  })

  if (session.auth_status === 'FAILED') {
    throw new Error(session.failure_reason ?? '3DS authentication failed')
  }

  if (session.auth_status === 'ACTION_REQUIRED') {
    await run3DSChallenge(session.tds_session_id)
  }

  return await createTransaction({
    amount: amountInCents,
    cardData: cardValues.card,
    three_d_secure_session_id: session.id
  })
}

async function run3DSChallenge(tdsSessionId: string) {
  return new Promise<void>((resolve, reject) => {
    rinne.elements.threeDSecure({
      target: '#three-ds-container',
      onSuccess: () => resolve(),
      onFailure: (error) => reject(new Error(error?.message ?? 'Authentication failed')),
      onError: (error) => reject(new Error(error.message))
    }).then((threeDS) => threeDS.mount(tdsSessionId))
  })
}
create3DSSession and createTransaction represent calls to your backend. Rinne also supports a transaction-first pattern where you create the transaction before authentication. See the Card + 3DS Guide for both flows with full backend examples.
Never collect raw PAN/CVC in your own inputs. Use only encrypted values from mountedCard.values.

4. Verify Success

Your checkout is correctly wired when:
  • Wallet authorization triggers onCapture and your backend receives an encrypted payload
  • Card submission creates a 3DS session, runs the challenge via onSuccess, and creates the transaction with the authenticated session ID
  • fail() is called whenever wallet backend processing fails

Next Steps