Documentation Index
Fetch the complete documentation index at: https://docs.sudo.africa/llms.txt
Use this file to discover all available pages before exploring further.
Package
Installation
npm install react-native-cloudcard
# or
yarn add react-native-cloudcard
Android Repository Setup
For Gradle < 7 (android/build.gradle):
allprojects {
repositories {
google()
mavenCentral()
maven {
url = uri("https://sdk.sudo.africa/repository/maven-releases/")
credentials {
username = project.findProperty("maven.repo.username") ?: ""
password = project.findProperty("maven.repo.password") ?: ""
}
}
}
}
For Gradle 7+ (android/settings.gradle):
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven {
url = uri("https://sdk.sudo.africa/repository/maven-releases/")
credentials {
username = providers.gradleProperty("maven.repo.username").orNull ?: System.getenv("NEXUS_USER")
password = providers.gradleProperty("maven.repo.password").orNull ?: System.getenv("NEXUS_PASS")
}
}
}
}
Set credentials in gradle.properties:
maven.repo.username=your_sudo_username
maven.repo.password=your_sudo_password
Or set environment variables:
export NEXUS_USER=your_sudo_username
export NEXUS_PASS=your_sudo_password
Android Manifest Configuration
Register the HCE service and receiver inside <application> in android/app/src/main/AndroidManifest.xml.
<service
android:name="com.sudo.cloud_card.HCEService"
android:enabled="true"
android:exported="true"
android:permission="android.permission.BIND_NFC_SERVICE">
<intent-filter>
<action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data
android:name="android.nfc.cardemulation.host_apdu_service"
android:resource="@xml/apduservice" />
</service>
<receiver
android:name="africa.sudo.cloudcard.reactnative.HceEventReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="${applicationId}.CLOUDCARD_EVENT" />
</intent-filter>
</receiver>
Create android/app/src/main/res/xml/apduservice.xml:
<?xml version="1.0" encoding="utf-8"?>
<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/app_name"
android:requireDeviceUnlock="false">
<aid-group android:category="payment" android:description="@string/app_name" />
</host-apdu-service>
iOS Setup
Create .env in your project root:
SUDO_USER=your_sudo_username
SUDO_PASS=your_sudo_password
Run:
export $(grep -v '^#' .env | xargs)
TMPHOME=$(mktemp -d)
trap 'rm -rf "$TMPHOME"' EXIT
export HOME="$TMPHOME"
cat > "$HOME/.netrc" <<EOF_NETRC
machine sdk.sudo.africa
login $SUDO_USER
password $SUDO_PASS
EOF_NETRC
chmod 600 "$HOME/.netrc"
cd ios && pod install
Initialization
Initialize once near app startup.
import CloudCard from 'react-native-cloudcard';
export async function initializeCloudCard() {
await CloudCard.init({
isSandBox: true,
onCardScanned: (event) => {
console.log('scan started', event?.eventType ?? event?.event_type, event?.message);
},
onScanComplete: (event) => {
console.log('scan done', event?.isSuccess ?? event?.is_success, event?.amount);
},
});
}
Environment:
isSandBox: true for sandbox
isSandBox: false for production
Health Checks
const isSupported = await CloudCard.isDeviceSupported();
const isNfcEnabled = await CloudCard.isNfcEnabled();
const isDefaultApp = await CloudCard.isDefaultPaymentApp();
if (isSupported && isNfcEnabled === true && isDefaultApp === false) {
await CloudCard.launchDefaultPaymentAppSettings();
}
Optional Security Behavior
await CloudCard.setRequireAuth(true);
Register Card
You register cards with RegistrationData.
Required fields:
walletId
paymentAppInstanceId
accountId
jwtToken
Optional fields:
secret
cardNumber
expiryDate
cardHolderName
import CloudCard from 'react-native-cloudcard';
const result = await CloudCard.registerCard({
walletId: 'institution-id',
paymentAppInstanceId: 'device-instance-id',
accountId: 'card-or-account-id',
jwtToken: 'onboarding-jwt-token',
secret: 'optional-secret',
cardNumber: '4111111111111111',
expiryDate: '12/25',
cardHolderName: 'John Doe',
});
if (result.status === 'SUCCESS') {
console.log('Card registered');
} else {
console.log(`Registration failed: ${result.message}`);
}
Digitalization Fetch Pattern
If you already have your own card-management system, you can build and pass your own RegistrationData directly to registerCard using the required fields walletId, paymentAppInstanceId, accountId, and jwtToken.
If you do not manage that payload yourself, fetch the onboarding or digitalization payload from your backend first, then pass it to registerCard. For endpoint details, see Card Digitalization Reference.
const res = await fetch(
`https://api.sandbox.sudo.cards/cards/digitalize/{id}`,
{
method: 'GET',
headers: {
Accept: 'text/plain',
'Content-Type': 'application/json',
platform: 'android',
Authorization: accessToken,
},
}
);
const jwtToken = await res.text();
Card Management
Get Cards
import CloudCard from 'react-native-cloudcard';
const result = await CloudCard.getCards();
if (result.status === 'SUCCESS' && Array.isArray(result.data)) {
result.data.forEach((card) => {
console.log(card.id, card.maskedPan, `active=${card.isActive}`);
});
}
Freeze or Unfreeze
await CloudCard.freezeUnfreezeCard({
cardId,
isFreeze: true,
periodInDays: 7,
});
Set isFreeze: false to unfreeze.
Delete Card
await CloudCard.deleteCard(cardId);
Wipe Wallet
await CloudCard.wipeWallet();
Use this only after explicit user confirmation.
Manual Key Replenishment
const result = await CloudCard.manualKeyReplenishment();
Token Usage Summary
const result = await CloudCard.tokenSummary();
if (result.status === 'SUCCESS' && result.data) {
console.log(
`total=${result.data.totalTokens} balance=${result.data.tokensBalance}`
);
}
QR and Transactions
Generate EMV QR
import CloudCard from 'react-native-cloudcard';
const result = await CloudCard.getEmvQr({
cardId,
amount: '000000000200',
foregroundColorHex: '#000000',
backgroundColorHex: '#FFFFFF',
});
if (result.status === 'SUCCESS' && result.data) {
const uri = `data:image/png;base64,${result.data}`;
console.log('QR ready', uri);
}
amount is in the smallest unit and typically zero-padded.
Read Saved Transactions
getSavedTransactions() returns recent cached transactions, up to 5.
const result = await CloudCard.getSavedTransactions();
if (result.status === 'SUCCESS' && Array.isArray(result.data)) {
result.data.forEach((tx) => {
console.log(tx.amount, tx.currency, tx.timestamp, tx.type);
});
}
NFC and Settings
import CloudCard from 'react-native-cloudcard';
const isNfcEnabled = await CloudCard.isNfcEnabled();
const isDefaultPaymentApp = await CloudCard.isDefaultPaymentApp();
if (isNfcEnabled === true && isDefaultPaymentApp === false) {
await CloudCard.launchDefaultPaymentAppSettings();
}
NFC Chip Indicator Helpers
await CloudCard.showNfcChipPosition({
duration: 5000,
colorHex: '#AF5298',
});
const position = await CloudCard.getNfcChipPosition();
console.log(position?.x, position?.y, position?.radius, position?.hint);
await CloudCard.hideNfcChipPosition();
Requirements
- React Native 0.68+
- Android API 24+
- iOS 13.0+
NFC-enabled device is required for NFC payments, but not for QR.
Troubleshooting
Initialization Fails
- Confirm SDK repository credentials are set correctly on Android.
- Confirm the iOS
.netrc auth step was completed before pod install.
- Check that you called
init() before card operations.
- Rebuild the app after native dependency changes.
- Run
cd ios && pod install for iOS before rebuilding.
NFC Not Working
- Confirm the device supports NFC.
- Confirm NFC is enabled in system settings.
- Confirm your app is set as default payment app when required.
- Verify the HCE service and receiver entries in
AndroidManifest.xml.
- Confirm the receiver class is
africa.sudo.cloudcard.reactnative.HceEventReceiver.
Card Registration Fails
- Verify
walletId, paymentAppInstanceId, accountId, and jwtToken.
- Ensure the onboarding token is still valid.
- Check that your backend is issuing tokens for the correct environment.
QR Generation Fails
- Use a valid
cardId.
- Ensure
amount is formatted correctly.
Empty Transaction List
getSavedTransactions() uses local cache and returns recent transactions only.
- Complete at least one transaction flow first, then reload.
Support
Contact support@sudo.africa.