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

# Entity Handles

> Manage PFEntityHandle credentials, ref counting, and entity token lifetime for authenticated player and title calls in the PlayFab C SDK.

A **PFEntityHandle** is your primary credential for making PlayFab service calls. It represents an authenticated entity—either a player (title\_player\_account) or a title—and holds the entity token the SDK needs to authorize requests. Every login or authentication call returns a **PFEntityHandle**, and every service call requires one.

## Getting an entity handle

You don't create entity handles directly. Instead, you get one as an output of a successful login or authentication call.

**Player login (Windows example):**

```cpp theme={null}
PFAuthenticationLoginWithXUserRequest request{};
request.createAccount = true;
request.user = userHandle; // XUserHandle from XUserAddAsync

XAsyncBlock async{};
HRESULT hr = PFAuthenticationLoginWithXUserAsync(serviceConfigHandle, &request, &async);
hr = XAsyncGetStatus(&async, true);

PFEntityHandle entityHandle{ nullptr };
size_t bufferSize{};
hr = PFAuthenticationLoginWithXUserGetResultSize(&async, &bufferSize);

std::vector<char> loginResultBuffer(bufferSize);
PFAuthenticationLoginResult const* loginResult{};
hr = PFAuthenticationLoginWithXUserGetResult(
    &async, &entityHandle,
    loginResultBuffer.size(), loginResultBuffer.data(),
    &loginResult, nullptr);
```

**Title entity (server):**

Title entities authenticate with a secret key instead of a user credential. The returned **PFEntityHandle** works the same way, but it represents the title rather than a player. See [Accessing PlayFab with a title entity](/services/playfab/sdks/c/server) for details.

## Handle ownership and ref counting

**PFEntityHandle** is ref-counted. When you receive a handle from a login call, you own one reference. You can create additional references with [**PFEntityDuplicateHandle**](/services/playfab/api-references/c/pfentity/functions/pfentityduplicatehandle) and release them with [**PFEntityCloseHandle**](/services/playfab/api-references/c/pfentity/functions/pfentityclosehandle). The underlying entity object is destroyed only when the last reference is closed.

**Rules:**

* Every call to a login `GetResult` function or **PFEntityDuplicateHandle** gives you a handle you must close.
* Closing a handle doesn't invalidate other handles to the same entity.
* Close all handles before calling [**PFServicesUninitializeAsync**](/services/playfab/api-references/c/pfservices/functions/pfservicesuninitializeasync).

```cpp theme={null}
// Duplicate a handle for another component
PFEntityHandle secondHandle{ nullptr };
HRESULT hr = PFEntityDuplicateHandle(entityHandle, &secondHandle);

// Both handles are independently valid
// ...

// Each owner closes their own handle
PFEntityCloseHandle(secondHandle);
PFEntityCloseHandle(entityHandle);
```

## Getting entity info

### Entity key

The entity key identifies the entity (its type and ID). Use the two-call pattern: get the size first, then get the data.

```cpp theme={null}
size_t size{};
HRESULT hr = PFEntityGetEntityKeySize(entityHandle, &size);

std::vector<char> buffer(size);
PFEntityKey const* entityKey{};
hr = PFEntityGetEntityKey(entityHandle, buffer.size(), buffer.data(), &entityKey, nullptr);

// entityKey->type is "title_player_account" for players
// entityKey->id is the entity's unique ID
```

### Entity token

The entity token authorizes service calls. The SDK manages tokens automatically, but you can retrieve the current one if needed.

```cpp theme={null}
XAsyncBlock async{};
HRESULT hr = PFEntityGetEntityTokenAsync(entityHandle, &async);
hr = XAsyncGetStatus(&async, true);

size_t size{};
hr = PFEntityGetEntityTokenResultSize(&async, &size);

std::vector<char> buffer(size);
const PFEntityToken* entityToken{};
hr = PFEntityGetEntityTokenResult(&async, buffer.size(), buffer.data(), &entityToken, nullptr);

// entityToken->token is the token string
// entityToken->expiration is the optional expiration time (UTC)
```

### Checking entity type

