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

# Manage Users

> Create, update, & manage user profiles and communication channels using Python SDK methods.

## How Suprsend identifies a user

SuprSend identifies users with immutable `distinct_id`. It's best to map the same identifier in your DB with `distinct_id` in SuprSend. Do not use identifiers that can be changed like email or phone number. You can view synced users by searching `distinct_id` on [Users page](https://app.suprsend.com/en/production/users).

## Create User

To create a new user or to update an existing user, you'll have to fetch user instance. Call `supr_client.user.get_instance` to instantiate user object.

```python theme={"system"}
import suprsend

supr_client = suprsend.Suprsend("workspace_key", "workspace_secret")

distinct_id = "distinct_id"  # Unique identifier of user in your application

# Instantiate User profile
user = supr_client.users.get_edit_instance(distinct_id)
```

## Edit User

To Edit user, you need to first fetch user instance, call all the update methods and save changes using `users.async_edit` method.

<CodeGroup>
  ```python Request theme={"system"}
  #Fetch user instance
  user = supr_client.users.get_edit_instance("_distinct_id_")

  #Call user update methods
  user.set_timezone("America/Los_Angeles")
  user.set("name", "John Doe")

  #Save Changes
  res = supr_client.users.async_edit(user)
  print(res)
  ```

  ```json Response theme={"system"}
  {
    "success": boolean,
    "status": "success"/"fail",
    "status_code": http_status_code,
    "message": "response_message"/"error_message",
  }
  ```
</CodeGroup>

Here's a list of all edit methods:

