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-svgreact-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
| Prop | Type | Description |
|---|---|---|
apiKey | string | Required. Your publishable key. |
transactionId | string | Required. 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. |
phoneNumber | string | The customer's phone number, sent with the payment. In the sandbox, a test number decides the outcome. |
onPaySuccess | (request, method) => void | Called when the payment succeeds. |
onPayError | (error: Error) => void | Called when the payment fails. |
onBackPress | () => void | Called when the customer taps the back arrow. |
primaryColor, buttonColor, radioColor | string | Colors for the button and the selected radio. buttonColor and radioColor override primaryColor. |
onCopyBankilyCode, onCopySedadCode | (code: string) => void | Called 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". |
masriviBottomSheetHeight | number | "${number}%" | Height of the Masrvi bottom sheet. |
LoadingComponent | ReactNode | ComponentType | Custom 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:
| Prop | Description |
|---|---|
selectedMethodId, onSelectMethod | The selected method, controlled by your state. |
onError | Called when loading the payment methods fails. |
onLoadingChange | Called when the methods start and finish loading. |
onContinueLoadingChange | Called when continuePayment() starts and finishes. |
accentColor | Accent color for the default rows and the payment dialogs. |
renderMethod | Renders 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
- Webhooks: confirm payments on your server
- Testing: test phone numbers and outcomes
- API keys: publishable and secret keys
- Package on npm