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

# Rotate API key

> Rotate an existing App API Key (Rich Authentication Token) for a OneSignal app. Useful when a token is compromised or needs replacement without creating a new key from scratch.

## Overview

Use this API to rotate a **Rich Authentication Token** (App API Key) for a specific OneSignal app. Rotating a key revokes the current token and generates a new one under the same configuration—ideal when a token is lost or compromised but you don’t want to recreate and reconfigure it from scratch.

<Note>
  For background on different OneSignal API keys, see [Keys & IDs](/docs/en/keys-and-ids).
</Note>

***

## How to use this API

Using your Organization API key (available in [Organizations > Keys & IDs](/docs/en/keys-and-ids#organization-api-key)) you can rotate an app token associated with a given app.

The `token_id` is a OneSignal-generated ID specific for the API key. This is not the API key itself. It is returned when creating an API key with [Create API key](/reference/create-api-key). It can be found in the OneSignal dashboard and in the response body of the [View API keys](/reference/view-api-keys) request.

***


## OpenAPI

````yaml POST /apps/{app_id}/auth/tokens/{token_id}/rotate
openapi: 3.1.0
info:
  title: api.onesignal.com
  version: '11.6'
servers:
  - url: https://api.onesignal.com
security:
  - {}
paths:
  /apps/{app_id}/auth/tokens/{token_id}/rotate:
    post:
      summary: Rotate API key
      description: >-
        Rotate an existing App API Key (Rich Authentication Token) for a
        OneSignal app. Useful when a token is compromised or needs replacement
        without creating a new key from scratch.
      operationId: rotate-api-key
      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
            default: YOUR_APP_ID
          required: true
        - name: Content-Type
          in: header
          required: true
          schema:
            type: string
            default: application/json
        - name: Authorization
          in: header
          description: >-
            Your Organization API key with prefix `Key `. See [Keys &
            IDs](/docs/en/keys-and-ids).
          required: true
          schema:
            type: string
            default: Key YOUR_ORGANIZATION_API_KEY
        - name: token_id
          in: path
          description: >-
            The OneSignal-generated ID specific to the API key. This is not the
            API key itself. It is returned when creating an API key with [Create
            API key](/reference/create-api-key). It can be found in the
            OneSignal dashboard and in the response body of the [View API
            keys](/reference/view-api-keys) request.
          schema:
            type: string
          required: true
      responses:
        '200':
          description: >-
            The rotated key's new secret. Only `formatted_token` is populated;
            everything else stays the same as before the rotate. Update your
            integration with the new secret immediately.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiKeyToken'
        '400':
          description: '400'
          content:
            application/json:
              examples:
                Result:
                  value: '{}'
              schema:
                type: object
                properties: {}
        '403':
          description: Forbidden. Your organization permissions do not allow this action.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BasicErrorResponse'
              example:
                errors:
                  - Current organization permissions do not allow this action.
        '404':
          description: Token not found in this app, or the App ID was wrong.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BasicErrorResponse'
              example:
                errors:
                  - Token not found
        '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/BasicErrorResponse'
              example:
                errors:
                  - 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({
                organizationApiKey: '<YOUR_ORGANIZATION_API_KEY>',
            });
            const apiInstance = new Onesignal.DefaultApi(configuration);

            // string
            const appId: string = "00000000-0000-0000-0000-000000000000";
            // string
            const tokenId: string = "0aa1b2c3-d4e5-46f7-8899-aabbccddeeff";

            try {
              const response = await apiInstance.rotateApiKey(appId, tokenId);
              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("rotateApiKey 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_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" 
                token_id = "0aa1b2c3-d4e5-46f7-8899-aabbccddeeff" 

                # example passing only required values which don't have defaults set
                try:
                    # Rotate API key
                    api_response = api_instance.rotate_api_key(app_id, token_id)
                    pprint(api_response)
                except onesignal.ApiException as e:
                    print("Exception when calling DefaultApi->rotate_api_key: %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: organization_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
            $token_id = '0aa1b2c3-d4e5-46f7-8899-aabbccddeeff'; // string

            try {
                $result = $apiInstance->rotateApiKey($app_id, $token_id);
                print_r($result);
            } catch (\onesignal\client\ApiException $e) {
                echo 'Exception when calling DefaultApi->rotateApiKey: ', $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->rotateApiKey: ', $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 | 
                tokenId := "0aa1b2c3-d4e5-46f7-8899-aabbccddeeff" // string | 

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

                orgAuth := context.WithValue(context.Background(), onesignal.OrganizationApiKey, "YOUR_ORGANIZATION_API_KEY") // Organization API key is only required for creating new apps and other top-level endpoints

                resp, r, err := apiClient.DefaultApi.RotateApiKey(orgAuth, appId, tokenId).Execute()

                if err != nil {
                    fmt.Fprintf(os.Stderr, "Error when calling `DefaultApi.RotateApiKey``: %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 `RotateApiKey`: CreateApiKeyResponse
                fmt.Fprintf(os.Stdout, "Response from `DefaultApi.RotateApiKey`: %v\n", resp)
            }
        - lang: ruby
          label: Ruby SDK
          source: |-
            require 'onesignal'
            # setup authorization
            OneSignal.configure do |config|
              # Configure Bearer authorization: organization_api_key
              config.organization_api_key = 'YOUR_BEARER_TOKEN'

            end

            api_instance = OneSignal::DefaultApi.new
            app_id = '00000000-0000-0000-0000-000000000000' # String | 
            token_id = '0aa1b2c3-d4e5-46f7-8899-aabbccddeeff' # String | 

            begin
              # Rotate API key
              result = api_instance.rotate_api_key(app_id, token_id)
              p result
            rescue OneSignal::ApiError => e
              puts "Error when calling DefaultApi->rotate_api_key: #{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: organization_api_key
                HttpBearerAuth organization_api_key = (HttpBearerAuth) defaultClient.getAuthentication("organization_api_key");
                organization_api_key.setBearerToken("BEARER TOKEN");

                DefaultApi apiInstance = new DefaultApi(defaultClient);
                String appId = "00000000-0000-0000-0000-000000000000"; // String | 
                String tokenId = "0aa1b2c3-d4e5-46f7-8899-aabbccddeeff"; // String | 
                try {
                  CreateApiKeyResponse result = apiInstance.rotateApiKey(appId, tokenId);
                  System.out.println(result);
                } catch (ApiException e) {
                  System.err.println("Exception when calling DefaultApi#rotateApiKey");
                  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 RotateApiKeyExample
                {
                    public static void Main()
                    {
                        Configuration config = new Configuration();
                        config.BasePath = "https://api.onesignal.com";
                        // Configure Bearer token for authorization: organization_api_key
                        config.AccessToken = "YOUR_BEARER_TOKEN";

                        var apiInstance = new DefaultApi(config);
                        var appId = "00000000-0000-0000-0000-000000000000";  // string | 
                        var tokenId = "0aa1b2c3-d4e5-46f7-8899-aabbccddeeff";  // string | 

                        try
                        {
                            // Rotate API key
                            CreateApiKeyResponse result = apiInstance.RotateApiKey(appId, tokenId);
                            Debug.WriteLine(result);
                        }
                        catch (ApiException  e)
                        {
                            Debug.Print("Exception when calling DefaultApi.RotateApiKey: " + 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;


            #[tokio::main]
            async fn main() {
                let mut configuration = Configuration::new();
                configuration.organization_api_key_token = Some("YOUR_ORGANIZATION_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 token_id: &str = "0aa1b2c3-d4e5-46f7-8899-aabbccddeeff";

                match default_api::rotate_api_key(&configuration, app_id, token_id).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!("rotate_api_key failed: {:?}", e.error_messages());
                    }
                    Err(e) => eprintln!("rotate_api_key failed: {:?}", e),
                }
            }
components:
  schemas:
    ApiKeyToken:
      type: object
      description: >-
        An API Key Token record (Rich Authentication Token). Different
        operations return different subsets of these fields:


        - **GET tokens** lists every field except `formatted_token`.

        - **POST tokens** (create) returns `token_id` and `formatted_token`.

        - **POST tokens/{id}/rotate** returns `formatted_token` only.

        - **PATCH tokens/{id}** updates the record; the response body is
        currently empty (consumers should re-fetch via GET).


        `formatted_token` is the actual REST API Key and is shown ONCE —
        OneSignal does not store it. Keep it secret.
      properties:
        token_id:
          type: string
          format: uuid
          description: >-
            OneSignal-generated identifier for this API key. NOT the API key
            itself — use this to manage the key in subsequent calls.
        name:
          type: string
          description: >-
            Internal name set when the key was created or last updated. Maximum
            128 characters.
        ip_allowlist_mode:
          type: string
          enum:
            - disabled
            - explicit
          description: >-
            When `explicit`, only requests from IP addresses matching
            `ip_allowlist` may use this key. Defaults to `disabled`.
        ip_allowlist:
          type: array
          items:
            type: string
          description: >-
            Allowed CIDR ranges. Only enforced when `ip_allowlist_mode` is
            `explicit`.
        created_at:
          type: string
          format: date-time
          description: ISO-8601 timestamp when the key was created.
        updated_at:
          type: string
          format: date-time
          description: ISO-8601 timestamp when the key was last updated.
        formatted_token:
          type: string
          description: >-
            The actual Rich Authentication Token (REST API Key). Returned in
            plaintext ONLY by the create and rotate endpoints, and ONLY
            immediately after that call. OneSignal does not store the secret —
            if you lose it, you must rotate the key. See [Rotate API
            Key](/reference/rotate-api-key).
    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.

````