# GoHighLevel Users API — Documentación Completa por Endpoint

> **Fuentes:** [GitHub OpenAPI spec](https://github.com/GoHighLevel/highlevel-api-docs/blob/main/apps/users.json) · [Marketplace Docs](https://marketplace.gohighlevel.com/docs/ghl/users/) · Perplexity Search
> **Base URL:** `https://services.leadconnectorhq.com`
> **Auth:** `Authorization: Bearer {TOKEN}` | `Version: 2021-07-28` | `User-Agent: Mozilla/5.0`

---

## 1. POST /users/ — Create User

Crea un nuevo usuario en la agencia y lo asigna a una o más locations.

### cURL

```bash
curl -X POST https://services.leadconnectorhq.com/users/ \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Version: 2021-07-28" \
  -H "User-Agent: Mozilla/5.0" \
  -d '{
    "companyId": "ve9EPM428h8vShlRW1KT",
    "firstName": "John",
    "lastName": "Deo",
    "email": "john@deo.com",
    "password": "*******",
    "phone": "+18832327657",
    "type": "account",
    "role": "admin",
    "locationIds": ["C2QujeCh8ZnC7al2InWR"],
    "permissions": {
      "contactsEnabled": true,
      "opportunitiesEnabled": true,
      "conversationsEnabled": true
    },
    "scopes": ["contacts.write", "opportunities.write"]
  }'
```

### Python

```python
import http.client
import json

def create_user(token, company_id, first_name, last_name, email, password, 
                location_ids, role="user", type_="account", phone=None,
                permissions=None, scopes=None, language="es"):
    """
    POST /users/ — Create a user in GHL.
    
    Args:
        token: API token (pit-xxx or OAuth)
        company_id: Agency ID
        location_ids: List of location IDs to assign user to
        permissions: Dict of 39 boolean flags (see §6 of research doc)
        scopes: List of scope strings (see §7 of research doc)
    
    Returns:
        dict with user data (id, name, email, phone) or error
    """
    payload = {
        "companyId": company_id,
        "firstName": first_name,
        "lastName": last_name,
        "email": email,
        "password": password,
        "type": type_,
        "role": role,
        "locationIds": location_ids,
        "platformLanguage": language
    }
    
    if phone:
        payload["phone"] = phone
    if permissions:
        payload["permissions"] = permissions
    if scopes:
        payload["scopes"] = scopes
    
    body = json.dumps(payload).encode()
    
    conn = http.client.HTTPSConnection("services.leadconnectorhq.com", timeout=30)
    conn.request("POST", "/users/", body, {
        "Accept": "application/json",
        "Authorization": f"Bearer {token}",
        "Version": "2021-07-28",
        "Content-Type": "application/json",
        "User-Agent": "Mozilla/5.0"
    })
    res = conn.getresponse()
    data = json.loads(res.read().decode())
    conn.close()
    
    if res.status == 201:
        return data.get("user", data)  # Response wraps in 'user' sometimes
    else:
        return {"error": res.status, "message": data.get("message", str(data))}


# ── Usage ──
user = create_user(
    token="pit-xxxxxxxx",
    company_id="ve9EPM428h8vShlRW1KT",
    first_name="Martin",
    last_name="Macedo",
    email="abejorrito79@gmail.com",
    password="********",
    phone="+527775610738",
    location_ids=["U0S0QntXgSOz9Fx18Db4"],
    role="user",
    permissions={
        "contactsEnabled": True,
        "opportunitiesEnabled": True,
        "conversationsEnabled": True,
        "assignedDataOnly": True
    },
    scopes=["contacts.write", "opportunities.write", "conversations.write"]
)
print(user)  # {"id": "0IHuJvc2ofPAAA8GzTRi", "name": "Martin Macedo", ...}
```

### Request Body Schema

| Campo | Tipo | Requerido | Descripción |
|-------|------|-----------|-------------|
| `companyId` | string | ✅ | ID de la agencia |
| `firstName` | string | ✅ | Nombre |
| `lastName` | string | ✅ | Apellido |
| `email` | string | ✅ | Email (debe ser único) |
| `password` | string | ✅ | Contraseña |
| `type` | string | ✅ | `account` o `agency` |
| `role` | string | ✅ | `admin`, `user`, `agency_admin` |
| `locationIds` | string[] | ✅ | Array de Location IDs |
| `phone` | string | | Teléfono en E.164 |
| `permissions` | object | | 39 flags booleanos |
| `scopes` | string[] | | 189 scopes OAuth |
| `scopesAssignedToOnly` | string[] | | Scopes asignados |
| `profilePhoto` | string | | URL de foto |
| `twilioPhone` | object | | `{"locId": "+123"}` — semántica replace |
| `platformLanguage` | string | | `es`, `en_US`, `fr_CA`, etc. |

### Response `201 Created`

```json
{
  "id": "0IHuJvc2ofPAAA8GzTRi",
  "name": "John Deo",
  "firstName": "John",
  "lastName": "Deo",
  "email": "john@deo.com",
  "phone": "+1 808-868-8888",
  "extension": "",
  "permissions": {...},
  "scopes": "...",
  "roles": {...},
  "deleted": false,
  "lcPhone": {"locationId": "+1234556677"},
  "platformLanguage": "en_US"
}
```

---

## 2. GET /users/{userId} — Get User

Obtiene todos los datos de un usuario por su ID.

### cURL

```bash
curl -X GET https://services.leadconnectorhq.com/users/{userId} \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Version: 2021-07-28" \
  -H "User-Agent: Mozilla/5.0"
```

### Python

```python
import http.client
import json

def get_user(token, user_id):
    """GET /users/{userId} — Get user details by ID."""
    conn = http.client.HTTPSConnection("services.leadconnectorhq.com", timeout=30)
    conn.request("GET", f"/users/{user_id}", "", {
        "Accept": "application/json",
        "Authorization": f"Bearer {token}",
        "Version": "2021-07-28",
        "User-Agent": "Mozilla/5.0"
    })
    res = conn.getresponse()
    data = json.loads(res.read().decode())
    conn.close()
    
    if res.status == 200:
        return data.get("user", data)
    return {"error": res.status, "message": data.get("message", str(data))}


# ── Usage ──
user = get_user(token="pit-xxxxxxxx", user_id="0IHuJvc2ofPAAA8GzTRi")
print(user["firstName"], user["email"], user["permissions"])
```

### Response `200`

```json
{
  "id": "0IHuJvc2ofPAAA8GzTRi",
  "name": "John Deo",
  "firstName": "John",
  "lastName": "Deo",
  "email": "john@deo.com",
  "phone": "+1 808-868-8888",
  "extension": "",
  "permissions": {...},
  "scopes": "...",
  "roles": {...},
  "deleted": false,
  "lcPhone": {"locationId": "+1234556677"},
  "platformLanguage": "en_US"
}
```

---

## 3. PUT /users/{userId} — Update User

Actualiza datos del usuario. **Todos los campos son opcionales** — solo envía lo que necesites cambiar.

### cURL — Cambiar permisos y scopes

```bash
curl -X PUT https://services.leadconnectorhq.com/users/{userId} \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Version: 2021-07-28" \
  -H "User-Agent: Mozilla/5.0" \
  -d '{
    "permissions": {"contactsEnabled": true, "opportunitiesEnabled": true},
    "scopes": ["contacts.write", "opportunities.write"]
  }'
```

### cURL — Mover usuario a otra location

```bash
curl -X PUT https://services.leadconnectorhq.com/users/{userId} \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Version: 2021-07-28" \
  -H "User-Agent: Mozilla/5.0" \
  -d '{"locationIds": ["LOC_ID_NUEVA"]}'
```

### Python

```python
import http.client
import json

def update_user(token, user_id, **kwargs):
    """
    PUT /users/{userId} — Update user fields.
    
    All kwargs are optional. Only send what you want to change.
    
    Examples:
        update_user(token, uid, permissions={"contactsEnabled": True})
        update_user(token, uid, location_ids=["LOC_A", "LOC_B"])
        update_user(token, uid, password="new_password")
        update_user(token, uid, scopes=["contacts.write"])
        update_user(token, uid, role="admin", type="account")
    """
    # Filter out None values
    payload = {k: v for k, v in kwargs.items() if v is not None}
    
    if not payload:
        return {"error": "No fields to update"}
    
    body = json.dumps(payload).encode()
    
    conn = http.client.HTTPSConnection("services.leadconnectorhq.com", timeout=30)
    conn.request("PUT", f"/users/{user_id}", body, {
        "Accept": "application/json",
        "Authorization": f"Bearer {token}",
        "Version": "2021-07-28",
        "Content-Type": "application/json",
        "User-Agent": "Mozilla/5.0"
    })
    res = conn.getresponse()
    data = json.loads(res.read().decode())
    conn.close()
    
    if res.status == 200:
        return data.get("user", data)
    return {"error": res.status, "message": data.get("message", str(data))}


# ── Usage examples ──

# Example 1: Update permissions and scopes
update_user(
    token="pit-xxxxxxxx",
    user_id="0IHuJvc2ofPAAA8GzTRi",
    permissions={
        "contactsEnabled": True,
        "opportunitiesEnabled": True,
        "conversationsEnabled": True,
        "assignedDataOnly": True
    },
    scopes=["contacts.write", "opportunities.write", "conversations.write"]
)

# Example 2: Move user to a different location
update_user(
    token="pit-xxxxxxxx",
    user_id="0IHuJvc2ofPAAA8GzTRi",
    location_ids=["U0S0QntXgSOz9Fx18Db4"]  # ZACATEPEC
)

# Example 3: Change role and type
update_user(
    token="pit-xxxxxxxx",
    user_id="0IHuJvc2ofPAAA8GzTRi",
    role="admin",
    type="account"
)

# Example 4: Reset password
update_user(
    token="pit-xxxxxxxx",
    user_id="0IHuJvc2ofPAAA8GzTRi",
    password="new_secure_password"
)
```

### Campos actualizables

| Campo | Tipo | Deprecado | Descripción |
|-------|------|-----------|-------------|
| `firstName` | string | | Nombre |
| `lastName` | string | | Apellido |
| `email` | string | ⚠️ SÍ | Ya no soportado por seguridad |
| `password` | string | | Nueva contraseña |
| `phone` | string | | Teléfono |
| `type` | string | | `account` / `agency` |
| `role` | string | | `admin` / `user` / `agency_admin` |
| `companyId` | string | | ID de agencia (requerido para agency-level) |
| `locationIds` | string[] | | Reasignar sucursales |
| `permissions` | object | | 39 flags booleanos |
| `scopes` | string[] | | 189 scopes OAuth |
| `scopesAssignedToOnly` | string[] | | Scopes asignados |
| `profilePhoto` | string | | URL de foto |
| `twilioPhone` | object | | Números inbound — semántica replace |
| `platformLanguage` | string | | `es`, `en_US`, etc. |

---

## 4. DELETE /users/{userId} — Delete User

Soft delete asíncrono. El usuario se encola para eliminación y toma efecto en minutos.

### cURL

```bash
curl -X DELETE https://services.leadconnectorhq.com/users/{userId} \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Version: 2021-07-28" \
  -H "User-Agent: Mozilla/5.0"
```

### Python

```python
import http.client
import json

def delete_user(token, user_id):
    """DELETE /users/{userId} — Soft delete (async, takes minutes)."""
    conn = http.client.HTTPSConnection("services.leadconnectorhq.com", timeout=30)
    conn.request("DELETE", f"/users/{user_id}", "", {
        "Accept": "application/json",
        "Authorization": f"Bearer {token}",
        "Version": "2021-07-28",
        "User-Agent": "Mozilla/5.0"
    })
    res = conn.getresponse()
    data = json.loads(res.read().decode())
    conn.close()
    return data  # {"succeded": true, "message": "Queued deleting user..."}


# ── Usage ──
result = delete_user(token="pit-xxxxxxxx", user_id="0IHuJvc2ofPAAA8GzTRi")
print(result["message"])  # "Queued deleting user with e-mail john@deo.com..."
```

### Response `200`

```json
{
  "succeded": true,
  "message": "Queued deleting user with e-mail john@deo.com and name John Deo. Will take effect in a few minutes."
}
```

---

## 5. GET /users/search — Search Users

Búsqueda avanzada con filtros por companyId, locationId, nombre, email, rol, tipo, IDs específicos, y ordenamiento.

### Parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `Version` | string | ✅ | API Version header |
| `companyId` | string | ✅ | ID de la agencia |
| `query` | string | | Búsqueda por nombre, email o teléfono |
| `locationId` | string | | Filtrar por location |
| `type` | string | | `agency`, `account` |
| `role` | string | | `admin`, `user`, `agency_admin` |
| `ids` | string | | IDs separados por coma |
| `skip` | string | | Paginación offset (default: 0) |
| `limit` | string | | Page size (default: 25) |
| `sort` | string | | Campo de orden: `dateAdded` |
| `sortDirection` | string | | `asc` o `desc` |

### cURL

```bash
curl -X GET "https://services.leadconnectorhq.com/users/search?companyId=5DP41231LkQsiKESj6rh&locationId=C2QujeCh8ZnC7al2InWR&query=John&limit=10&sort=dateAdded&sortDirection=desc" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Version: 2021-07-28" \
  -H "User-Agent: Mozilla/5.0"
```

### Python

```python
import http.client
import json
import urllib.parse

def search_users(token, company_id, query=None, location_id=None, 
                 user_type=None, role=None, ids=None, skip=0, limit=25,
                 sort="dateAdded", sort_direction="desc"):
    """GET /users/search — Advanced user search."""
    params = {
        "companyId": company_id,
        "skip": str(skip),
        "limit": str(limit),
        "sort": sort,
        "sortDirection": sort_direction
    }
    if query:
        params["query"] = query
    if location_id:
        params["locationId"] = location_id
    if user_type:
        params["type"] = user_type
    if role:
        params["role"] = role
    if ids:
        params["ids"] = ids
    
    qs = urllib.parse.urlencode(params)
    
    conn = http.client.HTTPSConnection("services.leadconnectorhq.com", timeout=30)
    conn.request("GET", f"/users/search?{qs}", "", {
        "Accept": "application/json",
        "Authorization": f"Bearer {token}",
        "Version": "2021-07-28",
        "User-Agent": "Mozilla/5.0"
    })
    res = conn.getresponse()
    data = json.loads(res.read().decode())
    conn.close()
    
    if res.status == 200:
        return data  # {"users": [...], "count": N}
    return {"error": res.status, "message": data.get("message", str(data))}


# ── Usage examples ──

# Find all users in a location
users = search_users(token="pit-xxxxxxxx", company_id="ve9EPM428h8vShlRW1KT",
                     location_id="U0S0QntXgSOz9Fx18Db4")
print(f"Found {users['count']} users in ZACATEPEC")

# Search by name
users = search_users(token="pit-xxxxxxxx", company_id="ve9EPM428h8vShlRW1KT",
                     query="Martin Macedo")
for u in users.get("users", []):
    print(f"  {u['id']}: {u['name']} ({u['email']})")

# Filter by role
admins = search_users(token="pit-xxxxxxxx", company_id="ve9EPM428h8vShlRW1KT",
                      role="admin", limit=50)
```

### Response `200`

```json
{
  "users": [
    {
      "id": "0IHuJvc2ofPAAA8GzTRi",
      "name": "John Deo",
      "firstName": "John",
      "lastName": "Deo",
      "email": "john@deo.com",
      "phone": "+1 808-868-8888",
      "extension": "",
      "permissions": {...},
      "scopes": "...",
      "roles": {...},
      "deleted": false,
      "lcPhone": {"locationId": "+1234556677"},
      "platformLanguage": "en_US"
    }
  ],
  "count": 1
}
```

---

## 6. POST /users/search/filter-by-email — Filter by Email

Filtra usuarios por array de emails. Ideal para verificar duplicados antes de crear.

### cURL

```bash
curl -X POST https://services.leadconnectorhq.com/users/search/filter-by-email \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Version: 2021-07-28" \
  -H "User-Agent: Mozilla/5.0" \
  -d '{
    "companyId": "ve9EPM428h8vShlRW1KT",
    "emails": ["john@deo.com", "jane@deo.com"],
    "includeDeleted": false
  }'
```

### Python

```python
import http.client
import json

def filter_users_by_email(token, company_id, emails, include_deleted=False):
    """
    POST /users/search/filter-by-email — Check if emails already exist.
    
    Args:
        emails: List of email strings to check
        include_deleted: Include soft-deleted users
    
    Returns:
        List of users matching the emails
    """
    body = json.dumps({
        "companyId": company_id,
        "emails": emails,
        "includeDeleted": include_deleted
    }).encode()
    
    conn = http.client.HTTPSConnection("services.leadconnectorhq.com", timeout=30)
    conn.request("POST", "/users/search/filter-by-email", body, {
        "Accept": "application/json",
        "Authorization": f"Bearer {token}",
        "Version": "2021-07-28",
        "Content-Type": "application/json",
        "User-Agent": "Mozilla/5.0"
    })
    res = conn.getresponse()
    data = json.loads(res.read().decode())
    conn.close()
    
    if res.status == 200:
        return data  # Array or {"users": [...]}
    return {"error": res.status, "message": data.get("message", str(data))}


# ── Usage: Check for duplicate before creating ──
def email_exists(token, company_id, email):
    """Returns True if a user with this email already exists."""
    result = filter_users_by_email(token, company_id, [email])
    users = result.get("users", result if isinstance(result, list) else [])
    return len(users) > 0


existing = email_exists(token="pit-xxxxxxxx", company_id="ve9EPM428h8vShlRW1KT",
                        email="abejorrito79@gmail.com")
if existing:
    print("⚠️ Email already taken — cannot create user")
else:
    print("✅ Email available — safe to create")
```

### Response 200

Devuelve array de usuarios que coinciden con los emails proporcionados.

---

## 7. GET /users/ — Get User by Location ⚠️ DEPRECADO

**No usar.** Reemplazado por `GET /users/search` con query param `locationId`.

```bash
# ❌ Deprecado
GET /users/?locationId=LOC_ID

# ✅ Correcto
GET /users/search?locationId=LOC_ID&companyId=COMPANY_ID
```

---

## 8. Response Codes

| Código | Significado | Schema |
|--------|-------------|--------|
| `200` | OK (GET, PUT, DELETE) | `UserSuccessfulResponseDto` / `DeleteUserSuccessfulResponseDto` |
| `201` | Created (POST) | `UserSuccessfulResponseDto` |
| `400` | Bad Request | `BadRequestDTO` |
| `401` | Unauthorized — token sin scope | `UnauthorizedDTO` |
| `422` | Unprocessable — email duplicado, locationIds inválido | `UnprocessableDTO` |

---

## 9. Scope Requirements

| Operación | Scope |
|-----------|-------|
| GET (search, get by id, filter by email) | `users.readonly` |
| POST (create) | `users.write` |
| PUT (update) | `users.write` |
| DELETE | `users.write` |

---

## 10. Notas importantes

1. **Email no se puede actualizar** — el campo `email` en PUT está deprecado por seguridad
2. **Delete es asíncrono** — la respuesta confirma encolado, no eliminación inmediata
3. **TwilioPhone tiene semántica replace** — si lo envías, reemplaza todo el mapa; no hace merge
4. **Scopes vacíos deshabilitan todo** — `"scopes": []` quita todos los permisos
5. **companyId es obligatorio** en search y filter-by-email — se obtiene del `GET /locations/{id}`
6. **locationIds acepta array** — un usuario puede pertenecer a múltiples sucursales simultáneamente
7. **Versión 2021-07-28** — todos los endpoints usan esta versión; algunos aceptan 2023-02-21

---

## 11. Python Helper — Clase completa

```python
import http.client
import json
import urllib.parse

class GHLUsersAPI:
    """Complete wrapper for GoHighLevel Users API."""
    
    BASE = "services.leadconnectorhq.com"
    
    def __init__(self, token):
        self.token = token
        self.headers = {
            "Accept": "application/json",
            "Authorization": f"Bearer {token}",
            "Version": "2021-07-28",
            "User-Agent": "Mozilla/5.0"
        }
    
    def _request(self, method, path, body=None):
        """Generic HTTP request helper."""
        conn = http.client.HTTPSConnection(self.BASE, timeout=30)
        conn.request(method, path, body or "", self.headers)
        res = conn.getresponse()
        data = json.loads(res.read().decode())
        conn.close()
        return res.status, data
    
    def create(self, company_id, first_name, last_name, email, password,
               location_ids, role="user", type_="account", **kwargs):
        """POST /users/ — Create user."""
        payload = {
            "companyId": company_id, "firstName": first_name,
            "lastName": last_name, "email": email, "password": password,
            "type": type_, "role": role, "locationIds": location_ids,
            "platformLanguage": kwargs.get("language", "es")
        }
        for k in ("phone", "permissions", "scopes", "profilePhoto", "twilioPhone"):
            if k in kwargs and kwargs[k] is not None:
                payload[k] = kwargs[k]
        
        status, data = self._request("POST", "/users/", 
                                      json.dumps(payload).encode())
        if status == 201:
            return data.get("user", data)
        raise Exception(f"Create failed: {status} {data.get('message', data)}")
    
    def get(self, user_id):
        """GET /users/{userId} — Get user."""
        status, data = self._request("GET", f"/users/{user_id}")
        if status == 200:
            return data.get("user", data)
        raise Exception(f"Get failed: {status}")
    
    def update(self, user_id, **kwargs):
        """PUT /users/{userId} — Update user fields."""
        payload = {k: v for k, v in kwargs.items() if v is not None}
        if not payload:
            raise Exception("No fields to update")
        status, data = self._request("PUT", f"/users/{user_id}",
                                      json.dumps(payload).encode())
        if status == 200:
            return data.get("user", data)
        raise Exception(f"Update failed: {status} {data.get('message', data)}")
    
    def delete(self, user_id):
        """DELETE /users/{userId} — Soft delete."""
        status, data = self._request("DELETE", f"/users/{user_id}")
        if status == 200:
            return data
        raise Exception(f"Delete failed: {status}")
    
    def search(self, company_id, **kwargs):
        """GET /users/search — Search users."""
        params = {"companyId": company_id, "skip": "0", "limit": "25"}
        for k in ("query", "locationId", "type", "role", "ids", "sort", 
                  "sortDirection"):
            if k in kwargs and kwargs[k] is not None:
                params[k] = str(kwargs[k])
        
        qs = urllib.parse.urlencode(params)
        status, data = self._request("GET", f"/users/search?{qs}")
        if status == 200:
            return data
        raise Exception(f"Search failed: {status}")
    
    def filter_by_email(self, company_id, emails, include_deleted=False):
        """POST /users/search/filter-by-email — Filter by email list."""
        payload = {"companyId": company_id, "emails": emails,
                   "includeDeleted": include_deleted}
        status, data = self._request("POST", "/users/search/filter-by-email",
                                      json.dumps(payload).encode())
        if status == 200:
            return data
        raise Exception(f"Filter failed: {status}")


# ── Complete usage example ──
api = GHLUsersAPI(token="pit-xxxxxxxx")

# 1. Check if email exists
try:
    existing = api.filter_by_email("ve9EPM428h8vShlRW1KT", ["test@example.com"])
    print(f"Email check: {len(existing.get('users', []))} found")
except:
    print("Email available")

# 2. Create user
user = api.create(
    company_id="ve9EPM428h8vShlRW1KT",
    first_name="Martin", last_name="Macedo",
    email="abejorrito79@gmail.com", password="********",
    phone="+527775610738",
    location_ids=["U0S0QntXgSOz9Fx18Db4"],
    role="user",
    permissions={"contactsEnabled": True, "opportunitiesEnabled": True},
    scopes=["contacts.write", "opportunities.write"]
)
print(f"Created: {user['id']}")

# 3. Update permissions
api.update(user["id"], 
           permissions={"contactsEnabled": True, "opportunitiesEnabled": True,
                        "conversationsEnabled": True, "assignedDataOnly": True},
           scopes=["contacts.write", "opportunities.write", "conversations.write"])

# 4. Search users in location
result = api.search("ve9EPM428h8vShlRW1KT", 
                    locationId="U0S0QntXgSOz9Fx18Db4")
print(f"Users in ZACATEPEC: {result['count']}")

# 5. Delete user (if needed)
# api.delete(user["id"])
```