Use [**PFEntityIsTitlePlayer**](/services/playfab/api-references/c/pfentity/functions/pfentityistitleplayer) as a quick check instead of inspecting the entity key type string:

```cpp theme={null}
bool isTitlePlayer{};
HRESULT hr = PFEntityIsTitlePlayer(entityHandle, &isTitlePlayer);
```

## Player entities vs. title entities

Both player and title entities use **PFEntityHandle**, but they differ in what they can do:

|                                                                                                          | Player entity                                            | Title entity                                  |
| -------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- | --------------------------------------------- |
| **How you get it**                                                                                       | Login call (e.g., `PFAuthenticationLoginWithXUserAsync`) | `PFAuthenticationGetEntityWithSecretKeyAsync` |
| **Entity type**                                                                                          | `title_player_account`                                   | `title`                                       |
| [**PFEntityIsTitlePlayer**](/services/playfab/api-references/c/pfentity/functions/pfentityistitleplayer) | Returns `true`                                           | Returns `false`                               |
| [**PFEntityGetSecretKey**](/services/playfab/api-references/c/pfentity/functions/pfentitygetsecretkey)   | Fails with `E_PF_NOSECRETKEY`                            | Returns the secret key                        |
| **Available APIs**                                                                                       | Client-prefixed and non-prefixed APIs                    | Server-prefixed and non-prefixed APIs         |

Non-prefixed APIs (e.g., Inventory, Leaderboards, Data) can generally be called by both player and title entities unless otherwise noted in their documentation. Client-prefixed APIs are player-only, and Server-prefixed APIs are title-only.

**PFEntityGetSecretKey** retrieves the secret key associated with a title entity. It fails for player entities because they don't have one.

```cpp theme={null}
size_t keySize{};
HRESULT hr = PFEntityGetSecretKeySize(entityHandle, &keySize);
if (SUCCEEDED(hr))
{
    std::vector<char> secretKey(keySize);
    hr = PFEntityGetSecretKey(entityHandle, secretKey.size(), secretKey.data(), nullptr);
}
```

<Note>
  **PFEntityGetSecretKey** is only available on Windows, Linux, and macOS platforms.
</Note>

## Token event handlers

The SDK automatically refreshes entity tokens before they expire. You can register callbacks to observe these events.

### Token expired

If automatic refresh fails (for example, the original login credential is no longer valid), the SDK fires the token-expired event. Register a handler to provide a new credential and retry the login.

```cpp theme={null}
PFRegistrationToken registrationToken{};
HRESULT hr = PFEntityRegisterTokenExpiredEventHandler(
    nullptr,  // XTaskQueueHandle, or nullptr for default
    nullptr,  // optional context
    [](void* ctx, PFEntityKey const* entityKey)
    {
        // Re-authenticate the player with a fresh credential
        // See relogin.md for a complete example
    },
    &registrationToken);
```

### Token refreshed

Register a token-refreshed handler if you want to know when the SDK successfully refreshes a token in the background. This is informational—you don't need to take any action.

```cpp theme={null}
PFRegistrationToken registrationToken{};
HRESULT hr = PFEntityRegisterTokenRefreshedEventHandler(
    nullptr,  // XTaskQueueHandle, or nullptr for default
    nullptr,  // optional context
    [](void* ctx, PFEntityKey const* entityKey, const PFEntityToken* newToken)
    {
        // Log the refresh or update cached token references
    },
    &registrationToken);
```

### When to register and unregister

* **Register** handlers early, right after SDK initialization and before login. This ensures you don't miss any events.
* **Unregister** handlers during shutdown, before you close entity handles.

```cpp theme={null}
PFEntityUnregisterTokenExpiredEventHandler(expiredRegistrationToken);
PFEntityUnregisterTokenRefreshedEventHandler(refreshedRegistrationToken);
```

For a complete walkthrough of token expiration handling and relogin, see [Handling Token Expiration](/services/playfab/sdks/c/relogin).

## Utility accessors

You can retrieve the API endpoint and title ID from an entity handle. These come from the **PFServiceConfigHandle** that was used during login.

