> ## 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.

# Transfer Subscription

> Transfer a Subscription to a different user within the same OneSignal app. Useful for associating existing Subscriptions like push, email, or SMS with a new or updated user identity.

## Overview

Use this API to transfer a Subscription from one user to another within the same OneSignal app.

It is highly recommended to use our web and mobile SDKs to set and update the External ID with the `login` method instead of this API. Your app or website may continue to be setting the wrong External ID. Make sure to only use this API if you are setting the same External ID within your app or website.

This is typically used when:

* You want to reassign an existing push, email, or SMS Subscription to a new or updated user.
* You have changed how you're identifying users (e.g., migrating from anonymous to known users).

<Note>
  - Subscriptions **cannot be transferred across different OneSignal apps**.
  - For email and SMS Subscriptions, you can instead create new ones using [Create User](/reference/create-user).
  - For push Subscriptions, platform limitations may apply—see [Subscriptions](/docs/en/subscriptions#importing-push-subscriptions) for details.
</Note>

***

## How to Use This API

### Required Path Parameter: `subscription_id`

You must know the `subscription_id` of the subscription to be transferred. This is a unique UUID assigned by OneSignal.

### Required Body Parameter: `identity` (object)

This specifies the user the subscription should be moved to. Only **one alias** should be used per request. You can identify the target user using one of:

* `external_id` (recommended)
* `onesignal_id`
* A [custom alias](/docs/en/aliases)

***


## OpenAPI

````yaml PATCH /apps/{app_id}/subscriptions/{subscription_id}/owner
openapi: 3.1.0
info:
  title: api.onesignal.com
  version: '11.6'
servers:
  - url: https://api.onesignal.com
security:
  - {}
paths:
  /apps/{app_id}/subscriptions/{subscription_id}/owner:
    patch:
      summary: Transfer subscription
      description: >-
        Transfer a Subscription to a different user within the same OneSignal
        app. Useful for associating existing Subscriptions like push, email, or
        SMS with a new or updated user identity.
      operationId: transfer-subscription
      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: subscription_id
          in: path
          description: >-
            The unique Subscription ID in UUID v4 format to transfer to the new
            user.
          schema:
            type: string
          required: true
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                identity:
                  type: object
                  description: >-
                    Identifies the user that this subscription is moved to. Must
                    contain exactly one alias.
                  properties:
                    external_id:
                      type: string
                      description: >-
                        The main user ID to identify the user. See
                        [Users](/docs/users).
                      default: test_external_id
                    onesignal_id:
                      type: string
      responses:
        '200':
          description: '200'
          content:
            application/json:
              examples:
                Result:
                  value:
                    identity:
                      external_id: the-external-id-transferred-to
                      onesignal_id: the-onesignal-id-transferred-to
              schema:
                type: object
                properties:
                  identity:
                    type: object
                    properties:
                      external_id:
                        type: string
                        example: the-external-id-transferred-to
                      onesignal_id:
                        type: string
                        example: the-onesignal-id-transferred-to
        '400':
          description: '400'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BasicErrorResponse'
              example:
                errors:
                  - Details about the error.
        '403':
          description: '403'
          content:
            application/json:
              examples:
                Result:
                  value:
                    errors:
                      - Forbidden
              schema:
                $ref: '#/components/schemas/BasicErrorResponse'
        '404':
          description: '404'
          content:
            application/json:
              examples:
                Result:
                  value:
                    errors:
                      - code: subscription-0
                        title: Subscription not found
              schema:
                $ref: '#/components/schemas/StructuredErrorResponse'
        '429':
          description: '429'
          content:
            application/json:
              examples:
                Result:
                  value:
                    errors:
                      - code: Rate Limit Exceeded
                        title: Example error title
                        meta: {}
              schema:
                $ref: '#/components/schemas/StructuredErrorResponse'
          headers:
            Retry-After:
              description: >-
                Number of seconds to wait before retrying the request. Always
                emitted on 429 responses.
              schema:
                type: integer
                minimum: 0
        '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 subscriptionId: string =
            "7e4c5b9a-1f60-4d07-9b1a-2e8c8d2cae51";

            // TransferSubscriptionRequestBody

            const transferSubscriptionRequestBody:
            Onesignal.TransferSubscriptionRequestBody = {
                identity: {
                  "key": "key_example",
                },
              };

            try {
              const response = await apiInstance.transferSubscription(appId, subscriptionId, transferSubscriptionRequestBody);
              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("transferSubscription 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" 
                subscription_id = "7e4c5b9a-1f60-4d07-9b1a-2e8c8d2cae51" 
                transfer_subscription_request_body = TransferSubscriptionRequestBody(
                    identity={
                        "key": "key_example",
                    },
                ) 

                try:
                    api_response = api_instance.transfer_subscription(app_id, subscription_id, transfer_subscription_request_body)
                    pprint(api_response)
                except onesignal.ApiException as e:
                    print("Exception when calling DefaultApi->transfer_subscription: %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

            $subscription_id = '7e4c5b9a-1f60-4d07-9b1a-2e8c8d2cae51'; // string

            $transfer_subscription_request_body = new
            \onesignal\client\model\TransferSubscriptionRequestBody(); //
            \onesignal\client\model\TransferSubscriptionRequestBody


            try {
                $result = $apiInstance->transferSubscription($app_id, $subscription_id, $transfer_subscription_request_body);
                print_r($result);
            } catch (\onesignal\client\ApiException $e) {
                echo 'Exception when calling DefaultApi->transferSubscription: ', $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->transferSubscription: ', $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 | 
                subscriptionId := "7e4c5b9a-1f60-4d07-9b1a-2e8c8d2cae51" // string | 
                transferSubscriptionRequestBody := *onesignal.NewTransferSubscriptionRequestBody() // TransferSubscriptionRequestBody | 

                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.TransferSubscription(restAuth, appId, subscriptionId).TransferSubscriptionRequestBody(transferSubscriptionRequestBody).Execute()

                if err != nil {
                    fmt.Fprintf(os.Stderr, "Error when calling `DefaultApi.TransferSubscription``: %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 `TransferSubscription`: UserIdentityBody
                fmt.Fprintf(os.Stdout, "Response from `DefaultApi.TransferSubscription`: %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 | 

            subscription_id = '7e4c5b9a-1f60-4d07-9b1a-2e8c8d2cae51' # String | 

            transfer_subscription_request_body =
            OneSignal::TransferSubscriptionRequestBody.new #
            TransferSubscriptionRequestBody | 


            begin
              
              result = api_instance.transfer_subscription(app_id, subscription_id, transfer_subscription_request_body)
              p result
            rescue OneSignal::ApiError => e
              puts "Error when calling DefaultApi->transfer_subscription: #{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 subscriptionId = "7e4c5b9a-1f60-4d07-9b1a-2e8c8d2cae51"; // String | 
                TransferSubscriptionRequestBody transferSubscriptionRequestBody = new TransferSubscriptionRequestBody(); // TransferSubscriptionRequestBody | 
                try {
                  UserIdentityBody result = apiInstance.transferSubscription(appId, subscriptionId, transferSubscriptionRequestBody);
                  System.out.println(result);
                } catch (ApiException e) {
                  System.err.println("Exception when calling DefaultApi#transferSubscription");
                  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 TransferSubscriptionExample
                {
                    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 subscriptionId = "7e4c5b9a-1f60-4d07-9b1a-2e8c8d2cae51";  // string | 
                        var transferSubscriptionRequestBody = new TransferSubscriptionRequestBody(); // TransferSubscriptionRequestBody | 

                        try
                        {
                            UserIdentityBody result = apiInstance.TransferSubscription(appId, subscriptionId, transferSubscriptionRequestBody);
                            Debug.WriteLine(result);
                        }
                        catch (ApiException  e)
                        {
                            Debug.Print("Exception when calling DefaultApi.TransferSubscription: " + 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 subscription_id: &str = "7e4c5b9a-1f60-4d07-9b1a-2e8c8d2cae51";
                let transfer_subscription_request_body: models::TransferSubscriptionRequestBody = todo!();

                match default_api::transfer_subscription(&configuration, app_id, subscription_id, transfer_subscription_request_body).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!("transfer_subscription failed: {:?}", e.error_messages());
                    }
                    Err(e) => eprintln!("transfer_subscription failed: {:?}", e),
                }
            }
components:
  schemas:
    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.
    StructuredErrorResponse:
      type: object
      properties:
        errors:
          type: array
          items:
            $ref: '#/components/schemas/StructuredErrorItem'
    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 } }`.

````