> ## 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.

# React Native SDK

> Sudo Cloud Card React Native SDK.

## Package

* SDK: `react-native-cloudcard`
* Version: **0.1.1** ([npmjs.com/package/react-native-cloudcard](https://www.npmjs.com/package/react-native-cloudcard))

## Installation

```bash theme={null}
npm install react-native-cloudcard
# or
yarn add react-native-cloudcard
```

## Android Repository Setup

For Gradle \< 7 (`android/build.gradle`):

```groovy theme={null}
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`):

```groovy theme={null}
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`:

```properties theme={null}
maven.repo.username=your_sudo_username
maven.repo.password=your_sudo_password
```

Or set environment variables:

```bash theme={null}
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`.

```xml theme={null}
<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>
</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>
```

## iOS Setup

Create `.env` in your project root:

```bash theme={null}
SUDO_USER=your_sudo_username
SUDO_PASS=your_sudo_password
```

Run:

```bash theme={null}
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.

```ts theme={null}
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

```ts theme={null}
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

```ts theme={null}
await CloudCard.setRequireAuth(true);
```

## Register Card

You register cards with `RegistrationData`.

Required fields:

* `walletId`
* `paymentAppInstanceId`
* `accountId`
* `jwtToken`

Optional fields:

* `secret`
* `cardNumber`
* `expiryDate`
* `cardHolderName`

```ts theme={null}
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](/reference/card-digitalization).

```ts theme={null}
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

```ts theme={null}
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

```ts theme={null}
await CloudCard.freezeUnfreezeCard({
  cardId,
  isFreeze: true,
  periodInDays: 7,
});
```

Set `isFreeze: false` to unfreeze.

### Delete Card

```ts theme={null}
await CloudCard.deleteCard(cardId);
```

### Wipe Wallet

```ts theme={null}
await CloudCard.wipeWallet();
```

Use this only after explicit user confirmation.

### Manual Key Replenishment

```ts theme={null}
const result = await CloudCard.manualKeyReplenishment();
```

### Token Usage Summary

```ts theme={null}
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

```ts theme={null}
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.

```ts theme={null}
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

```ts theme={null}
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

```ts theme={null}
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](mailto:support@sudo.africa).