```cpp theme={null}
// Get API endpoint
size_t endpointSize{};
HRESULT hr = PFEntityGetAPIEndpointSize(entityHandle, &endpointSize);

std::vector<char> endpoint(endpointSize);
hr = PFEntityGetAPIEndpoint(entityHandle, endpoint.size(), endpoint.data(), nullptr);

// Get title ID
size_t titleIdSize{};
hr = PFEntityGetTitleIdSize(entityHandle, &titleIdSize);

std::vector<char> titleId(titleIdSize);
hr = PFEntityGetTitleId(entityHandle, titleId.size(), titleId.data(), nullptr);
```

## Complete example

This example demonstrates creating, duplicating, querying, and closing entity handles:

```cpp theme={null}
#include <playfab/core/PFEntity.h>
#include <playfab/services/PFServices.h>

void EntityHandleExample(PFServiceConfigHandle serviceConfigHandle, XUserHandle userHandle)
{
    //
    // Log in and get an entity handle
    //
    PFAuthenticationLoginWithXUserRequest request{};
    request.createAccount = true;
    request.user = userHandle;

    XAsyncBlock asyncLogin{};
    HRESULT hr = PFAuthenticationLoginWithXUserAsync(serviceConfigHandle, &request, &asyncLogin);
    hr = XAsyncGetStatus(&asyncLogin, true);

    PFEntityHandle entityHandle{ nullptr };
    size_t resultSize{};
    hr = PFAuthenticationLoginWithXUserGetResultSize(&asyncLogin, &resultSize);

    std::vector<char> loginBuffer(resultSize);
    PFAuthenticationLoginResult const* loginResult{};
    hr = PFAuthenticationLoginWithXUserGetResult(
        &asyncLogin, &entityHandle,
        loginBuffer.size(), loginBuffer.data(),
        &loginResult, nullptr);

    //
    // Register token event handlers
    //
    PFRegistrationToken expiredToken{};
    hr = PFEntityRegisterTokenExpiredEventHandler(nullptr, nullptr,
        [](void* ctx, PFEntityKey const* entityKey)
        {
            // Handle re-authentication
        }, &expiredToken);

    PFRegistrationToken refreshedToken{};
    hr = PFEntityRegisterTokenRefreshedEventHandler(nullptr, nullptr,
        [](void* ctx, PFEntityKey const* entityKey, const PFEntityToken* newToken)
        {
            // Log token refresh
        }, &refreshedToken);

    //
    // Duplicate the handle for a subsystem
    //
    PFEntityHandle subsystemHandle{ nullptr };
    hr = PFEntityDuplicateHandle(entityHandle, &subsystemHandle);

    //
    // Query entity info
    //
    bool isTitlePlayer{};
    hr = PFEntityIsTitlePlayer(entityHandle, &isTitlePlayer);

    size_t keySize{};
    hr = PFEntityGetEntityKeySize(entityHandle, &keySize);

    std::vector<char> keyBuffer(keySize);
    PFEntityKey const* entityKey{};
    hr = PFEntityGetEntityKey(entityHandle, keyBuffer.size(), keyBuffer.data(), &entityKey, nullptr);

    //
    // ... make service calls with entityHandle or subsystemHandle ...
    //

    //
    // Cleanup: unregister handlers, then close all handles
    //
    PFEntityUnregisterTokenExpiredEventHandler(expiredToken);
    PFEntityUnregisterTokenRefreshedEventHandler(refreshedToken);

    PFEntityCloseHandle(subsystemHandle);
    PFEntityCloseHandle(entityHandle);
}
```

## API reference

