npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@paysio/react-native

v0.1.1

Published

Paysio Mobile SDK for React Native and Expo: native card and bank entry, 3-D Secure, and checkout.

Readme

@paysio/react-native

Paysio Mobile SDK for React Native and Expo. Native card and bank account entry, 3-D Secure, and a drop-in checkout sheet. Card numbers go straight from the secure fields to the Paysio vault (VGS). They never reach your app code, your server, or Paysio's servers.

Works in Expo Go and in bare React Native. No native code to link. The only extra packages are react-native-webview (for 3-D Secure) and react-native-svg (for the card brand marks and icons).

Install

npm i @paysio/react-native react-native-webview react-native-svg

With Expo:

npx expo install react-native-webview react-native-svg
npm i @paysio/react-native

Requirements: React Native 0.71 or newer, React 18 or newer, react-native-svg 13 or newer, react-native-webview 11 or newer.

Quickstart

  1. On your server, create a checkout session with your secret key. The response contains a slug. Hand that slug to the app (never ship a secret key in the app).

    curl https://api.paysio.com/v1/checkout-sessions \
      -H "Authorization: Bearer sk_live_..." \
      -H "Content-Type: application/json" \
      -d '{ "items": [{ "productId": "prod_...", "quantity": 1 }], "customerEmail": "[email protected]" }'
  2. In the app, render the payment sheet with that slug.

    import { PaysioProvider, PaysioPaymentSheet } from '@paysio/react-native'
    
    export function CheckoutScreen({ slug }: { slug: string }) {
      return (
        <PaysioProvider sessionSlug={slug} theme={{ scheme: 'auto' }} appId="com.example.app">
          <PaysioPaymentSheet
            onSuccess={(result) => console.log('paid', result.transactionId, result.orderLabel)}
            onError={(error) => console.log(error.code, error.message)}
          />
        </PaysioProvider>
      )
    }
  3. Handle onSuccess. The result carries transactionId, orderLabel, status (pending_settlement), amount, currency and card: { brand, last4 }. Confirm the order on your server from the Paysio webhook, not from the app.

  4. Test with sandbox cards. Create the session in a sandbox workspace and use these numbers with any future expiry and any CVC:

    | Card | Number | |---|---| | Visa, no 3-D Secure | 4111 1111 1111 1111 | | Visa, 3-D Secure frictionless | 4147 4630 1111 0134 | | Visa, 3-D Secure challenge | 4016 3600 0000 0493 |

    Bank account (sandbox): routing 490000018, account 24413815. Other routing numbers are refused in the sandbox.

  5. Go live. Create sessions with your live secret key. Nothing changes in the app.

Custom layout

The sheet is built from pieces you can arrange yourself. Everything reads from usePaysio().

import { Button, View } from 'react-native'
import {
  PaysioProvider, usePaysio,
  PaysioContactFields, PaysioCardFields, PaysioBillingAddress,
} from '@paysio/react-native'

function Form() {
  const { session, state, pay, customer, setCustomer, billing, setBilling } = usePaysio()
  if (!session) return null
  return (
    <View style={{ gap: 24 }}>
      <PaysioContactFields value={customer} onChange={setCustomer} requirePhone={session.requirePhone} hideName />
      <PaysioCardFields />
      <PaysioBillingAddress value={billing} onChange={setBilling} errors={state.fieldErrors} />
      <Button title={`Pay ${session.totalFormatted}`} disabled={!state.canPay} onPress={() => pay()} />
    </View>
  )
}

export function Screen({ slug }: { slug: string }) {
  return (
    <PaysioProvider sessionSlug={slug}>
      <Form />
    </PaysioProvider>
  )
}

pay(options?) validates, tokenizes, runs 3-D Secure when the merchant has it on, and charges. It returns the same result as the sheet and throws a PaysioError on failure. state has canPay, isPaying, step (idle, validating, aliasing, three_ds, charging, done), fields.number / expiry / cvc, brand, last4 and fieldErrors.

Other pieces: PaymentMethodPicker (the radio rows with collapsible panels), PaysioBankFields, PaysioCustomFields, SavedMethodSelect, AcceptedBrandStack, CardBrand, Icon, StackedInput, BottomSheet.

3-D Secure

When the merchant has 3-D Secure on, pay() runs it before the charge. Most cards pass silently. When the bank asks the cardholder to confirm, the SDK opens a white sheet titled "Verify your card" with the bank's own page inside. The sheet closes by itself when the bank answers. If the customer taps Cancel, pay() throws three_ds_cancelled and nothing is charged. If the bank does not answer within 4 minutes, pay() throws three_ds_timeout.

The sheet is part of PaysioProvider, so it works in custom layouts too. Nothing to mount.

Bank accounts

