> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dodopayments.com/llms.txt
> Use this file to discover all available pages before exploring further.

# React Native

> Buka checkout hosted Dodo Payments dari aplikasi React Native atau Expo dalam tampilan browser sistem, dan dapatkan hasil checkout bertipe dari satu panggilan.

<Info>
  Halaman ini membahas SDK checkout React Native resmi Dodo Payments, `@dodopayments/react-native-checkout`. SDK ini membuka checkout hosted Dodo Payments dalam tampilan browser native dan mengembalikan hasil bertipe. Paket yang lebih lama, `dodopayments-react-native-sdk` (tanpa scope), memiliki API yang berbeda. Halaman ini hanya mendokumentasikan paket dengan scope.
</Info>

<CardGroup cols={2}>
  <Card title="Checkout Sessions API" icon="cart-shopping" href="/developer-resources/checkout-session">
    Buat `checkout_url` yang dibuka SDK ini dari backend Anda.
  </Card>

  <Card title="Mobile Integration Guide" icon="mobile" href="/developer-resources/mobile-integration">
    Lihat bagaimana SDK ini menjadi bagian dari alur pembayaran mobile secara lengkap.
  </Card>
</CardGroup>

SDK React Native adalah Turbo Module yang membungkus SDK checkout native [iOS](/developer-resources/sdks/ios) dan [Android](/developer-resources/sdks/android). SDK ini membuka `SFSafariViewController` di iOS dan Custom Tab di Android. SDK ini tidak menyimpan API key dan tidak memiliki logika checkout sendiri, sehingga tidak pernah memanggil API Dodo Payments. Checkout berjalan di tampilan browser. SDK menampilkan dan menutup tampilan tersebut serta membaca hasil dari return URL.

<Warning>
  SDK ini hanya mendukung **New Architecture**. SDK ini memerlukan React Native 0.77 atau yang lebih baru, iOS 16 atau yang lebih baru, dan Android `minSdk` 24. Aplikasi Android Anda harus dibangun dengan `compileSdk` 34 atau yang lebih baru.
</Warning>

## Instalasi

