> For the complete documentation index, see [llms.txt](https://docs.helodata.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.helodata.com/api-reference/sub-users.md).

# Sub-users

Sub-users are the unit of access control on the proxy gateway. Every proxy request must reference one, and each sub-user has its own password, limits, and per-product scope.

## Endpoints

| Method   | Path                             | Purpose                        |
| -------- | -------------------------------- | ------------------------------ |
| `GET`    | `/subusers`                      | List all sub-users             |
| `POST`   | `/subusers`                      | Create a sub-user              |
| `GET`    | `/subusers/{id}`                 | Get one sub-user               |
| `PATCH`  | `/subusers/{id}`                 | Update name, limits, or status |
| `POST`   | `/subusers/{id}/rotate-password` | Rotate the password            |
| `DELETE` | `/subusers/{id}`                 | Delete (irreversible)          |

## List

```bash
curl -H "Authorization: Bearer API_KEY" \
     https://api.helodata.com/v1/subusers?product=residential
```

Response:

```json
{
  "data": [
    {
      "id":              "sub_01HX2K3PQ4M5",
      "name":            "s1a2b3c4d5e",
      "label":           "acme-prod",
      "products":        ["residential", "mobile"],
      "status":          "active",
      "concurrent_max":  600,
      "rps_max":         1000,
      "created_at":      "2026-05-01T00:00:00Z"
    }
  ],
  "next_cursor": null
}
```

Filter with `product=residential|mobile|isp`, `status=active|disabled`, `label_contains=...`.

## Create

```bash
curl -X POST -H "Authorization: Bearer API_KEY" \
     -H "Content-Type: application/json" \
     -d '{
       "label":    "acme-staging",
       "products": ["residential"],
       "concurrent_max": 200,
       "rps_max":        500
     }' \
     https://api.helodata.com/v1/subusers
```

Response:

```json
{
  "id":       "sub_01HX2K3PQ4M5",
  "name":     "s9z8y7x6w5v",
  "password": "Mz4yQv8R...",
  "label":    "acme-staging",
  "products": ["residential"]
}
```

> The `password` is shown **only** in this response. Store it immediately; we keep only a hash.

### Field constraints

| Field            | Constraint                                   |
| ---------------- | -------------------------------------------- |
| `label`          | 1–64 chars, `[a-z0-9-]`                      |
| `products`       | Subset of `["residential", "mobile", "isp"]` |
| `concurrent_max` | 1–10000, must not exceed plan limit          |
| `rps_max`        | 1–10000                                      |

## Get one

```bash
curl -H "Authorization: Bearer API_KEY" \
     https://api.helodata.com/v1/subusers/sub_01HX2K3PQ4M5
```

## Update

```bash
curl -X PATCH -H "Authorization: Bearer API_KEY" \
     -H "Content-Type: application/json" \
     -d '{"concurrent_max": 1000, "status": "active"}' \
     https://api.helodata.com/v1/subusers/sub_01HX2K3PQ4M5
```

Editable: `label`, `status` (`active` / `disabled`), `concurrent_max`, `rps_max`. To change `products`, delete and recreate.

Setting `status` to `disabled` makes the sub-user immediately return `403` on every proxy request — the credentials still exist, just deactivated.

## Rotate password

```bash
curl -X POST -H "Authorization: Bearer API_KEY" \
     https://api.helodata.com/v1/subusers/sub_01HX2K3PQ4M5/rotate-password
```

Response includes the new password (shown once). The old password works for 60 seconds, then `407`.

## Delete

```bash
curl -X DELETE -H "Authorization: Bearer API_KEY" \
     https://api.helodata.com/v1/subusers/sub_01HX2K3PQ4M5
```

Deletes the sub-user. Existing proxy requests in flight may take up to 60 seconds to drain.

## Errors

| Status | Code                | Meaning                                      |
| ------ | ------------------- | -------------------------------------------- |
| `409`  | `label_taken`       | Another sub-user already has this label      |
| `422`  | `over_plan_limit`   | Requested `concurrent_max` exceeds your plan |
| `404`  | `subuser_not_found` | Wrong ID                                     |