When the merchant accepts bank payments, the sheet shows a "Bank account" row with a routing number field, an account number field, Personal / Business and Checking / Savings toggles, and the authorization text the customer must accept. The account number goes to the vault the same way a card number does. Bank payments settle later; the result status is pending_settlement and the final outcome arrives by webhook.

Address suggestions

The street line in the billing and shipping address suggests real addresses as the customer types, the same as hosted checkout. Picking one fills the street, city, state, ZIP and country. Suggestions come from Google Places through Paysio's API, so there is no key to add to your app. Inside PaysioProvider this is on automatically. If suggestions are unavailable, the field works as normal text.

Saved methods

Saved methods are a phase 2 feature. PaysioProvider accepts savedMethods and savedMethodPortalToken; when both are given the sheet renders a "Saved method" row. Obtaining the portal token (email code) is not part of this release.

Theming

Pass theme to PaysioProvider:

<PaysioProvider
  sessionSlug={slug}
  theme={{
    scheme: 'auto',              // 'light' | 'dark' | 'auto'
    colors: { primary: '#0B57D0' },
    darkColors: { card: '#111111' },
    fontFamily: 'Inter',
    fontFamilyMedium: 'Inter-Medium',
    radius: 18,                  // outer radius of the picker
  }}
>

| Token | Light | Dark | Used for | |---|---|---|---| | primary | #0B57D0 | #0B57D0 | Pay button, selected radio, links | | foreground | #1B1B1B | #F0F0F0 | Text, input text | | mutedForeground | #5D5D5F | #A6A6A6 | Headings, placeholders, icons | | card | #FCFCFD | #101010 | Sheets, saved method trigger | | background | #F3F3F4 | #0A0A0A | Chip press state | | secondary | #EAEAED | #181818 | Saved address trigger, chips | | border | #ECECEC | rgba(255,255,255,0.09) | Picker border and dividers | | input | #DBDBDC | #404040 | Field borders | | rowHover | rgba(0,0,0,0.04) | rgba(255,255,255,0.05) | Row press | | ring | rgba(0,0,0,0.35) | rgba(255,255,255,0.4) | Focus ring, same as hosted checkout | | destructive | #C70A24 | #DC2626 | Errors |

The focus ring stays grey when you change colors.primary, the same as the hosted checkout. Set ring yourself if you want a coloured one. The 3-D Secure sheet is always white, because the bank's page inside it is.

Errors

pay() throws PaysioError. code is stable; message is plain language you can show.

| Code | Meaning | What to do | |---|---|---| | invalid_fields | Something is missing or invalid. fieldErrors has a message per field. | Show the messages | | billing_address_required | Street, city, postal code or country is missing | Show the billing block | | contact_required | Email, first name or last name is missing (or phone when required) | Show the contact block | | declined | The bank declined. declineCode has the processor code. | Ask for another card | | three_ds_failed | Card verification was refused | Ask for another card | | three_ds_cancelled | The customer closed the verification sheet | Let them try again | | three_ds_timeout | The bank did not answer in 4 minutes | Let them try again | | session_expired | The session is expired, inactive or already paid | Create a new session | | session_invalid | The slug is empty or not a checkout | Check the slug | | rate_limited | Too many attempts | Wait, then retry | | network | Paysio could not be reached before anything was charged | Retry | | unknown | The charge was sent but the answer did not arrive. idempotencyKey is set. | Do not retry blindly. Confirm by webhook or ask support with the key. | | vault_unavailable | The secure fields could not be submitted | Retry | | not_configured | The session has no vault configuration | Contact Paysio |

unknown deserves care: the SDK already retried the charge once with the same idempotency key when the network dropped. A second attempt with the same key is safe (Paysio replays the stored answer), a new attempt is not.

Events

onEvent on PaysioProvider receives analytics events. None of them contains card data.

ready, field_focus, method_change, pay_start, three_ds_start, three_ds_challenge, three_ds_result, pay_result, error.

App Store and Google Play rules

Physical goods and real-world services (clothes, food delivery, a plumber, a gym booking) must not use in-app purchase. Collecting a card in the app is allowed and carries no store fee. That is what this SDK is for.

Digital goods and services consumed inside the app (subscriptions to app features, coins, unlocks) must use the store's own billing on both platforms. Do not use this SDK for those sales. See Apple App Store Review Guideline 3.1.3(e) and the Google Play Payments policy.

Security and PCI

Card data is typed into fields provided by VGS and sent directly to VGS's PCI DSS Level 1 environment. It is not transmitted to or stored by your servers or by Paysio's servers; Paysio only ever receives an alias. Your app is still the point of entry, so:

  • Keep the SDK up to date.
  • Do not take screenshots or screen recordings of the payment screen in your own code (on Android consider FLAG_SECURE for that screen).
  • Never put a secret key (sk_) or a publishable key (pk_) in the app. The session slug is the only thing the app needs.
  • onEvent and PaysioError never carry card data; it is safe to log them.

