---
title: "Cấp mức độ truy cập thủ công"
description: "Mở khóa các tính năng trả phí thủ công cho người dùng hoặc nhóm người dùng cụ thể"
---

Nếu bạn cần **mở khóa tính năng premium thủ công** cho người dùng hoặc nhóm người dùng cụ thể, bạn có thể thực hiện điều này thông qua Adapty API. Cách này hữu ích cho các chiến dịch khuyến mãi, cấp quyền truy cập cho nhà đầu tư, hoặc các trường hợp hỗ trợ khách hàng đặc biệt.

Trong hướng dẫn này, bạn sẽ tìm hiểu cách xác định người dùng và cấp mức độ truy cập cho họ theo cách lập trình.

#### Một số trường hợp sử dụng tiêu biểu

- **Mã khuyến mãi**: Khi người dùng nhập mã khuyến mãi hợp lệ trong ứng dụng, tự động cấp cho họ quyền truy cập vào các tính năng premium.

- **Quyền truy cập cho nhà đầu tư/beta tester**: Cấp quyền truy cập premium cho nhà đầu tư hoặc beta tester bằng cách kiểm tra các thuộc tính tùy chỉnh của họ.

:::note
**Mã khuyến mãi Google Play**: Giao dịch mua được thực hiện bằng cách đổi mã khuyến mãi Google Play có thể không có `orderId`. Tính năng xác thực sản phẩm mua một lần (non-subscription) của Adapty yêu cầu phải có `orderId`, do đó các giao dịch đổi mã này không được xác thực hoặc cấp quyền tự động. Hãy cấp quyền truy cập thủ công theo các bước bên dưới — Server-Side API không phụ thuộc vào `orderId`.
:::

## Bước 1. Xác định người dùng \{#step-1-identify-users\}

Adapty sử dụng `customer_user_id` để nhận diện người dùng trên các nền tảng và thiết bị khác nhau. Điều này rất quan trọng để đảm bảo người dùng giữ được quyền truy cập sau khi cài đặt lại ứng dụng hoặc đổi thiết bị.

Bạn chỉ cần tạo ID này một lần. Khi người dùng đăng ký lần đầu từ ứng dụng, bạn có thể truyền customer user ID của họ trong quá trình kích hoạt SDK, hoặc dùng phương thức `identify` nếu SDK đã được kích hoạt trước khi đăng ký.

:::important
Nếu bạn xác định người dùng mới sau khi kích hoạt SDK, SDK sẽ tạo một hồ sơ người dùng ẩn danh trước (SDK không thể hoạt động mà không có hồ sơ). Khi bạn gọi `identify` với customer user ID, một hồ sơ người dùng mới sẽ được tạo.

Hành vi này là bình thường và sẽ không ảnh hưởng đến độ chính xác của analytics. Đọc thêm [tại đây](ios-quickstart-identify).
:::

<Tabs groupId="current-os" queryString>
<TabItem value="swift" label="iOS" default>
```swift showLineNumbers
do {
    try await Adapty.identify("YOUR_USER_ID") // Unique for each user
} catch {
    // handle the error
}
```
</TabItem>
<TabItem value="swift-callback" label="iOS (Swift-Callback)" default>

```swift showLineNumbers
// User IDs must be unique for each user
Adapty.identify("YOUR_USER_ID") { error in
    if let error {
        // handle the error
    }
}
```
</TabItem>
<TabItem value="android" label="Android (Kotlin)" default>
```kotlin showLineNumbers
Adapty.identify("YOUR_USER_ID") { error -> // Unique for each user
    if (error == null) {
        // successful identify
    }
}
```
</TabItem>
<TabItem value="java" label="Android (Java)" default>
```java showLineNumbers
// User IDs must be unique for each user
Adapty.identify("YOUR_USER_ID", error -> {
    if (error == null) {
        // successful identify
    }
});
```
</TabItem>
<TabItem value="react-native" label="React Native" default>
```typescript showLineNumbers
try {
    await adapty.identify("YOUR_USER_ID"); // Unique for each user
    // successfully identified
} catch (error) {
    // handle the error
}
```
</TabItem>

<TabItem value="flutter" label="Flutter" default>
```dart showLineNumbers
try {
  await Adapty().identify(customerUserId); // Unique for each user
} on AdaptyError catch (adaptyError) {
  // handle the error
} catch (e) {
}
```
</TabItem>

<TabItem value="unity" label="Unity" default>
```csharp showLineNumbers
Adapty.Identify("YOUR_USER_ID", (error) => { // Unique for each user
  if(error == null) {
    // successful identify
  }
});
```
</TabItem>

<TabItem value="kmp" label="Kotlin Multiplatform" default>
```kotlin showLineNumbers
Adapty.identify("YOUR_USER_ID") // Unique for each user
    .onSuccess {
        // successful identify
    }
    .onError { error ->
        // handle the error
    }
```
</TabItem>

<TabItem value="capacitor" label="Capacitor" default>
```typescript showLineNumbers
try {
  await adapty.identify({ customerUserId: "YOUR_USER_ID" });
  // successfully identified
} catch (error) {
  // handle the error
}
```
</TabItem>
</Tabs>

## Bước 2. Cấp mức độ truy cập qua API \{#step-2-grant-access-level-via-api\}

