---
title: Product Users & Credits API
description: Supported service-key operations for product users identified by external user ID.
---

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

## Get Product User by External ID

Retrieve complete product user profile, spend cap, live credit balances, and token usage by your own system identifier (`external_user_id`).

The response can include `allowance` with the effective connection, period boundaries, remaining base allowance, and total available allowance. See [Check available allowance](/startups/check-allowance) and [allowance periods](/startups/allowance-periods). `credits` alone does not represent the total amount available to spend.

<ApiEndpoint method="GET" path="/product-users/by-external-id" auth="service_key" />

### Query Parameters

<ParamField name="app_id" type="string" required>
  The Zorveus App ID (e.g. `app_support_123`).
</ParamField>

<ParamField name="external_user_id" type="string" required>
  Your platform's unique user identifier (e.g. `usr_alex_8842`).
</ParamField>

<ApiRunner method="GET" path="/product-users/by-external-id" authType="service_key" />

#### Response (`200 OK`)

```json
{
  "product_end_user_id": "peu_01j6abc1234567890def",
  "org_id": "org_startup_123",
  "app_id": "app_support_123",
  "external_user_id": "usr_alex_8842",
  "display_name": "Alex Smith",
  "email_hash": "sha256:5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8",
  "status": "active",
  "metadata": {
    "plan": "pro"
  },
  "allowance_starts_at": null,
  "last_app_connection_id": "conn_123",
  "allowance": {
    "app_connection_id": "conn_123",
    "cap_source": "product_end_user",
    "cap_rule_id": "cap_01j6def456",
    "credit_mode": "enforce",
    "overrun_policy": "limit_output",
    "currency": "USD",
    "period": "monthly",
    "period_start": "2026-08-01T00:00:00Z",
    "period_end": "2026-09-01T00:00:00Z",
    "cap_amount": "50.000000000000",
    "spent_this_period": "12.450000000000",
    "remaining_base_allowance": "37.550000000000",
    "available_credits": "25.000000000000",
    "available_allowance": "62.550000000000"
  },
  "cap": {
    "source": "product_end_user",
    "cap_rule_id": "cap_01j6def456",
    "amount": "50.000000000000",
    "currency": "USD",
    "period": "monthly",
    "spent_this_period": "12.450000000000",
    "reset_at": "2026-09-01T00:00:00Z",
    "status": "active",
    "updated_at": "2026-08-01T10:00:00Z"
  },
  "credits": {
    "currency": "USD",
    "available_credits": "25.000000000000",
    "active_grant_count": 2,
    "expiring_soon_amount": "5.000000000000",
    "spent_this_month": "10.000000000000",
    "spent_total": "35.000000000000",
    "last_grant_at": "2026-08-10T14:30:00Z",
    "last_used_at": "2026-08-14T22:15:00Z"
  },
  "usage": {
    "this_month": {
      "sell_cost": "12.450000000000",
      "input_tokens": 154000,
      "output_tokens": 32000,
      "total_tokens": 186000,
      "request_count": 48
    },
    "total": {
      "sell_cost": "45.800000000000",
      "input_tokens": 620000,
      "output_tokens": 115000,
      "total_tokens": 735000,
      "request_count": 192
    }
  }
}
```

---

## Get Product User Credit Summary by External ID

A fast, lightweight endpoint for querying a product user's live credit balance without token usage breakdowns.

<ApiEndpoint method="GET" path="/product-users/by-external-id/credit-summary" auth="service_key" />

### Query Parameters

<ParamField name="app_id" type="string" required>
  The Zorveus App ID (e.g. `app_support_123`).
</ParamField>

<ParamField name="external_user_id" type="string" required>
  Your platform's unique user identifier (e.g. `usr_alex_8842`).
</ParamField>

<ParamField name="currency" type="string">
  3-letter ISO currency code. Defaults to `USD`.
</ParamField>

<ApiRunner method="GET" path="/product-users/by-external-id/credit-summary" authType="service_key" />

#### Response (`200 OK`)

```json
{
  "currency": "USD",
  "available_credits": "25.000000000000",
  "active_grant_count": 2,
  "expiring_soon_amount": "5.000000000000",
  "spent_this_month": "10.000000000000",
  "spent_total": "35.000000000000",
  "last_grant_at": "2026-08-10T14:30:00Z",
  "last_used_at": "2026-08-14T22:15:00Z"
}
```

---

## Upsert Product User by External ID

The request accepts `allowance_starts_at` as a nullable RFC 3339 timestamp. Omit the field to preserve the stored anchor. Send `null` to restore calendar periods. A supplied timestamp cannot be in the future or older than the stored anchor. See [allowance periods](/startups/allowance-periods).

<ApiEndpoint method="PUT" path="/product-users/by-external-id" auth="service_key" />

<ApiRunner method="PUT" path="/product-users/by-external-id" authType="service_key" />

---

## Grant Product User Credits By External Id Route

<ApiEndpoint method="POST" path="/product-users/by-external-id/credit-grants" auth="service_key" />

<ApiRunner method="POST" path="/product-users/by-external-id/credit-grants" authType="service_key" />

---

## Dashboard-only operations

Use **Product Users** in the dashboard to change a user's status or revoke a credit grant. Routes that use `product_end_user_id` are dashboard operations, not service-key endpoints.

---

## Error Codes & Statuses

| HTTP Status | Error Code (`error.code`) | Description | Resolution |
| :--- | :--- | :--- | :--- |
| `400 Bad Request` | `zorveus_invalid_app_id` | `app_id` query parameter is empty or missing. | Supply a valid Zorveus `app_id`. |
| `400 Bad Request` | `zorveus_invalid_external_user_id` | `external_user_id` query parameter is empty. | Supply a non-empty `external_user_id`. |
| `401 Unauthorized` | `zorveus_malformed_or_missing_service_key` | Missing or invalid `Authorization` header. | Provide a valid Bearer token (`zrv_svc_...`). |
| `403 Forbidden` | `zorveus_service_key_scope_required` | Service key lacks `product_users:read` or `product_users:write`. | Add the required scope in the Zorveus Dashboard. |
| `403 Forbidden` | `zorveus_service_key_inactive` | Service key has expired or been revoked. | Rotate or create a new active Service Key. |
| `404 Not Found` | `zorveus_product_user_not_found` | No user exists for that `(app_id, external_user_id)` tuple. | Call `PUT /product-users/by-external-id` to create/upsert. |

### Error Response Format

```json
{
  "error": {
    "code": "zorveus_product_user_not_found",
    "message": "Product user not found."
  }
}
```
