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

# Update user

> Modify a user's properties.

<Warning>
  If you are still using pre-User Model APIs or SDKs (Mobile SDKs version 4 or
  lower, Web SDKs version 15 or lower), we recommend thorough testing of this
  endpoint before switching to the new User Model. Discrepancies may occur where
  the External ID set through the SDK and the External ID set through the API do
  not generate matching OneSignal IDs. To ensure a smooth transition, consider
  the following options:

  * **Update to the User Model SDKs:** Upgrade to the latest User Model SDKs (Mobile SDK 5+, Web SDK 16+). For more details, refer to the [User Model Migration Guide](/docs/en/user-model-migration-guide).
  * **Continue Using Pre-User Model APIs:** If you are not ready to migrate, continue using the existing APIs for [Adding a Device](/reference/add-a-device), [Editing Tags with External User ID](/reference/edit-tags-with-external-user-id), and [Editing a Device](/reference/edit-device) until the SDK migration is complete.
</Warning>

## Overview

This endpoint updates user-level properties for an existing user in your OneSignal app.

* To change a user's `identity` like `external_id` or custom [Aliases](/docs/en/aliases), use the [Create alias](/reference/create-alias) and [Delete alias](/reference/delete-alias) APIs.
* To manage a user's `subscriptions`, use the [Create Subscription by alias](/reference/create-subscription) or [Create user](/reference/create-user) APIs.

***

## How to use this API

You must supply an alias in the request path:

* `alias_label`: The type of identifier (e.g., `external_id`, `onesignal_id`, or a custom alias label).
* `alias_id`: The corresponding value for that label.

See [Users](/docs/en/users) and [Aliases](/docs/en/aliases) for more info.

***


## OpenAPI

````yaml PATCH /apps/{app_id}/users/by/{alias_label}/{alias_id}
openapi: 3.1.0
info:
  title: api.onesignal.com
  version: '11.6'
servers:
  - url: https://api.onesignal.com
security:
  - {}
