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

# Embedded Quick Buy: Android Integration

> Integrate Embedded Quick Buy in your Android app with the Razorpay Custom UI SDK and show customers their recommended payment instrument.

<div style={{display:"flex",flexWrap:"wrap",alignItems:"center",gap:"0.35rem 0.9rem",border:"1px solid rgba(128,128,128,0.28)",borderRadius:"0.5rem",padding:"0.45rem 0.75rem",margin:"0 0 1.25rem",fontSize:"0.875rem"}}>
  <span style={{fontWeight:600}}>Available in</span>
  <span>🇮🇳 India</span>
</div>

Follow these steps to add [Embedded Quick Buy](/docs/payments/payment-gateway/features/quickbuy/embedded) to your Android app. The integration builds on the [Android Custom UI SDK](/docs/payments/payment-gateway/android-integration/custom/build-integration). You render your own payment screen, and Razorpay processes the payment.

<Info>
  **Already on the Android Custom UI SDK?**

  The steps specific to Quick Buy are [1.3 Create a Customer](#1-3-create-a-customer) and [1.4 Fetch Recommended Instruments](#1-4-fetch-recommended-instruments). All other steps follow the standard Custom UI SDK integration.
</Info>

**1.1** [Add the SDK Dependency](#1-1-add-the-sdk-dependency).

**1.2** [Configure the SDK](#1-2-configure-the-sdk).

**1.3** [Create a Customer](#1-3-create-a-customer). New for Quick Buy.

**1.4** [Fetch Recommended Instruments](#1-4-fetch-recommended-instruments). New for Quick Buy.

**1.5** [Create an Order in Server](#1-5-create-an-order-in-server).

**1.6** [Initialise Razorpay in Your Activity](#1-6-initialise-razorpay-in-your-activity).

**1.7** [Submit Payment](#1-7-submit-payment).

**1.8** [Store Fields in Your Server](#1-8-store-fields-in-your-server).

**1.9** [Verify Payment Signature](#1-9-verify-payment-signature).

**1.10** [Verify Payment Status](#1-10-verify-payment-status).

## 1.1 Add the SDK Dependency

Add the Custom UI SDK to your app-level `build.gradle` file:

```groovy build.gradle theme={null}
dependencies {
    implementation 'com.razorpay:customui:3.9.22'
}
```

Make sure your project can resolve dependencies from Maven Central. The SDK supports `minSdkVersion` 19 and above.

## 1.2 Configure the SDK

### Add Your API Key and Permissions

Add your API Key ID and the internet permission to `AndroidManifest.xml`. The `<queries>` block lets the SDK detect installed UPI apps on Android 11 (API level 30) and above.

```xml AndroidManifest.xml theme={null}
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

  <uses-permission android:name="android.permission.INTERNET" />

  <application>
    <meta-data
        android:name="com.razorpay.ApiKey"
        android:value="YOUR_KEY_ID" />
  </application>

  <!-- Required on Android 11+ (API 30) to detect installed UPI apps -->
  <queries>
    <intent>
      <action android:name="android.intent.action.VIEW" />
      <data android:scheme="upi" />
    </intent>
  </queries>

</manifest>
```

### Add ProGuard Rules

```text proguard-rules.pro theme={null}
-keepclassmembers class * {
    @android.webkit.JavascriptInterface <methods>;
}
-keepattributes JavascriptInterface
-keepattributes *Annotation*
-dontwarn com.razorpay.**
-keep class com.razorpay.** {*;}
-optimizations !method/inlining/*
-keepclasseswithmembers class * {
  public void onPayment*(...);
}
```

### Add a WebView

The SDK uses a WebView to complete flows such as card 3DS and bank OTP pages. Add a hidden WebView to your payment Activity's layout and register it with the SDK. Make it visible only while the payment is being submitted.

```java Java theme={null}
WebView webview = findViewById(R.id.payment_webview);
webview.setVisibility(View.GONE); // set to VISIBLE only during submit()
razorpay.setWebView(webview);
```

<Info>
  **Handy Tips**

  Make sure the device supports TLS v1.1 or v1.2 for PCI compliance. Never log or store card details on the device.
</Info>

## 1.3 Create a Customer

Create a customer on your server with the [Customers API](/docs/api/customers/create). You can do this asynchronously, for example when you collect the customer's details. Use the `customer_id` returned in the response to fetch recommended instruments in [step 1.4](#1-4-fetch-recommended-instruments).

<CodeGroup>
  ```bash Request theme={null}
  curl -u [YOUR_KEY_ID]:[YOUR_KEY_SECRET] \
  -X POST https://api.razorpay.com/v1/customers \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Gaurav Kumar",
    "contact": "9123456780",
    "email": "gaurav.kumar@example.com",
    "fail_existing": "0",
    "notes": {
      "notes_key_1": "Tea, Earl Grey, Hot",
      "notes_key_2": "Tea, Earl Grey… decaf."
    }
  }'
  ```

  ```json Response theme={null}
  {
    "id": "cust_1Aa00000000004",
    "entity": "customer",
    "name": "Gaurav Kumar",
    "email": "gaurav.kumar@example.com",
    "contact": "9123456780",
    "gstin": null,
    "notes": {
      "notes_key_1": "Tea, Earl Grey, Hot",
      "notes_key_2": "Tea, Earl Grey… decaf."
    },
    "created_at": 1234567890
  }
  ```
</CodeGroup>

## 1.4 Fetch Recommended Instruments

Call `getRecommendedInstruments()` to get the customer's recommended payment instruments.

* The response contains up to 3 instruments, ranked by how likely the customer is to complete the payment. `items[0]` is the strongest recommendation.
* The SDK checks which UPI apps are installed on the device and returns only those.
* The response includes the logos you need to render the Quick Buy button: `app_logo`, `network_logo_url` and `issuer_logo_url`.
* Create an order first and pass its `order_id`, so that all instrument types are eligible. Without an `order_id`, the response is limited to UPI intent apps and `amount` and `currency` become mandatory.

```java Java theme={null}
JSONObject options = new JSONObject();
options.put("order_id", "order_xxxxxx");     // recommended
options.put("customer_id", "cust_xxxxxx");   // from step 1.3
options.put("amount", 100);                  // mandatory if no order_id
options.put("currency", "INR");              // mandatory if no order_id
options.put("contact", "8050981760");        // pass if no customer_id

razorpay.getRecommendedInstruments(options, new RecommendedInstrumentsCallback() {
    @Override
    public void onInstrumentsReceived(JSONObject response) {
        JSONArray items = response
                .getJSONObject("get_recommended_instruments")
                .getJSONArray("items");

        for (int i = 0; i < items.length(); i++) {
            JSONObject item = items.getJSONObject(i);
            String method = item.getString("method");

            if ("card".equals(method)) {
                JSONObject card = item.getJSONObject("card");
                Log.d(TAG, card.getString("last4"));                  // display only
            }

            if ("upi".equals(method)) {
                JSONObject upi = item.getJSONObject("upi");
                Log.d(TAG, upi.getString("app"));                     // for example, gpay
                Log.d(TAG, upi.getString("upi_app_package_name"));    // Android package name
                Log.d(TAG, upi.getString("app_logo"));                // CDN logo URL
            }
        }
    }

    @Override
    public void onError(String error) {
        // Fall back to Standard Checkout
    }
});
```

<Warning>
  **Watch Out!**

  * Always show a **Change payment method** option next to the Quick Buy button. It should open the full Razorpay Checkout, as per the [Android Standard Checkout integration](/docs/payments/payment-gateway/android-integration/standard/integration-steps).
  * If the response has no instruments, or the call fails, show your regular checkout instead of the Quick Buy button.
</Warning>

#### Sample Response

```json Response theme={null}
{
  "actions": ["get_recommended_instruments"],
  "get_recommended_instruments": {
    "entity": "collection",
    "count": 3,
    "items": [
      {
        "method": "card",
        "token": "token_Hf7vKlM2NpQrSt",
        "card": {
          "last4": "4242",
          "network": "Visa",
          "issuer": "HDFC",
          "type": "debit",
          "sub_type": "consumer",
          "international": false,
          "network_logo_url": "https://cdn.razorpay.com/app/visa.svg",
          "issuer_logo_url": "https://cdn.razorpay.com/app/hdfc.svg"
        }
      },
      {
        "method": "upi",
        "upi": {
          "flow": "intent",
          "app": "gpay",
          "upi_app_package_name": "com.google.android.apps.nbu.paisa.user",
          "app_logo": "https://cdn.razorpay.com/app/gpay.svg"
        }
      },
      {
        "method": "upi",
        "upi": {
          "flow": "intent",
          "app": "phonepe",
          "upi_app_package_name": "com.phonepe.app",
          "app_logo": "https://cdn.razorpay.com/app/phonepe.svg"
        }
      }
    ]
  }
}
```

#### Response Parameters

| Parameter | Type | Description | How to use it |
| - | - | - | - |
| `actions` | array | Always `get_recommended_instruments`. | Check that the response matches the action you called. |
| `get_recommended_instruments.entity` | string | Always `collection`. | Standard Razorpay collection identifier. |
| `get_recommended_instruments.count` | integer | Number of instruments in `items`. Maximum 3. | Check before you render the button. |
| `get_recommended_instruments.items` | array | Recommended instruments in order. Index 0 is the strongest recommendation. | Render the Quick Buy button from `items[0]`. |
| `items.method` | string | `card` or `upi`. | Decides which UI to render and which payment fields to send. |
| `token` | string | Razorpay token ID of the saved card. | Pass as `token` when you submit the payment. |
| `card.last4` | string | Last 4 digits of the card. For display only. | Render a masked label, such as **HDFC Debit ••••4242**. Never pass it to payment APIs. |
| `card.network` | string | `Visa`, `MasterCard`, `RuPay`, `Amex` or `Diners`. | Show the network name. |
| `card.issuer` | string | 4-character issuer code. For example, `HDFC`, `ICIC` or `SBIN`. | Show the issuer name. |
| `card.type` | string | `credit`, `debit` or `prepaid`. | Show the card type on the button. |
| `card.sub_type` | string | `consumer`, `business` or `unknown`. | Optional. Use it if business cards need a different treatment. |
| `card.international` | boolean | `true` if the card is international. | Flag international cards if needed. |
| `card.network_logo_url` | string | CDN-hosted card network logo. | Load directly into an `ImageView`. |
| `card.issuer_logo_url` | string | CDN-hosted issuing bank logo. | Load directly into an `ImageView`. |
| `upi.flow` | string | Always `intent`. | Confirms the UPI flow. |
| `upi.app` | string | Short name of the UPI app. For example, `gpay`, `phonepe`, `paytm` or `bhim`. | Show on the button. |
| `upi.upi_app_package_name` | string | Android package name of the UPI app. For example, `com.google.android.apps.nbu.paisa.user`. | Pass as `upi_app_package_name` when you submit the payment. |
| `upi.app_logo` | string | CDN-hosted UPI app logo. | Show on the button. |

## 1.5 Create an Order in Server

Create an order on your server using the [Orders API](/docs/api/orders/create) when the customer taps the Quick Buy button, or earlier if you pass the `order_id` in [step 1.4](#1-4-fetch-recommended-instruments).

<Warning>
  **Watch Out!**

  Create an order for every payment, server-side, using your API Key ID and secret. Payments made without an `order_id` cannot be captured and are automatically refunded.
</Warning>

<CodeGroup>
  ```bash Request theme={null}
  curl -X POST https://api.razorpay.com/v1/orders \
  -u [YOUR_KEY_ID]:[YOUR_KEY_SECRET] \
  -H 'content-type:application/json' \
  -d '{
    "amount": 50000,
    "currency": "INR",
    "customer_id": "cust_1Aa00000000004",
    "receipt": "rcptid_11",
    "notes": {
      "key1": "value3",
      "key2": "value2"
    }
  }'
  ```

  ```json Response theme={null}
  {
    "id": "order_IluGWxBm9U8zJ8",
    "entity": "order",
    "amount": 50000,
    "amount_paid": 0,
    "amount_due": 50000,
    "currency": "INR",
    "receipt": "rcptid_11",
    "status": "created",
    "attempts": 0,
    "notes": [],
    "created_at": 1642662092
  }
  ```
</CodeGroup>

#### Request Parameters

`amount` *mandatory*
: `integer` Payment amount in the smallest currency sub-unit. For example, pass `50000` for ₹500.

`currency` *mandatory*
: `string` The 3-letter ISO currency code. For example, `INR`.

`customer_id` *mandatory*
: `string` The customer ID returned in [step 1.3](#1-3-create-a-customer).

`receipt` *optional*
: `string` Your receipt number for the order. Maximum 40 characters.

`notes` *optional*
: `object` Key-value pairs for additional information. Maximum 15 pairs of 256 characters each.

`partial_payment` *optional*
: `boolean` Set to `true` to accept partial payments. Defaults to `false`.

`first_payment_min_amount` *optional*
: `integer` Minimum amount for the first partial payment. Use only when `partial_payment` is `true`.

## 1.6 Initialise Razorpay in Your Activity

Create the SDK instance in your payment Activity. The SDK reads the key from the manifest ([step 1.2](#1-2-configure-the-sdk)), or you can pass it in code.

```java Java theme={null}
import com.razorpay.Razorpay;

Razorpay razorpay = new Razorpay(this);                 // uses com.razorpay.ApiKey from the manifest
// OR
Razorpay razorpay = new Razorpay(this, "YOUR_KEY_ID");  // sets the key in code

// Register the hidden WebView from step 1.2
razorpay.setWebView(findViewById(R.id.payment_webview));
```

## 1.7 Submit Payment

When the customer taps the Quick Buy button, build the payment data as a `JSONObject` and pass it to `razorpay.submit()`. The result is returned to `PaymentResultWithDataListener`:

* `onPaymentSuccess` for a successful payment.
* `onPaymentError` for a failed payment.

#### Common Parameters

`order_id` *mandatory*
: `string` The order ID created in [step 1.5](#1-5-create-an-order-in-server).

`amount` *mandatory*
: `integer` Payment amount in the smallest currency sub-unit.

`currency` *mandatory*
: `string` The 3-letter ISO currency code. For example, `INR`.

`email` *mandatory*
: `string` Customer's email address.

`contact` *mandatory*
: `string` Customer's phone number.

`method` *mandatory*
: `string` Payment method. Possible values: `upi`, `card`, `netbanking`, `wallet` or `emi`.

`notes` *optional*
: `object` Key-value pairs for additional information. Maximum 15 pairs of 256 characters each.

<Tabs>
  <Tab title="UPI Intent">
    Pass the `upi_app_package_name` returned by `getRecommendedInstruments()` in [step 1.4](#1-4-fetch-recommended-instruments).

    ```java Java theme={null}
    JSONObject data = new JSONObject();
    data.put("amount", 29935);
    data.put("currency", "INR");
    data.put("order_id", "order_DgZ26rHjbzLLY2");
    data.put("email", "gaurav.kumar@example.com");
    data.put("contact", "+919876543210");
    data.put("method", "upi");
    data.put("_[flow]", "intent");
    data.put("upi_app_package_name", "com.google.android.apps.nbu.paisa.user");

    findViewById(R.id.payment_webview).setVisibility(View.VISIBLE);
    razorpay.submit(data, resultListener);
    ```
  </Tab>

  <Tab title="Saved Card">
    Pass the `token` returned by `getRecommendedInstruments()` in [step 1.4](#1-4-fetch-recommended-instruments) and collect only the CVV from the customer.

    ```java Java theme={null}
    JSONObject data = new JSONObject();
    data.put("amount", 29935);
    data.put("currency", "INR");
    data.put("order_id", "order_DgZ26rHjbzLLY2");
    data.put("email", "gaurav.kumar@example.com");
    data.put("contact", "+919876543210");
    data.put("method", "card");
    data.put("token", "token_Hf7vKlM2NpQrSt");
    data.put("card[cvv]", "100");
    razorpay.submit(data, resultListener);
    ```
  </Tab>

  <Tab title="Netbanking">
    ```java Java theme={null}
    JSONObject data = new JSONObject();
    data.put("amount", 29935);
    data.put("currency", "INR");
    data.put("order_id", "order_DgZ26rHjbzLLY2");
    data.put("email", "gaurav.kumar@example.com");
    data.put("contact", "+919876543210");
    data.put("method", "netbanking");
    data.put("bank", "SBIN");
    razorpay.submit(data, resultListener);
    ```
  </Tab>

  <Tab title="Wallet">
    ```java Java theme={null}
    JSONObject data = new JSONObject();
    data.put("amount", 29935);
    data.put("currency", "INR");
    data.put("order_id", "order_DgZ26rHjbzLLY2");
    data.put("email", "gaurav.kumar@example.com");
    data.put("contact", "+919876543210");
    data.put("method", "wallet");
    data.put("wallet", "mobikwik");
    razorpay.submit(data, resultListener);
    ```
  </Tab>
</Tabs>

#### Handle the Result

```java Java theme={null}
PaymentResultWithDataListener resultListener = new PaymentResultWithDataListener() {
    @Override
    public void onPaymentSuccess(String razorpayPaymentId, PaymentData paymentData) {
        // Send paymentData.getPaymentId(), paymentData.getOrderId() and
        // paymentData.getSignature() to your server for verification (step 1.9)
    }

    @Override
    public void onPaymentError(int code, String description) {
        // For example, Checkout.NETWORK_ERROR or Checkout.PAYMENT_CANCELED
    }
};
```

## 1.8 Store Fields in Your Server

A successful payment returns these fields through `PaymentData`. Store them on your server and verify the signature in the next step.

```json Success Response theme={null}
{
  "razorpay_payment_id": "pay_29QQoUBi66xm2f",
  "razorpay_order_id": "order_9A33XWu170gUtm",
  "razorpay_signature": "9ef4dffbfd84f1318f6739a3ce19f9d85851857ae648f114332d8401e0949a3d"
}
```

`razorpay_payment_id`
: `string` Unique identifier of the payment. Returned only for successful payments.

`razorpay_order_id`
: `string` Unique identifier of the order.

`razorpay_signature`
: `string` Signature used to verify that the payment is authentic.

## 1.9 Verify Payment Signature

Verify the signature on your server to confirm the payment is authentic. This step is mandatory. Never verify the signature in the app.

1. Use the `order_id` stored on your server. Do not use the `razorpay_order_id` returned to the app.
2. Create an HMAC-SHA256 hex digest of `order_id + "|" + razorpay_payment_id` using your API key secret.
3. If the digest matches `razorpay_signature`, the payment is authentic.

```text Pseudocode theme={null}
generated_signature = hmac_sha256(order_id + "|" + razorpay_payment_id, secret);

if (generated_signature == razorpay_signature) {
    // payment is authentic
}
```

```java Java (server-side) theme={null}
RazorpayClient razorpay = new RazorpayClient("[YOUR_KEY_ID]", "[YOUR_KEY_SECRET]");
String secret = "[YOUR_KEY_SECRET]";

JSONObject options = new JSONObject();
options.put("razorpay_order_id", "order_IEIaMR65cu6nz3");
options.put("razorpay_payment_id", "pay_IH4NVgf4Dreq1l");
options.put("razorpay_signature", "0d4e745a1838664ad6c9c9902212a32d627d68e917290b0ad5f08ff4561bc50f");

boolean status = Utils.verifyPaymentSignature(options, secret);
```

## 1.10 Verify Payment Status

Confirm that the payment status is `captured`. You can track it in 3 ways:

* **Dashboard**: Log in to the Dashboard and go to **Transactions** → **Payments**. A successful payment has a payment ID and the status **Captured**.
* **Webhooks**: Subscribe to [payment webhook events](/docs/webhooks/payments) for real-time updates.
* **API**: Poll the [Fetch a Payment API](/docs/api/payments/fetch-with-id) with the `razorpay_payment_id`.

<Info>
  **Handy Tips**

  Use [Payment Capture Settings](/docs/payments/payments/capture-settings) to capture payments automatically.
</Info>

## Next Steps

* [Test your integration](/docs/payments/payment-gateway/android-integration/custom/test-integration) in Test Mode.
* Complete the [go-live checklist](/docs/payments/payment-gateway/android-integration/custom/go-live-checklist).
* Replace your test API keys with live keys when you are ready to go live.

## Related Information

* [Embedded Quick Buy](/docs/payments/payment-gateway/features/quickbuy/embedded)
* [Embedded Quick Buy FAQs](/docs/payments/payment-gateway/features/quickbuy/embedded/faqs)
* [Android Custom UI SDK Integration](/docs/payments/payment-gateway/android-integration/custom/build-integration)