Sau khi người dùng được xác định bằng `customer_user_id`, bạn có thể cấp mức độ truy cập cho họ thông qua server-side API. Lệnh gọi API này sẽ cấp mức độ truy cập cho người dùng, cho phép họ sử dụng các tính năng trả phí mà không cần thực sự thanh toán.

Xem tài liệu tham chiếu đầy đủ về phương thức [tại đây](api-adapty/operations/grantAccessLevel).

:::tip
Bạn có thể kiểm soát quyền truy cập của người dùng bằng cách thêm thuộc tính tùy chỉnh (ví dụ: Beta tester hoặc Investor) trong Adapty dashboard.
Khi ứng dụng khởi chạy, [kiểm tra thuộc tính này trong hồ sơ người dùng](subscription-status) để cấp quyền truy cập tự động.
Để cập nhật quyền truy cập, chỉ cần thay đổi thuộc tính trong dashboard.
:::

```bash
curl --request POST \
  --url https://api.adapty.io/api/v2/server-side-api/purchase/profile/grant/access-level/ \
  --header 'Accept: application/json' \
  --header 'Authorization: Api-Key YOUR_SECRET_API_KEY' \
  --header 'Content-Type: application/json' \
  --header 'adapty-customer-user-id: CUSTOMER_USER_ID' \
  --data '{
  "access_level_id": "YOUR_ACCESS_LEVEL"
}'
```

## Bước 3. Xác minh quyền truy cập trong ứng dụng \{#step-3-verify-access-in-the-app\}

Sau khi cấp quyền truy cập qua API, hồ sơ người dùng sẽ được cập nhật tự động. Lấy hồ sơ của họ để kiểm tra trạng thái gói đăng ký và mở khóa các tính năng premium.

<Tabs groupId="current-os" queryString>
<TabItem value="swift" label="iOS" default>

```swift showLineNumbers
do {
    let profile = try await Adapty.getProfile()

    if profile.accessLevels["YOUR_ACCESS_LEVEL_ID"]?.isActive ?? false {
        // grant access to premium features
    }
} catch {
// handle the error
}
```

</TabItem>

<TabItem value="swift-callback" label="iOS (Swift-Callback)" default>

```swift showLineNumbers
Adapty.getProfile { result in
    if let profile = try? result.get() {
        // check the access
        if profile.accessLevels["YOUR_ACCESS_LEVEL_ID"]?.isActive ?? false {
            // grant access to premium features
        }
    }
}
```

</TabItem>

<TabItem value="android" label="Android (Kotlin)" default>

```kotlin showLineNumbers
Adapty.getProfile { result ->
    when (result) {
        is AdaptyResult.Success -> {
            val profile = result.value
            // check the access
            if (profile.accessLevels["YOUR_ACCESS_LEVEL_ID"]?.isActive == true) {
                // grant access to premium features
            }
        }
        is AdaptyResult.Error -> {
            val error = result.error
            // handle the error
        }
    }
}
```

</TabItem>

<TabItem value="java" label="Android (Java)" default>

```java showLineNumbers
Adapty.getProfile(result -> {
    if (result instanceof AdaptyResult.Success) {
        AdaptyProfile profile = ((AdaptyResult.Success<AdaptyProfile>) result).getValue();
        // check the access
        if (profile.getAccessLevels().get("YOUR_ACCESS_LEVEL_ID") != null && profile.getAccessLevels().get("YOUR_ACCESS_LEVEL_ID").getIsActive()) {
            // grant access to premium features
        }

    } else if (result instanceof AdaptyResult.Error) {
        AdaptyError error = ((AdaptyResult.Error) result).getError();
        // handle the error
    }
});
```

</TabItem>

<TabItem value="react-native" label="React Native" default>

```typescript showLineNumbers
try {
    const profile = await adapty.getProfile();
    // check the access
    if (profile.accessLevels["YOUR_ACCESS_LEVEL_ID"]?.isActive) {
        // grant access to premium features
    }
} catch (error) {
  // handle the error
}
```

</TabItem>

<TabItem value="flutter" label="Flutter" default>

```dart showLineNumbers
try {
  final profile = await Adapty().getProfile();
  // check the access
  if (profile.accessLevels["YOUR_ACCESS_LEVEL_ID"]?.isActive ?? false) {
      // grant access to premium features
  }
} on AdaptyError catch (adaptyError) {
  // handle the error
} catch (e) {
}
```

</TabItem>

<TabItem value="unity" label="Unity" default>

```csharp showLineNumbers
Adapty.GetProfile((profile, error) => {
  if (error != null) {
    // handle the error
    return;
  }

  // check the access
  if (profile.AccessLevels["YOUR_ACCESS_LEVEL_ID"]?.IsActive ?? false) {
      // grant access to premium features
  }
});
```

</TabItem>

<TabItem value="kmp" label="Kotlin Multiplatform" default>

```kotlin showLineNumbers
Adapty.getProfile()
    .onSuccess { profile ->
        // check the access
        if (profile.accessLevels["YOUR_ACCESS_LEVEL_ID"]?.isActive == true) {
            // grant access to premium features
        }
    }
    .onError { error ->
        // handle the error
    }
```

</TabItem>

<TabItem value="capacitor" label="Capacitor" default>

```typescript showLineNumbers
try {
  const profile = await adapty.getProfile();
  // check the access
  if (profile.accessLevels["YOUR_ACCESS_LEVEL_ID"]?.isActive) {
      // grant access to premium features
  }
} catch (error) {
  // handle the error
}
```

</TabItem>
</Tabs>