paths:
  /apps/{app_id}/users/by/{alias_label}/{alias_id}:
    patch:
      summary: Update user
      description: Modify a user's properties.
      operationId: update-user
      parameters:
        - name: app_id
          in: path
          description: >-
            Your OneSignal App ID in UUID v4 format. See [Keys &
            IDs](/docs/en/keys-and-ids).
          schema:
            type: string
          required: true
        - name: alias_label
          in: path
          description: >-
            The alias name or key to locate the user. Most commonly set as
            `external_id` but can be the `onesignal_id` or a [custom
            alias](/docs/aliases).
          schema:
            type: string
          required: true
        - name: alias_id
          in: path
          description: The specific identifier for the given alias to identify the user.
          schema:
            type: string
          required: true
        - name: Authorization
          in: header
          description: >-
            Your App API key with prefix `Key `. See [Keys &
            IDs](/docs/en/keys-and-ids).
          required: true
          schema:
            type: string
            default: Key YOUR_APP_API_KEY
        - name: onesignal-subscription-id
          in: header
          description: >-
            Optional. Identifies a specific subscription to update. Some user
            properties, such as Session Time and Session Count, will update
            values on both the User and the Subscription.
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                properties:
                  type: object
                  description: >-
                    Represents user profile data for a given user, including
                    tags, preferences, user activity, and other valuable
                    properties.
                  properties:
                    tags:
                      type: object
                      description: >-
                        Custom user events or properties made of key-value pairs
                        of string values. See
                        [Tags](/docs/en/add-user-data-tags). Does not support
                        arrays or other nested objects. Example:
                        `{'foo':'bar','this':'that'}`
                      format: json
                    language:
                      type: string
                      description: >-
                        Language Abbreviation in ISO 639-1 format. See
                        [supported
                        languages](/docs/en/multi-language-messaging#supported-languages).
                        Must be lower-case.
                      default: en
                    timezone_id:
                      type: string
                      description: >-
                        Timezone ID based on the [tz database "TZ
                        identifier"](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List).
                      default: America/Los_Angeles
                    lat:
                      type: number
                      description: >-
                        User's current latitude. Acceptable values range between
                        `-90` to `90`.
                      format: float
                    long:
                      type: number
                      description: >-
                        User's current longitude. Acceptable values range
                        between `-180` to `180`.
                      format: float
                    country:
                      type: string
                      description: >-
                        Country code in [ISO 3166-1 Alpha 2
                        format](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Officially_assigned_code_elements).
                        Must be upper-case.
                      default: US
                    first_active:
                      type: integer
                      description: >-
                        Unix timestamp in seconds representing when the user was
                        created.
                      format: int32
                    last_active:
                      type: integer
                      description: >-
                        Unix timestamp in seconds representing the most recent
                        time the user was active in your app.
                      format: int32
                    ip:
                      type: string
                      description: IPv4 or IPv6, response only
                    test_user_name:
                      type: string
                      description: >-
                        A label for marking this user as a [Test
                        user](/docs/en/test-users).
                deltas:
                  type: object
                  description: >-
                    User properties that change frequently and generally only
                    increment.
                  properties:
                    session_time:
                      type: integer
                      description: >-
                        The total amount of time the user has had the app open
                        in seconds.
                      format: int32
                    session_count:
                      type: integer
                      description: The total amount of times the user has opened the app.
                      format: int32
                    purchases:
                      type: array
                      description: List of purchases
                      items:
                        properties:
                          sku:
                            type: string
                            description: The SKU of the item purchased.
                          iso:
                            type: string
                            description: The Currency Code
                            default: USD
                          amount:
                            type: string
                            description: The amount spent on the item.
                          count:
                            type: integer
                            description: The number of times the item has been purchased.
                        type: object
      responses:
        '202':
          description: '202'
          content:
            application/json:
              examples:
                Result:
                  value:
                    properties:
                      language: en
                      timezone_id: PST
                      lat: 90
                      long: 135
                      country: US
                      first_active: 1678215680
                      last_active: 1678215682
                      test_user_name: QA Device - Jane
                      purchases:
                        - amount: $33.33
                          count: 3
                          iso: USD
                          sku: item
              schema:
                type: object
                properties:
                  properties:
                    type: object
                    properties:
                      language:
                        type: string
                        example: en
                      timezone_id:
                        type: string
                        example: PST
                      lat:
                        type: integer
                        example: 90
                        default: 0
                      long:
                        type: integer
                        example: 135
                        default: 0
                      country:
                        type: string
                        example: US
                      first_active:
                        type: integer
                        example: 1678215680
                        default: 0
                      last_active:
                        type: integer
                        example: 1678215682
                        default: 0
                      test_user_name:
                        type: string
                        example: QA Device - Jane
                      purchases:
                        type: array
                        items:
                          type: object
                          properties:
                            amount:
                              type: string
                              example: $33.33
                            count:
                              type: integer
                              example: 3
                              default: 0
                            iso:
                              type: string
                              example: USD
                            sku:
                              type: string
                              example: item
        '400':
          description: '400'
          content:
            application/json:
              examples:
                Result:
                  value:
                    errors:
                      - code: internal error code
                        title: example error title
              schema:
                $ref: '#/components/schemas/StructuredErrorResponse'
        '401':
          description: '401'
          content:
            application/json:
              examples:
                Result:
                  value:
                    errors:
                      - code: auth-1
                        title: >-
                          This operation requires 'Authorization' in the HTTP
                          header
              schema:
                $ref: '#/components/schemas/StructuredErrorResponse'
        '409':
          description: '409'
          content:
            application/json:
              examples:
                Result:
                  value:
                    errors:
                      - code: Subscription Limit Exceeded
                        title: Example error title
              schema:
                $ref: '#/components/schemas/StructuredErrorResponse'
        '429':
          description: >-
            Rate limit exceeded. Wait the number of seconds in the `Retry-After`
            header before retrying.
          headers:
            Retry-After:
              description: >-
                Number of seconds to wait before retrying the request. Always
                emitted on 429 responses.
              schema:
                type: integer
                minimum: 0
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StructuredErrorResponse'
              example:
                errors:
                  - code: Rate Limit Exceeded
                    title: API rate limit exceeded
        '503':
          description: >-
            Service temporarily unavailable. Retry after a short backoff. The
            body may be empty or non-JSON in some failure modes.
          headers:
            Retry-After:
              description: >-
                Number of seconds to wait before retrying. Optional — may be
                absent when the response is generated upstream.
              schema:
                type: integer
                minimum: 0
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BasicErrorResponse'
              example:
                errors:
                  - Service temporarily unavailable
      deprecated: false
      x-codeSamples:
        - lang: typescript
          label: Node.js SDK
          source: |-
            import Onesignal from '@onesignal/node-onesignal';

            const configuration = Onesignal.createConfiguration({
                restApiKey: 'YOUR_REST_API_KEY',
            });
            const apiInstance = new Onesignal.DefaultApi(configuration);

            // string
            const appId: string = "00000000-0000-0000-0000-000000000000";
            // string
            const aliasLabel: string = "external_id";
            // string
            const aliasId: string = "YOUR_USER_EXTERNAL_ID";
            // UpdateUserRequest
            const updateUserRequest: Onesignal.UpdateUserRequest = {
                properties: {
                  tags: {},
                  language: "language_example",
                  timezone_id: "timezone_id_example",
                  lat: 3.14,
                  long: 3.14,
                  country: "country_example",
                  first_active: 1,
                  last_active: 1,
                  amount_spent: 3.14,
                  purchases: [
                    {
                      sku: "sku_example",
                      amount: "amount_example",
                      iso: "iso_example",
                      count: 1,
                    },
                  ],
                  ip: "ip_example",
                },
                refresh_device_metadata: false,
                deltas: {
                  session_time: 1,
                  session_count: 1,
                  purchases: [
                    {
                      sku: "sku_example",
                      amount: "amount_example",
                      iso: "iso_example",
                      count: 1,
                    },
                  ],
                },
              };

            try {
              const response = await apiInstance.updateUser(appId, aliasLabel, aliasId, updateUserRequest);
              console.log(response);
            } catch (e) {
              if (e instanceof Onesignal.ApiException) {
                // `e.errorMessages` flattens any error-envelope shape to a `string[]`;
                // the raw parsed body remains on `e.body`.
                console.error("updateUser failed: HTTP " + e.code, e.errorMessages);
              } else {
                throw e;
              }
            }
        - lang: python
          label: Python SDK
          source: >-
            import onesignal

            from onesignal.api import default_api

            from onesignal.models import *

            from pprint import pprint


            # See configuration.py for a list of all supported configuration
            parameters.

            # Some of the OneSignal endpoints require ORGANIZATION_API_KEY token
            for authorization, while others require REST_API_KEY.

            # We recommend adding both of them in the configuration page so that
            you will not need to figure it out yourself.

            configuration = onesignal.Configuration(
                rest_api_key = "YOUR_REST_API_KEY", # App REST API key required for most endpoints
                organization_api_key = "YOUR_ORGANIZATION_API_KEY" # Organization key is only required for creating new apps and other top-level endpoints
            )



            # Enter a context with an instance of the API client

            with onesignal.ApiClient(configuration) as api_client:
                # Create an instance of the API class
                api_instance = default_api.DefaultApi(api_client)
                app_id = "00000000-0000-0000-0000-000000000000" 
                alias_label = "external_id" 
                alias_id = "YOUR_USER_EXTERNAL_ID" 
                update_user_request = UpdateUserRequest(
                    properties=PropertiesObject(
                        tags={},
                        language="language_example",
                        timezone_id="timezone_id_example",
                        lat=3.14,
                        long=3.14,
                        country="country_example",
                        first_active=1,
                        last_active=1,
                        amount_spent=3.14,
                        purchases=[
                            Purchase(
                                sku="sku_example",
                                amount="amount_example",
                                iso="iso_example",
                                count=1,
                            ),
                        ],
                        ip="ip_example",
                    ),
                    refresh_device_metadata=False,
                    deltas=PropertiesDeltas(
                        session_time=1,
                        session_count=1,
                        purchases=[
                            Purchase(
                                sku="sku_example",
                                amount="amount_example",
                                iso="iso_example",
                                count=1,
                            ),
                        ],
                    ),
                ) 

                try:
                    api_response = api_instance.update_user(app_id, alias_label, alias_id, update_user_request)
                    pprint(api_response)
                except onesignal.ApiException as e:
                    print("Exception when calling DefaultApi->update_user: %s\n" % e)
                    print("Status Code: %s" % e.status)
                    print("Response Body: %s" % e.body)
        - lang: php
          label: PHP SDK
          source: >-
            <?php

            require_once(__DIR__ . '/vendor/autoload.php');



            // Configure Bearer authorization: rest_api_key

            $config = onesignal\client\Configuration::getDefaultConfiguration()
                                                            ->setRestApiKeyToken('YOUR_REST_API_KEY')
                                                            ->setOrganizationApiKeyToken('YOUR_ORGANIZATION_API_KEY');



            $apiInstance = new onesignal\client\Api\DefaultApi(
                // If you want use custom http client, pass your client which implements `GuzzleHttp\ClientInterface`.
                // This is optional, `GuzzleHttp\Client` will be used as default.
                new GuzzleHttp\Client(),
                $config
            );

            $app_id = '00000000-0000-0000-0000-000000000000'; // string

            $alias_label = 'external_id'; // string

            $alias_id = 'YOUR_USER_EXTERNAL_ID'; // string

            $update_user_request = new
            \onesignal\client\model\UpdateUserRequest(); //
            \onesignal\client\model\UpdateUserRequest


            try {
                $result = $apiInstance->updateUser($app_id, $alias_label, $alias_id, $update_user_request);
                print_r($result);
            } catch (\onesignal\client\ApiException $e) {
                echo 'Exception when calling DefaultApi->updateUser: ', $e->getMessage(), PHP_EOL;
                echo 'Status Code: ', $e->getCode(), PHP_EOL;
                // getErrorMessages() flattens any error-envelope shape to a string[];
                // the raw body remains on getResponseBody().
                echo 'Error Messages: ', implode(', ', $e->getErrorMessages()), PHP_EOL;
                echo 'Response Body: ', $e->getResponseBody(), PHP_EOL;
            } catch (\Exception $e) {
                echo 'Exception when calling DefaultApi->updateUser: ', $e->getMessage(), PHP_EOL;
            }
        - lang: go
          label: Go SDK
          source: |-
            package main

            import (
                "context"
                "fmt"
                "os"

                "github.com/OneSignal/onesignal-go-api/v5"
            )

            func main() {
                appId := "00000000-0000-0000-0000-000000000000" // string | 
                aliasLabel := "external_id" // string | 
                aliasId := "YOUR_USER_EXTERNAL_ID" // string | 
                updateUserRequest := *onesignal.NewUpdateUserRequest() // UpdateUserRequest | 

                configuration := onesignal.NewConfiguration()
                apiClient := onesignal.NewAPIClient(configuration)

                restAuth := context.WithValue(context.Background(), onesignal.RestApiKey, "YOUR_REST_API_KEY") // App REST API key required for most endpoints

                resp, r, err := apiClient.DefaultApi.UpdateUser(restAuth, appId, aliasLabel, aliasId).UpdateUserRequest(updateUserRequest).Execute()

                if err != nil {
                    fmt.Fprintf(os.Stderr, "Error when calling `DefaultApi.UpdateUser``: %v\n", err)
                    fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r)
                    if apiErr, ok := err.(*onesignal.GenericOpenAPIError); ok {
                        // ErrorMessages() flattens any error-envelope shape to a []string;
                        // the raw body remains on Body().
                        fmt.Fprintf(os.Stderr, "Error Messages: %v\n", apiErr.ErrorMessages())
                        fmt.Fprintf(os.Stderr, "Response Body: %s\n", apiErr.Body())
                    }
                }
                // response from `UpdateUser`: PropertiesBody
                fmt.Fprintf(os.Stdout, "Response from `DefaultApi.UpdateUser`: %v\n", resp)
            }
        - lang: ruby
          label: Ruby SDK
          source: >-
            require 'onesignal'

            # setup authorization

            OneSignal.configure do |config|
              # Configure Bearer authorization: rest_api_key
              config.rest_api_key = 'YOUR_REST_API_KEY'

            end


            api_instance = OneSignal::DefaultApi.new

            app_id = '00000000-0000-0000-0000-000000000000' # String | 

            alias_label = 'external_id' # String | 

            alias_id = 'YOUR_USER_EXTERNAL_ID' # String | 

            update_user_request = OneSignal::UpdateUserRequest.new #
            UpdateUserRequest | 


            begin
              
              result = api_instance.update_user(app_id, alias_label, alias_id, update_user_request)
              p result
            rescue OneSignal::ApiError => e
              puts "Error when calling DefaultApi->update_user: #{e}"
              puts "Status Code: #{e.code}"
              # `e.error_messages` flattens any error-envelope shape to an Array<String>;
              # the raw body remains on `e.response_body`.
              puts "Error Messages: #{e.error_messages}"
              puts "Response Body: #{e.response_body}"
            end
        - lang: java
          label: Java SDK
          source: |-
            // Import classes:
            import com.onesignal.client.ApiClient;
            import com.onesignal.client.ApiException;
            import com.onesignal.client.Configuration;
            import com.onesignal.client.auth.*;
            import com.onesignal.client.model.*;
            import com.onesignal.client.api.DefaultApi;

            public class Example {
              public static void main(String[] args) {
                ApiClient defaultClient = Configuration.getDefaultApiClient();
                defaultClient.setBasePath("https://api.onesignal.com");
                
                // Configure HTTP bearer authorization: rest_api_key
                HttpBearerAuth rest_api_key = (HttpBearerAuth) defaultClient.getAuthentication("rest_api_key");
                rest_api_key.setBearerToken("YOUR_REST_API_KEY");

                DefaultApi apiInstance = new DefaultApi(defaultClient);
                String appId = "00000000-0000-0000-0000-000000000000"; // String | 
                String aliasLabel = "external_id"; // String | 
                String aliasId = "YOUR_USER_EXTERNAL_ID"; // String | 
                UpdateUserRequest updateUserRequest = new UpdateUserRequest(); // UpdateUserRequest | 
                try {
                  PropertiesBody result = apiInstance.updateUser(appId, aliasLabel, aliasId, updateUserRequest);
                  System.out.println(result);
                } catch (ApiException e) {
                  System.err.println("Exception when calling DefaultApi#updateUser");
                  System.err.println("Status code: " + e.getCode());
                  // getErrorMessages() flattens any error-envelope shape to a List<String>;
                  // the raw body remains on getResponseBody().
                  System.err.println("Error messages: " + e.getErrorMessages());
                  System.err.println("Reason: " + e.getResponseBody());
                  System.err.println("Response headers: " + e.getResponseHeaders());
                  e.printStackTrace();
                }
              }
            }
        - lang: csharp
          label: C# SDK
          source: |-
            using System;
            using System.Collections.Generic;
            using System.Diagnostics;
            using OneSignalApi.Api;
            using OneSignalApi.Client;
            using OneSignalApi.Model;

            namespace Example
            {
                public class UpdateUserExample
                {
                    public static void Main()
                    {
                        Configuration config = new Configuration();
                        config.BasePath = "https://api.onesignal.com";
                        // Configure Bearer token for authorization: rest_api_key
                        config.AccessToken = "YOUR_REST_API_KEY";

                        var apiInstance = new DefaultApi(config);
                        var appId = "00000000-0000-0000-0000-000000000000";  // string | 
                        var aliasLabel = "external_id";  // string | 
                        var aliasId = "YOUR_USER_EXTERNAL_ID";  // string | 
                        var updateUserRequest = new UpdateUserRequest(); // UpdateUserRequest | 

                        try
                        {
                            PropertiesBody result = apiInstance.UpdateUser(appId, aliasLabel, aliasId, updateUserRequest);
                            Debug.WriteLine(result);
                        }
                        catch (ApiException  e)
                        {
                            Debug.Print("Exception when calling DefaultApi.UpdateUser: " + e.Message );
                            Debug.Print("Status Code: "+ e.ErrorCode);
                            // e.ErrorMessages flattens any error-envelope shape to an IReadOnlyList<string>;
                            // the raw body remains on e.ErrorContent.
                            Debug.Print("Error Messages: " + string.Join(", ", e.ErrorMessages));
                            Debug.Print("Response Body: " + e.ErrorContent);
                            Debug.Print(e.StackTrace);
                        }
                    }
                }
            }
        - lang: rust
          label: Rust SDK
          source: |-
            use onesignal_rust_api::apis::configuration::Configuration;
            use onesignal_rust_api::apis::default_api;

            use onesignal_rust_api::models;


            #[tokio::main]
            async fn main() {
                let mut configuration = Configuration::new();
                configuration.rest_api_key_token = Some("YOUR_REST_API_KEY".to_string());


                // Realistic values are pulled from the spec's `example:` fields where present.
                let app_id: &str = "00000000-0000-0000-0000-000000000000";
                let alias_label: &str = "external_id";
                let alias_id: &str = "YOUR_USER_EXTERNAL_ID";
                let update_user_request: models::UpdateUserRequest = todo!();

                match default_api::update_user(&configuration, app_id, alias_label, alias_id, update_user_request).await {
                    Ok(resp) => println!("{:?}", resp),
                    Err(e @ onesignal_rust_api::apis::Error::ResponseError(_)) => {
                        // `e.error_messages()` flattens any error-envelope shape to a Vec<String>;
                        // the raw response remains on the ResponseError variant.
                        eprintln!("update_user failed: {:?}", e.error_messages());
                    }
                    Err(e) => eprintln!("update_user failed: {:?}", e),
                }
            }
components:
  schemas:
    StructuredErrorResponse:
      type: object
      properties:
        errors:
          type: array
          items:
            $ref: '#/components/schemas/StructuredErrorItem'
    BasicErrorResponse:
      type: object
      properties:
        errors:
          type: array
          items:
            type: string
          description: One or more human-readable error messages.
        success:
          type: boolean
          description: >-
            Present (and `false`) on some endpoints (notifications, templates,
            segments). Not emitted by every endpoint.
        reference:
          type: array
          items:
            type: string
          description: >-
            Documentation URL fragments related to the error. Only emitted by
            the API-key auth error helpers.
    StructuredErrorItem:
      type: object
      required:
        - code
        - title
      properties:
        code:
          type: string
          description: >-
            Stable error-code identifier. Use this for programmatic branching in
            your integration.
        title:
          type: string
          description: >-
            Human-readable error message intended for logs and operator-facing
            surfaces.
        meta:
          type: object
          additionalProperties: true
          description: >-
            Optional structured details about this specific error. The shape of
            `meta` varies by `code` — for example, the create-user `Conflict`
            code returns `{ conflicting_aliases: { [alias_label]: alias_id } }`.

````