<Steps>
  <Step title="Install the Package">
    <Tabs>
      <Tab title="Android">
        Paket ini terhubung secara otomatis dan mengambil `com.dodopayments.api:checkout-android` dari Maven Central.

        ```sh theme={null}
        npm i @dodopayments/react-native-checkout
        ```

        Dependensi native diselesaikan secara otomatis, sehingga tidak diperlukan langkah instalasi lainnya.
      </Tab>

      <Tab title="iOS">
        ```sh theme={null}
        npm i @dodopayments/react-native-checkout
        cd ios && pod install
        ```

        Paket ini menyertakan core Swift, dan CocoaPods menginstalnya.
      </Tab>

      <Tab title="Expo">
        SDK ini hanya berfungsi dalam development build, bukan di Expo Go.

        ```sh theme={null}
        npm i @dodopayments/react-native-checkout
        ```

        Selanjutnya, konfigurasikan plugin di `app.json`, seperti ditunjukkan pada langkah berikutnya.
      </Tab>
    </Tabs>

    [Kustomisasi tampilan](#appearance-customization) memerlukan versi 1.2.0 atau yang lebih baru.
  </Step>

  <Step title="Register a Callback URL Scheme">
    Daftarkan URL scheme agar sistem operasi mengarahkan return URL checkout kembali ke aplikasi Anda.

    <Tabs>
      <Tab title="Android (Gradle)">
        Tetapkan scheme sebagai manifest placeholder di `android/app/build.gradle`:

        ```groovy android/app/build.gradle theme={null}
        android {
            defaultConfig {
                manifestPlaceholders["dodoCallbackScheme"] = "myapp"
            }
        }
        ```

        Ganti `"myapp"` dengan scheme aplikasi Anda.
      </Tab>

      <Tab title="iOS (Info.plist)">
        Tambahkan URL type ke `ios/YourApp/Info.plist`:

        ```xml Info.plist theme={null}
        <key>CFBundleURLTypes</key>
        <array>
          <dict>
            <key>CFBundleURLName</key>
            <string>myapp</string>
            <key>CFBundleURLSchemes</key>
            <array>
              <string>myapp</string>
            </array>
          </dict>
        </array>
        ```

        Anda juga dapat menambahkan URL type di Xcode melalui **Info → URL Types**.
      </Tab>

      <Tab title="Expo (both platforms)">
        Plugin config paket ini mendaftarkan scheme untuk kedua platform selama `prebuild`. Berikan scheme sebagai opsi `scheme` milik plugin di `app.json`:

        ```json app.json theme={null}
        {
          "expo": {
            "scheme": "myapp",
            "plugins": [
              [
                "@dodopayments/react-native-checkout",
                { "scheme": "myappcheckout" }
              ]
            ]
          }
        }
        ```

        `scheme` milik plugin harus cocok dengan scheme `returnUrl` yang Anda berikan, misalnya `myappcheckout://return`. Gunakan scheme yang berbeda dari `expo.scheme`. Expo sudah mendaftarkan `expo.scheme` di `MainActivity`, sehingga menggunakannya kembali dapat mengirim return checkout ke activity yang salah di Android, dan plugin akan memberikan peringatan. Plugin menolak `http`, `https`, serta scheme sistem lainnya.

        Bangun ulang proyek native setelah mengedit `app.json`:

        ```sh theme={null}
        npx expo prebuild --clean
        ```

        Plugin ini hanya berfungsi dalam development build, bukan di Expo Go. Di iOS, Anda tetap memerlukan listener `Linking` di [Meneruskan Return URL](#forwarding-the-return-url).

        Jika `android/app/build.gradle` tidak memiliki blok `defaultConfig { }`, plugin menghentikan `prebuild` dengan error. Dalam hal ini, tambahkan placeholder tersebut sendiri, seperti ditunjukkan pada tab Android.
      </Tab>
    </Tabs>

    Di setiap platform, tetapkan URL yang sama dengan `return_url` milik checkout session saat backend Anda membuat session. SDK mencocokkan return URL berdasarkan scheme, host, dan path. URL tersebut tidak perlu memuat halaman sungguhan.
  </Step>
</Steps>

## Penggunaan

Panggil `DodoCheckout.start` dengan `checkout_url` dari backend Anda:

```typescript theme={null}
import { Linking } from 'react-native';
import { DodoCheckout } from '@dodopayments/react-native-checkout';

// Required for iOS's return-URL handling.
Linking.addEventListener('url', ({ url }) => DodoCheckout.handleOpenURL(url));

// showSuccess(), showFailure(), showExpired(), and reconcileAbandonedSession()
// are your own functions. See Abandoned Sessions for what to reconcile.
const result = await DodoCheckout.start({
  checkoutUrl,                          // from your backend's checkout session
  returnUrl: 'myapp://checkout/return', // scheme must be registered (see Installation)
  onEvent: (e) => console.log(e.type),  // logging only
});

switch (result.status) {
  case 'succeeded': showSuccess(result.paymentId); break;
  case 'failed':    showFailure(); break;
  case 'cancelled': await reconcileAbandonedSession(); break; // outcome unknown, not a failure
  case 'pending':   await reconcileAbandonedSession(); break;
  case 'expired':   showExpired(); break;
}
```

`onEvent` menerima event dengan `type` berupa `checkout.opened`, `checkout.return_received`, atau `checkout.closed`. Gunakan hanya untuk logging, jangan untuk menentukan hasil.

## Meneruskan Return URL

iOS memerlukan listener `Linking` untuk menangani return URL, karena `SFSafariViewController` tidak dapat menangkap return URL miliknya sendiri. Di Android, `handleOpenURL` tidak melakukan apa pun dan mengembalikan `false`, karena Android SDK menangkap redirect secara native. Anda dapat mendaftarkan listener di kedua platform.

```typescript theme={null}
import { Linking } from 'react-native';
import { DodoCheckout } from '@dodopayments/react-native-checkout';

Linking.addEventListener('url', ({ url }) => {
  DodoCheckout.handleOpenURL(url);
});
```

Di iOS, `handleOpenURL` mengembalikan `true` saat URL tersebut merupakan milik checkout yang sedang berlangsung, dan `false` untuk URL lainnya.

## Arti Hasil

SDK membangun hasil dari query parameters pada return URL.

<Warning>
  `result.status` adalah petunjuk UI, bukan bukti pembayaran. Konfirmasikan setiap pembayaran dari backend Anda, menggunakan webhook `payment.succeeded` atau `subscription.active`.
</Warning>

<ParamField body="status" type="CheckoutStatus" required>
  Salah satu dari lima nilai berikut:

  * `succeeded`: return URL memiliki `status=succeeded` (pembayaran satu kali) atau `status=active` (subscription).
  * `failed`: pembayaran ditolak (`status=failed`).
  * `cancelled`: customer menutup tampilan browser sebelum return URL diterima. SDK tidak mengetahui hasilnya, dan pembayaran mungkin berhasil, jadi jangan tampilkan layar kegagalan. Rekonsiliasikan [abandoned session](#abandoned-sessions) sebagai gantinya.
  * `pending`: pembayaran diselesaikan kemudian (`status=processing` atau nilai `requires_*` lainnya), atau parameter `status` tidak ada atau tidak dikenali. Rekonsiliasikan seperti `cancelled`.
  * `expired`: checkout session kedaluwarsa (`status=expired`).
</ParamField>

<ParamField body="paymentId" type="string">
  Parameter query `payment_id`, jika return URL menyertakannya. Tampilkan di UI Anda, tetapi jangan gunakan untuk memberikan akses. Lihat [Verifikasi Pembayaran](#verify-the-payment).
</ParamField>

<ParamField body="subscriptionId" type="string">
  Parameter query `subscription_id`. Ditetapkan untuk subscription checkout.
</ParamField>

<ParamField body="licenseKeys" type="string[]">
  Parameter query `license_key`. Ditetapkan saat checkout menyertakan produk license key.
</ParamField>

<ParamField body="customerEmail" type="string">
  Parameter query `email`. Ditetapkan saat checkout mengambil alamat email.
</ParamField>

<ParamField body="raw" type="Record<string, string>">
  Setiap query parameter dari return URL, apa adanya.
</ParamField>

## Verifikasi Pembayaran

<CardGroup cols={2}>
  <Card title="Webhooks" icon="webhook" href="/developer-resources/webhooks">
    Dodo Payments memanggil backend Anda saat pembayaran berhasil atau subscription aktif.
  </Card>

  <Card title="Get Payment Detail" icon="magnifying-glass" href="/api-reference/payments/get-payments-1">
    Cari `paymentId` dengan secret key Anda untuk memeriksa statusnya.
  </Card>
</CardGroup>

Berikan akses hanya setelah salah satu hal berikut mengonfirmasi pembayaran. Jangan hanya mengandalkan `result.status`.

## Kustomisasi Tampilan

Untuk mengubah toolbar, tombol, dan skema warna browser checkout, berikan `customization` ke `start(...)`. Android Custom Tabs dan `SFSafariViewController` di iOS menyediakan kontrol native yang berbeda, sehingga opsi dikelompokkan ke dalam objek `android` dan objek `ios`. Setiap platform hanya membaca objeknya sendiri. Semua field bersifat opsional. Jika field tidak disertakan, platform akan menerapkan nilai defaultnya sendiri.

<AccordionGroup>
  <Accordion title="Android — Custom Tab">
    <ParamField body="toolbarColor" type="string">
      Warna latar toolbar, sebagai string hex: `"#RRGGBB"` atau `"#AARRGGBB"`.
    </ParamField>

    <ParamField body="navigationBarColor" type="string">
      Warna navigation bar, sebagai string hex.
    </ParamField>

    <ParamField body="navigationBarDividerColor" type="string">
      Warna divider di atas navigation bar, sebagai string hex.
    </ParamField>

    <ParamField body="closeButtonStyle" type="'default' | 'back'">
      `default` menampilkan ikon sistem "X". `back` menampilkan panah kembali yang digambar SDK.
    </ParamField>

    <ParamField body="closeButtonPosition" type="'start' | 'end'">
      Sisi toolbar tempat tombol tutup muncul.
    </ParamField>

    <ParamField body="shareButtonEnabled" type="boolean">
      Menampilkan ikon share pada toolbar. `false` menyembunyikannya.
    </ParamField>

    <ParamField body="showTitleEnabled" type="boolean">
      Menampilkan judul halaman di bawah URL pada toolbar.
    </ParamField>

    <ParamField body="urlBarHidingEnabled" type="boolean">
      Menyembunyikan toolbar secara otomatis saat halaman di-scroll.
    </ParamField>

    <ParamField body="bookmarksButtonEnabled" type="boolean">
      Menampilkan "Bookmark this page" di menu overflow.
    </ParamField>

    <ParamField body="downloadsButtonEnabled" type="boolean">
      Menampilkan "Download page" di menu overflow.
    </ParamField>

    <ParamField body="colorScheme" type="'system' | 'light' | 'dark'">
      `light` atau `dark` memaksa tampilan tersebut terlepas dari pengaturan sistem perangkat. `system` mengikuti pengaturan sistem.
    </ParamField>
  </Accordion>

  <Accordion title="iOS — SFSafariViewController">
    <ParamField body="dismissButtonStyle" type="'done' | 'close' | 'cancel'">
      Gaya tombol dismiss. iOS menentukan apakah tombol tersebut dirender sebagai label atau ikon.
    </ParamField>

    <ParamField body="presentationStyle" type="'pageSheet' | 'fullScreen'">
      `pageSheet` (default) menampilkan card yang dapat di-swipe ke bawah oleh customer untuk menutupnya. `fullScreen` memenuhi seluruh layar.
    </ParamField>

    <ParamField body="barCollapsingEnabled" type="boolean">
      Memungkinkan toolbar diciutkan saat halaman di-scroll. Pengaturan ini hanya terlihat pengaruhnya ketika `presentationStyle` adalah `fullScreen`. Dengan `pageSheet`, bar tetap berada di posisinya terlepas dari pengaturan ini.
    </ParamField>

    <ParamField body="colorScheme" type="'system' | 'light' | 'dark'">
      `light` atau `dark` memaksa tampilan tersebut terlepas dari pengaturan sistem perangkat. `system` mengikuti pengaturan sistem.
    </ParamField>
  </Accordion>
</AccordionGroup>

iOS tidak memiliki opsi warna toolbar, karena properti tint `SFSafariViewController` yang mendasarinya sudah deprecated sejak iOS 26.

```typescript theme={null}
const result = await DodoCheckout.start({
  checkoutUrl,
  returnUrl: 'myapp://checkout/return',
  customization: {
    android: { toolbarColor: '#6366F1', closeButtonStyle: 'back' },
    ios: { presentationStyle: 'fullScreen', colorScheme: 'dark' },
  },
});
```

## Error

`start` hanya menolak dengan `CheckoutError` untuk penggunaan yang salah atau kegagalan platform. Baca alasannya dari `error.code`. Customer yang membatalkan atau pembayaran yang ditolak selalu merupakan hasil, bukan rejection.

* `INVALID_CHECKOUT_URL`: `checkoutUrl` bukan URL checkout session `https` (path yang dimulai dengan `/session/`) pada `checkout.dodopayments.com` atau `test.checkout.dodopayments.com`.
* `INVALID_RETURN_URL`: `returnUrl` bukan absolute URL dengan scheme dan host.
* `ALREADY_IN_PROGRESS`: checkout lain sedang berjalan. Hanya satu checkout yang dapat berjalan pada satu waktu.
* `PLATFORM_ERROR`: kegagalan platform yang tidak terduga. SDK juga melaporkan native error yang tidak dikenali dengan kode ini.

## Session yang Ditinggalkan

Native SDK mencatat checkout session saat checkout dimulai, dan menghapus catatan tersebut hanya ketika checkout berakhir dengan `succeeded`, `failed`, atau `expired`. Catatan tersebut tetap ada ketika aplikasi atau JavaScript bundle dihentikan selama checkout, yang menyebabkan promise `start` hilang, serta setelah hasil `cancelled` atau `pending`. Periksa catatan tersebut saat mount berikutnya dan setelah setiap hasil `cancelled` atau `pending`:

```typescript theme={null}
import { DodoCheckout } from '@dodopayments/react-native-checkout';

const abandoned = await DodoCheckout.getAbandonedSession();
if (abandoned) {
  // Ask your backend for the outcome of abandoned.sessionId, and show it.
  // Clear the record only after the outcome is final:
  await DodoCheckout.clearAbandonedSession();
}
```

`abandoned.sessionId` adalah ID checkout session, yang dimulai dengan `cks_`. `abandoned.createdAt` adalah `Date` saat checkout dimulai. Backend Anda dapat mencari session tersebut menggunakan [Dapatkan Checkout Session](/api-reference/checkout-sessions/get-checkouts), yang mengembalikan `payment_id` dan `payment_status`. Sebelum pembayaran mencapai status final, perlakukan sebagai pending, bukan gagal.

## Terkait

<CardGroup cols={2}>
  <Card title="Mobile Integration Guide" icon="mobile" href="/developer-resources/mobile-integration">
    Kontrak yang sama untuk Android, iOS, dan Flutter.
  </Card>

  <Card title="Expo Boilerplate" icon="layer-group" href="/developer-resources/expo-boilerplate">
    Contoh Expo lengkap dengan integrasi checkout.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.