---
title: Manage product users
description: Look up and update your customers, then read their usage, credits, and allowance.
---

Product Users are your customers. You can create or update them automatically inline during inference or manage them explicitly using your Organization Service Key (`zrv_svc_...`).

<KeyInserter type="service" label="Service Key Inserter" placeholder="zrv_svc_your_service_key" />

<Callout type="tip" title="Automatic Inline User Provisioning">
  You do not need to create product users through the Management API before inference. Send `X-Zorveus-External-User-ID` in the headers or `metadata.external_user_id` in the body. Either creates the product user on their first request and attributes subsequent requests to that user. Include the same identifier on every request.
</Callout>

---

## Look up a product user

Read a product user's live profile, configured spending cap, available credits, and monthly token usage without accidental creations or mutations.

<CodeGroup titles={["TypeScript (@zorveus/sdk)", "Python (zorveus)", "cURL"]}>

```typescript
import { ZorveusServiceClient } from "@zorveus/sdk";

const service = new ZorveusServiceClient({
  apiKey: "zrv_svc_your_service_key",
});

// Fetch full user profile, active cap, credits, and monthly usage
const user = await service.productUsers.getByExternalId({
  appId: "app_support_123",
  externalUserId: "usr_sara_101",
});

console.log("Display name:", user.display_name);
console.log("Available allowance:", user.getTotalAvailableToSpend());
```

```python
from zorveus import ZorveusServiceClient

service = ZorveusServiceClient(api_key="zrv_svc_your_service_key")

# Fetch full user profile, active cap, credits, and monthly usage
user = service.product_users.get_by_external_id(
    app_id="app_support_123",
    external_user_id="usr_sara_101",
)

print("Display name:", user.display_name)
print("Available allowance:", user.get_total_available_to_spend())
service.close()
```

```bash
curl -X GET "https://api.zorveus.com/product-users/by-external-id?app_id=app_support_123&external_user_id=usr_sara_101" \
  -H "Authorization: Bearer zrv_svc_your_service_key"
```

</CodeGroup>

---

## Check whether a user has money to spend

For an active user under a known enforced cap, use `user.has_available_allowance()` in Python or `user.hasAvailableAllowance()` in TypeScript. Both check whether total available allowance is greater than zero without another API call.

To get the amount as well, use `user.get_total_available_to_spend_decimal()` in Python or `user.getTotalAvailableToSpend()` in TypeScript. See [the amount check and SDK shortcuts](/startups/check-allowance#check-whether-the-user-has-any-amount-to-spend) for examples and the uncapped-key rules.

## Read credits separately

The credit summary contains credit grants only. It does not include remaining base allowance. To decide whether a capped user can attempt inference, follow [Check available allowance](/startups/check-allowance).

<CodeGroup titles={["TypeScript (@zorveus/sdk)", "Python (zorveus)", "cURL"]}>

```typescript
import { ZorveusServiceClient } from "@zorveus/sdk";

const service = new ZorveusServiceClient({
  apiKey: "zrv_svc_your_service_key",
});

const creditSummary = await service.productUsers.getCreditSummaryByExternalId({
  appId: "app_support_123",
  externalUserId: "usr_sara_101",
});

console.log("Available Credits:", creditSummary.available_credits);
```

```python
from zorveus import ZorveusServiceClient

service = ZorveusServiceClient(api_key="zrv_svc_your_service_key")

credits = service.product_users.get_credit_summary_by_external_id(
    app_id="app_support_123",
    external_user_id="usr_sara_101",
)

print("Available credits:", credits.available_credits)
service.close()
```

```bash
curl -X GET "https://api.zorveus.com/product-users/by-external-id/credit-summary?app_id=app_support_123&external_user_id=usr_sara_101" \
  -H "Authorization: Bearer zrv_svc_your_service_key"
```

</CodeGroup>

---

## Update a product user

To update user profile details outside of inference requests:

<CodeGroup titles={["TypeScript (@zorveus/sdk)", "Python (zorveus)", "cURL"]}>

```typescript
import { ZorveusServiceClient } from "@zorveus/sdk";

const service = new ZorveusServiceClient({
  apiKey: "zrv_svc_your_service_key",
});

const user = await service.productUsers.createOrUpdate({
  appId: "app_support_123",
  externalUserId: "usr_sara_101",
  displayName: "Sara Connor",
  email: "sara@example.com",
});
```

```python
from zorveus import ZorveusServiceClient

service = ZorveusServiceClient(api_key="zrv_svc_your_service_key")

user = service.product_users.create_or_update(
    app_id="app_support_123",
    external_user_id="usr_sara_101",
    display_name="Sara Connor",
    email="sara@example.com",
)
service.close()
```

```bash
curl -X PUT https://api.zorveus.com/product-users/by-external-id \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer zrv_svc_your_service_key" \
  -d '{
    "app_id": "app_support_123",
    "external_user_id": "usr_sara_101",
    "display_name": "Sara Connor",
    "email": "sara@example.com"
  }'
```

</CodeGroup>