Expo notes

  • Works in Expo Go. No config plugin, no development build needed.
  • iOS privacy manifest: the VGS SDK declares its API usage in its own PrivacyInfo.xcprivacy. If your app ships its own manifest, copy the entries from node_modules/@vgs/collect-react-native/PrivacyInfo.xcprivacy (when present in your installed version) into it. They are "Product Interaction" entries, not tracking.
  • Android: nothing to add.

Using the fields without a checkout session (advanced)

Paysio's own app and some integrations need the secure fields without a session. PaysioFieldsProvider gives the fields a vault and a theme; usePaysioFields() returns aliasCard() and aliasBank(), which submit the mounted fields and return aliases you post to your own endpoint.

import { Button } from 'react-native'
import { PaysioFieldsProvider, PaysioCardFields, usePaysioFields } from '@paysio/react-native'

function AddCard({ onAlias }: { onAlias: (a: { panAlias: string; cvcAlias: string; expMonth: string; expYear: string }) => void }) {
  const { aliasCard, cardState } = usePaysioFields()
  return (
    <>
      <PaysioCardFields />
      <Button title="Save card" disabled={!cardState.valid} onPress={async () => onAlias(await aliasCard())} />
    </>
  )
}

export function Screen() {
  return (
    <PaysioFieldsProvider vault={{ vaultId: 'tnt...', environment: 'sandbox' }} sandbox theme={{ scheme: 'dark' }}>
      <AddCard onAlias={(a) => fetch('https://your.server/cards', { method: 'POST', body: JSON.stringify(a) })} />
    </PaysioFieldsProvider>
  )
}

Pass apiBase="https://api.paysio.com" to PaysioFieldsProvider (or to PaysioBillingAddress directly) to turn on address suggestions outside a session. createCollector({ vaultId, environment }), aliasCard(collector, meta) and aliasBank(collector, meta) are exported for code that manages the VGS collector itself. PaymentMethodPicker, PaysioBillingAddress, SavedMethodSelect and the other pieces are plain controlled components and work inside either provider.

Keeping fields clear of the keyboard

When a field gets focus, or the address suggestions open, the SDK scrolls the page just enough that they sit above the keyboard, sliding up together with it. PaysioPaymentSheet does this on its own.

In a custom layout, the SDK needs to scroll your scroll view. Either use PaysioScrollView in place of your ScrollView, or wrap your content in PaysioKeyboardScrollProvider and tell it how to scroll:

import { useRef } from 'react'
import { ScrollView } from 'react-native'
import { PaysioKeyboardScrollProvider, PaysioCardFields } from '@paysio/react-native'

export function Checkout() {
  const ref = useRef<ScrollView>(null)
  const offset = useRef(0)
  return (
    <ScrollView ref={ref} onScroll={(e) => (offset.current = e.nativeEvent.contentOffset.y)} scrollEventThrottle={16}>
      <PaysioKeyboardScrollProvider scrollBy={(dy) => ref.current?.scrollTo({ y: offset.current + dy, animated: true })}>
        <PaysioCardFields />
      </PaysioKeyboardScrollProvider>
    </ScrollView>
  )
}

Without either, the fields still work; they just do not scroll themselves into view.

Using your own sheets and list rows

The country, state, saved address, saved card and custom select lists open in a bottom sheet. If your app already has its own sheet and list rows, pass them in and every list matches the rest of your app:

import { PaysioSheetComponentsProvider, type PaysioSheetComponents } from '@paysio/react-native'

const sheets: PaysioSheetComponents = {
  Sheet: MySheet, // { open, onClose, title, searchable, searchPlaceholder, children: (query) => ReactNode }
  Row: MyRow, // { selected, onPress, leading, label, detail, trailing, disabled, children }
  Empty: MyEmpty, // { text }
}

<PaysioSheetComponentsProvider components={sheets}>{/* Paysio fields */}</PaysioSheetComponentsProvider>

Each part is optional. Anything you leave out uses the SDK's own look.

Changelog

0.1.1

Street address suggestions (Google Places through Paysio's API) in PaysioBillingAddress. New apiBase prop on PaysioFieldsProvider and PaysioBillingAddress. Fields and the suggestion list now stay clear of the keyboard: the drop-in sheet handles it, and custom layouts use PaysioKeyboardScrollProvider or PaysioScrollView. Pick-list sheets sit above the keyboard while you search, and can be replaced with your own through PaysioSheetComponentsProvider. Fixed a "Cannot update a component while rendering a different component" warning when onEvent sets state. The focus ring now matches hosted checkout (grey, not blue) and the CVC is no longer masked, same as the web.

0.1.0

First release. Drop-in PaysioPaymentSheet, composable fields, 3-D Secure sheet, bank accounts, light and dark themes, Expo Go support.