| Function                                                                                                                                           | Description                                                                                          |
| -------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| [PFEntityDuplicateHandle](/services/playfab/api-references/c/pfentity/functions/pfentityduplicatehandle)                                           | Duplicates a handle, incrementing the ref count. Both handles must be closed independently.          |
| [PFEntityCloseHandle](/services/playfab/api-references/c/pfentity/functions/pfentityclosehandle)                                                   | Closes a handle, decrementing the ref count. The entity is destroyed when the last handle is closed. |
| [PFEntityGetEntityKeySize](/services/playfab/api-references/c/pfentity/functions/pfentitygetentitykeysize)                                         | Gets the buffer size needed to store the entity key.                                                 |
| [PFEntityGetEntityKey](/services/playfab/api-references/c/pfentity/functions/pfentitygetentitykey)                                                 | Gets the entity key (type and ID) for the entity.                                                    |
| [PFEntityGetEntityTokenAsync](/services/playfab/api-references/c/pfentity/functions/pfentitygetentitytokenasync)                                   | Retrieves the cached entity token asynchronously.                                                    |
| [PFEntityGetEntityTokenResultSize](/services/playfab/api-references/c/pfentity/functions/pfentitygetentitytokenresultsize)                         | Gets the buffer size needed for the entity token result.                                             |
| [PFEntityGetEntityTokenResult](/services/playfab/api-references/c/pfentity/functions/pfentitygetentitytokenresult)                                 | Gets the entity token from a completed PFEntityGetEntityTokenAsync call.                             |
| [PFEntityIsTitlePlayer](/services/playfab/api-references/c/pfentity/functions/pfentityistitleplayer)                                               | Returns whether the entity is a title\_player\_account.                                              |
| [PFEntityGetSecretKeySize](/services/playfab/api-references/c/pfentity/functions/pfentitygetsecretkeysize)                                         | Gets the buffer size needed for the secret key. Fails if the entity isn't a title entity.            |
| [PFEntityGetSecretKey](/services/playfab/api-references/c/pfentity/functions/pfentitygetsecretkey)                                                 | Gets the secret key for a title entity. Only available on Windows, Linux, and macOS.                 |
| [PFEntityGetAPIEndpointSize](/services/playfab/api-references/c/pfentity/functions/pfentitygetapiendpointsize)                                     | Gets the buffer size needed for the API endpoint string.                                             |
| [PFEntityGetAPIEndpoint](/services/playfab/api-references/c/pfentity/functions/pfentitygetapiendpoint)                                             | Gets the API endpoint from the entity's associated service config.                                   |
| **PFEntityGetTitleIdSize**                                                                                                                         | Gets the buffer size needed for the title ID string.                                                 |
| **PFEntityGetTitleId**                                                                                                                             | Gets the title ID from the entity's associated service config.                                       |
| [PFEntityRegisterTokenExpiredEventHandler](/services/playfab/api-references/c/pfentity/functions/pfentityregistertokenexpiredeventhandler)         | Registers a callback for when automatic token refresh fails.                                         |
| [PFEntityUnregisterTokenExpiredEventHandler](/services/playfab/api-references/c/pfentity/functions/pfentityunregistertokenexpiredeventhandler)     | Unregisters a token-expired callback.                                                                |
| [PFEntityRegisterTokenRefreshedEventHandler](/services/playfab/api-references/c/pfentity/functions/pfentityregistertokenrefreshedeventhandler)     | Registers a callback for when the SDK successfully refreshes a token.                                |
| [PFEntityUnregisterTokenRefreshedEventHandler](/services/playfab/api-references/c/pfentity/functions/pfentityunregistertokenrefreshedeventhandler) | Unregisters a token-refreshed callback.                                                              |

For the complete API reference, see [PFEntity members](/services/playfab/api-references/c/pfentity/pfentity_members).

## See also

* [Handling Token Expiration](/services/playfab/sdks/c/relogin)
* [Accessing PlayFab with a title entity](/services/playfab/sdks/c/server)
* [SDK Lifecycle](/services/playfab/sdks/c/lifecycle)
* [Quickstart: Windows](/services/playfab/sdks/c/quickstart-gdk)
* [Quickstart: Win32](/services/playfab/sdks/c/quickstart-win32)


## Related topics

- [PFEntityDuplicateHandle](/services/playfab/api-references/c/pfentity/functions/pfentityduplicatehandle.md)
- [PFEntityCloseHandle](/services/playfab/api-references/c/pfentity/functions/pfentityclosehandle.md)
- [PFEntityGetEntityKey](/services/playfab/api-references/c/pfentity/functions/pfentitygetentitykey.md)
- [PFEntityGetEntityKeySize](/services/playfab/api-references/c/pfentity/functions/pfentitygetentitykeysize.md)
- [PFEntityGetEntityTokenAsync](/services/playfab/api-references/c/pfentity/functions/pfentitygetentitytokenasync.md)
