Moosyl logo

React Native SDK

Accept Bankily, Sedad, Masrvi and other Mauritanian bank app payments in your React Native app with the Moosyl SDK.

moosyl-react-native shows the Moosyl payment flow inside your React Native app: your customer picks their bank app, pays, and your app gets the result. It supports Bankily, Sedad, Masrvi, BimBank, BCI Pay and Amanty, in English, French and Arabic.

The SDK only handles the customer's side. Your server creates the payment request with your secret key (Quickstart) and confirms the payment from the webhook.

Install

Install the package and its native peer dependencies:

npm install moosyl-react-native react-native-webview lucide-react-native react-native-svg

react-native-webview renders the Masrvi payment page, and lucide-react-native with react-native-svg draw the icons in the Bankily and Sedad dialogs. react-native-localize is an optional peer dependency.

On iOS, run pod install in your ios folder afterwards.

Show the payment view

MoosylView renders the whole flow: method list, summary and the Continue button.

import { MoosylView } from "moosyl-react-native";

export function CheckoutScreen({ transactionId }: { transactionId: string }) {
  return (
    <MoosylView
      apiKey="YOUR_PUBLISHABLE_KEY"
      transactionId={transactionId} // from your server
      locale="fr"
      items={[
        { label: "amountToPay", amount: 2000 },
        { label: "tax", amount: 150 },
      ]}
      onPaySuccess={(request, method) => {
        // Show a confirmation. Fulfil the order from your webhook.
      }}
      onPayError={(error) => console.error(error)}
    />
  );
}

Props

PropTypeDescription
apiKeystringRequired. Your publishable key.
transactionIdstringRequired. The transactionId of the payment request your server created.
locale"en" | "fr" | "ar"UI language. Defaults to "en".
items{ label: string; amount: number }[]Summary rows in MRU. Their total must equal the payment request amount. amountToPay, serviceFee, tax, total and paymentSummary are translated; other labels are shown as written.
phoneNumberstringThe customer's phone number, sent with the payment. In the sandbox, a test number decides the outcome.
onPaySuccess(request, method) => voidCalled when the payment succeeds.
onPayError(error: Error) => voidCalled when the payment fails.
onBackPress() => voidCalled when the customer taps the back arrow.
primaryColor, buttonColor, radioColorstringColors for the button and the selected radio. buttonColor and radioColor override primaryColor.
onCopyBankilyCode, onCopySedadCode(code: string) => voidCalled when the customer taps a payment code in the Bankily or Sedad/BimBank dialog. Use it to copy the code, e.g. with Clipboard.setString.
masriviPresentation"fullPage" | "bottomSheet"How the Masrvi page opens. Defaults to "fullPage".
masriviBottomSheetHeightnumber | "${number}%"Height of the Masrvi bottom sheet.
LoadingComponentReactNode | ComponentTypeCustom UI while payment methods load.

Use your own checkout screen

To keep your own layout and button, use MoosylPaymentMethods. It loads and shows the payment methods; your button calls continuePayment() on its ref.

import { useRef, useState } from "react";
import { Button, View } from "react-native";
import {
  MoosylPaymentMethods,
  type MoosylPaymentMethodsRef,
  type PaymentMethodItem,
} from "moosyl-react-native";

export function CustomCheckout({ transactionId }: { transactionId: string }) {
  const methodsRef = useRef<MoosylPaymentMethodsRef>(null);
  const [selected, setSelected] = useState<PaymentMethodItem | null>(null);

  return (
    <View>
      <MoosylPaymentMethods
        ref={methodsRef}
        apiKey="YOUR_PUBLISHABLE_KEY"
        transactionId={transactionId}
        selectedMethodId={selected?.id ?? null}
        onSelectMethod={setSelected}
        onPaySuccess={(request, method) => {
          // Show a confirmation. Fulfil the order from your webhook.
        }}
        onPayError={(error) => console.error(error)}
      />
      <Button
        title="Continue"
        disabled={!selected}
        onPress={() => methodsRef.current?.continuePayment()}
      />
    </View>
  );
}

MoosylPaymentMethods takes apiKey, transactionId, locale, phoneNumber, onPaySuccess, onPayError, masriviPresentation, masriviBottomSheetHeight and LoadingComponent like MoosylView, plus:

PropDescription
selectedMethodId, onSelectMethodThe selected method, controlled by your state.
onErrorCalled when loading the payment methods fails.
onLoadingChangeCalled when the methods start and finish loading.
onContinueLoadingChangeCalled when continuePayment() starts and finishes.
accentColorAccent color for the default rows and the payment dialogs.
renderMethodRenders each method row yourself. Call onSelect() from your row.

The ref exposes continuePayment() and getSelectedMethod().

Custom method rows

import { Image, Pressable, Text } from "react-native";

<MoosylPaymentMethods
  apiKey="YOUR_PUBLISHABLE_KEY"
  transactionId={transactionId}
  onSelectMethod={setSelected}
  renderMethod={({ title, iconSource, isSelected, onSelect }) => (
    <Pressable onPress={onSelect} style={{ flexDirection: "row", gap: 12 }}>
      <Image source={iconSource} style={{ width: 36, height: 36 }} />
      <Text>{isSelected ? `✓ ${title}` : title}</Text>
    </Pressable>
  )}
/>

The render props are method, title (translated), iconSource, isSelected, selectedMethodId, locale, isRTL and onSelect. method.method is one of bankily, sedad, masrivi, bim_bank, bci_pay or amanty.

Test in the sandbox

Use a publishable key from your Sandbox environment, and create the payment request with a sandbox secret key. Pass a test phone number as phoneNumber to choose the outcome.

Never put your secret key in the app. The app only needs the publishable key and a transactionId.

Next steps