<AccordionGroup>
  <Accordion title="Add User Channels">
    Add communication channels on which you want to notify user. Push sand Inbox tokens are automatically tracked on user identification when the corresponding frontend SDK is integrated. Other channels (Email, SMS, Slack, MS teams, WhatsApp) need to be explicitly set in user profile.

    Use `user.add_*` method(s) to add user channels.

    <CodeGroup>
      ```python python theme={"system"}
      # Add channel details to user-instance. Call relevant add_* methods

      user.add_email("user@example.com") # - To add Email

      user.add_sms("+15555555555") # - To add SMS

      user.add_whatsapp("+15555555555") # - To add WhatsApp

      user.add_androidpush("__android_push_fcm_token__")

      user.add_iospush("__iospush_token__")

      # - To add Slack using email
      user.add_slack(
        {
          "email": "user@example.com",
          "access_token": "xoxb-XXXXXXXX"
        })

      # - To add Slack if slack member_id is known
      user.add_slack(
        {
          "user_id": "U03XXXXXXXX",
          "access_token": "xoxb-XXXXXXXX"
        })

      # - To add Slack channel
      user.add_slack(
        {
          "channel_id": "CXXXXXXXX",
          "access_token": "xoxb-XXXXXXXX"
        })

      # - To add Slack incoming webhook
      user.add_slack(
        {
          "incoming_webhook": {
            "url": "https://hooks.slack.com/services/TXXXX/BXXXX/XXXXXXX"
          }
        })

      # - To add MS teams user or channel using conversation_id
      user.add_ms_teams(
        {
      		"tenant_id": "c1981ab2-9aaf-xxxx-xxxx",
      		"service_url": "https://smba.trafficmanager.net/amer",
      		"conversation_id": "19:c1524d7c-a06f-456f-8abe-xxxx"
        })

      # - To add MS teams user using user_id
      user.add_ms_teams(
        {
      		"tenant_id": "c1981ab2-9aaf-xxxx-xxxx",
      		"service_url": "https://smba.trafficmanager.net/amer",
      		"user_id": "29:1nsLcmJ2RKtYH6Cxxxx-xxxx"
        })

      # - To add MS teams using incoming webhook
      user.add_ms_teams(
        {
          "incoming_webhook": {
            "url": "https://wnk1z.webhook.office.com/webhookb2/XXXXXXXXX"
          }
        })

      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Remove User Channels">
    Use `user.remove_*` method(s) to remove channels.

    <CodeGroup>
      ```python python theme={"system"}
      # Remove channel details from user-instance. Call relevant remove_* methods

      user.remove_email("user@example.com")

      user.remove_sms("+15555555555")

      user.remove_whatsapp("+15555555555")

      user.remove_androidpush("__android_push_fcm_token__")

      user.remove_iospush("__iospush_token__")

      # - To remove Slack email
      user.remove_slack(
        {
          "email": "user@example.com",
          "access_token": "xoxb-XXXXXXXX"
        })

      # - To remove Slack if slack member_id is known
      user.remove_slack(
        {
          "user_id": "U03XXXXXXXX",
          "access_token": "xoxb-XXXXXXXX"
        })

      # - To remove Slack channel
      user.remove_slack(
        {
          "channel_id": "CXXXXXXXX",
          "access_token": "xoxb-XXXXXXXX"
        })

      # - To remove Slack incoming webhook
      user.remove_slack(
        {
          "incoming_webhook": {
            "url": "https://hooks.slack.com/services/TXXXX/BXXXX/XXXXXXX"
          }
        })

      # - To remove MS teams user or channel using conversation_id
      user.remove_ms_teams(
        {
      		"tenant_id": "c1981ab2-9aaf-xxxx-xxxx",
      		"service_url": "https://smba.trafficmanager.net/amer",
      		"conversation_id": "19:c1524d7c-a06f-456f-8abe-xxxx"
        })

      # - To remove MS teams user using user_id
      user.remove_ms_teams(
        {
      		"tenant_id": "c1981ab2-9aaf-xxxx-xxxx",
      		"service_url": "https://smba.trafficmanager.net/amer",
      		"user_id": "29:1nsLcmJ2RKtYH6Cxxxx-xxxx"
        })

      # - To remove MS teams using incoming webhook
      user.remove_ms_teams(
        {
          "incoming_webhook": {
            "url": "https://wnk1z.webhook.office.com/webhookb2/XXXXXXXXX"
          }
        })

      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Remove Channel types">
    This method will delete/unset all values in specified channel for user (ex: remove all emails attached to user).

    <CodeGroup>
      ```python python theme={"system"}
      # --- To delete all emails associated with user
      user.unset("$email")
      user.unset(["$email", "$sms", "$whatsapp"])

      # Supported channel keys are:
      # $email, $whatsapp, $sms, $androidpush, $iospush, $webpush, $slack, $ms_teams
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Set Preferred language">
    If you want to send notification in user's preferred language, you can set it by passing [language code](https://github.com/suprsend/suprsend-py-sdk/blob/v0.12.0/src/suprsend/language_codes.py) in this method. This is useful especially for the applications which offer vernacular or multi-lingual support.

    ```python theme={"system"}
    user.set_preferred_language("en")
    ```
  </Accordion>

  <Accordion title="Set preferred timezone">
    You can set timezone of user using this method. Value for timezone must be from amongst the [IANA timezones](https://data.iana.org/time-zones/tzdb-2024a/zonenow.tab).

    ```python theme={"system"}
    user.set_timezone("America/Los_Angeles")
    ```
  </Accordion>

  <Accordion title="Set">
    Set is used to add custom user properties. It is an upsert function, meaning any existing property value with the same key will be overwritten on subsequent updates.

    ```python theme={"system"}
    user.set(key, value)
    user.set("name","John Doe")

    user.set({ key1: value1, key2: value2 })
    user.set({"name": "John Doe","city": "San Francisco"})
    ```
  </Accordion>

  <Accordion title="Set Once">
    Works just like user.set, except it will not override already existing property values. This is useful for properties like first\_login\_date.

    ```python theme={"system"}
    user.set_once(key, value)
    user.set_once("first_login","2021-11-02")

    user.set_once({ key1: value1, key2: value2 })
    user.set_once({"first_login": "2021-11-02","signup_date": "2021-11-02"})
    ```
  </Accordion>

  <Accordion title="Unset">
    Unset is used to remove a property key.

    ```python theme={"system"}
    user.unset(key)
    user.unset("name")

    user.unset([key1, key2])
    user.unset(["name","city"])
    ```
  </Accordion>

  <Accordion title="Append">
    This method will append a value to the array list.

    ```python theme={"system"}
    user.append(key, value)
    user.append("played_games", "game_1")

    user.append({ key1: value1, key2: value2 })
    user.append({"played_games": "game_1", "liked_games": "game_2"})
    ```
  </Accordion>

  <Accordion title="Remove">
    This method will remove a value from the array list.

    ```python theme={"system"}
    user.remove(key, value)
    user.remove("played_games", "game_1")

    user.remove({ key1: value1, key2: value2 })
    user.remove({"played_games": "game_1", "liked_games": "game_2"})
    ```
  </Accordion>

  <Accordion title="Increment">
    Increase or decrease integer values on consecutive action, like login count. To reduce a property, provide a negative number for the value.

    ```python theme={"system"}
    user.increment(key, value)
    user.increment("login_count", 1)

    user.increment({ key1: value1, key2: value2 })
    user.increment({"login_count" : 1, "order_count" : 1})
    ```
  </Accordion>
</AccordionGroup>

<Warning>
  After calling `add*/remove*/unset` methods, don't forget to call `users.async_edit()` since user edit is async update and the changes will be sent to SuprSend only after calling this method.
</Warning>

## Bulk Update users

Bulk operations use **UPSERT** to create or update users.
There isn't any limit on number-of-records that can be added to `bulk_users` instance. Use `.append()` on bulk\_users instance to add however-many-records to call in bulk.

<Tip>
  **Rate limit:** 1000 requests per second. The SDK automatically chunks requests based on the size of the payload. So, you don't need to worry about these rate limits while using bulk operations.
</Tip>

<CodeGroup>
  ```python Request theme={"system"}
  # Create bulk instance
  bulk_ins = supr_client.users.get_bulk_edit_instance()

  # Prepare multiple users edit instance
  distinct_id1 = "__distinct_id1__"  # User 1
  u1 = supr_client.users.get_edit_instance(distinct_id1)
  u1.add_email("u1@example.com")

  distinct_id2 = "__distinct_id2__"  # User 2
  u2 = supr_client.users.get_edit_instance(distinct_id2)
  u2.add_email("u2@example.com")

  # Append users to the bulk instance
  bulk_ins.append(u1, u2)

  # -------
  res = bulk_ins.save()
  print(res)
  ```

  ```python Response theme={"system"}
  {
    status = "fail",
    total = 10, # number of records sent in bulk
    success = 0, # number of records succeeded
    failure = 10, # number of records failed
    failed_records = [{"record": {...}, "error": "error_str", "code": 500}]
  }
  ```
</CodeGroup>

<Warning>
  **Bulk API supported in SDK version 0.2.0 and above:**

  Bulk API is supported in SuprSend python-sdk version 0.2.0 and above. If you are using an older version, please upgrade to the latest SDK version.
</Warning>

## Get user details

<CodeGroup>
  ```javascript Request theme={"system"}
  res = supr_client.users.get("_distinct_id_")
  print(res)
  ```

  ```json Response theme={"system"}
  {
    "distinct_id": "_distinct_id_",
    "properties": {
      "name": "John Doe",
      "email": ["johndoe@example.com"],
      "created_at": "2024-01-01T12:00:00Z"
    },
    "status": "active"
  }
  ```
</CodeGroup>

## Delete user

<CodeGroup>
  ```javascript Request theme={"system"}
  res = supr_client.users.delete("_distinct_id_")
  print(res)
  ```

  ```json Response theme={"system"}
   {
   "success": True,
   "status_code": 204
   }
  ```
</CodeGroup>

## Get list of objects subscribed by user

You can pass optional query parameters -`limit`, `before`, `after`

<CodeGroup>
  ```javascript Request theme={"system"}
  res = supr_client.users.get_objects_subscribed_to("_distinct_id_", {"after": "01JJW6HXXXXPB59ARDW85G0KN", "limit": 1})
  print(res)
  ```

  ```json Response theme={"system"}
  {
      "objects": [
        {
          "object_id": "Frontend",
          "type": "Developers",
          "subscribed_at": "2024-02-20T10:15:30Z"
        }
      ],
      "paging": {
        "after": "01JJW6HXXXXPB59ARDW85G0KN",
        "has_more": false
      }
    }
  ```
</CodeGroup>

## Get lists subscribed by user

You can pass optional query parameters -`limit`, `before`, `after`

<CodeGroup>
  ```javascript Request theme={"system"}
  res = supr_client.users. get_lists_subscribed_to("_distinct_id_", {"after": "01JJW6HXXXXPB59ARDW85G0KN", "limit": 1})
  print(res)
  ```

  ```json Response theme={"system"}
  {
    "lists": [
      {
        "list_id": "product_updates",
        "subscribed_at": "2024-02-20T12:00:00Z",
        "status": "subscribed"
      }
    ],
    "paging": {
      "after": "01JJW6HXXXXPB59ARDW85G0KN",
      "has_more": true
    }
  }
  ```
</CodeGroup>
