---
openapi: 3.0.3
info:
  title: Braze REST API – Rename external ID
  description: |
    ## Prerequisites

    To use this endpoint, you'll need an [API key]({{site.baseurl}}/api/basics) with the `users.external_ids.rename` permission.

    ## Rate limit

    We apply a rate limit of 1,000 requests per minute to this endpoint, as documented in [API rate limits]({{site.baseurl}}/api/api_limits/).
  version: 1.0.0
  contact:
    name: Braze Support
    url: https://www.braze.com/docs/braze_support/
  license:
    name: Braze Documentation
    url: https://www.braze.com/docs/api/home/
servers:
  - url: https://rest.iad-01.braze.com
    description: US-01
  - url: https://rest.iad-02.braze.com
    description: US-02
  - url: https://rest.iad-03.braze.com
    description: US-03
  - url: https://rest.iad-04.braze.com
    description: US-04
  - url: https://rest.iad-05.braze.com
    description: US-05
  - url: https://rest.iad-06.braze.com
    description: US-06
  - url: https://rest.iad-07.braze.com
    description: US-07
  - url: https://rest.iad-08.braze.com
    description: US-08
  - url: https://rest.us-10.braze.com
    description: US-10
  - url: https://rest.fra-01.braze.eu
    description: EU-01
  - url: https://rest.fra-02.braze.eu
    description: EU-02
  - url: https://rest.au-01.braze.com
    description: AU-01
  - url: https://rest.id-01.braze.com
    description: ID-01
  - url: https://rest.jp-01.braze.com
    description: JP-01
  - url: https://rest.kr-01.braze.com
    description: KR-01
security:
  - BearerAuth: []
paths:
  /users/external_ids/rename:
    post:
      summary: Rename external ID
      description: |
        ## How renaming works

        When you call this endpoint, it assigns a new primary `external_id` to a user profile while simultaneously converting the previous primary `external_id` into a deprecated external ID. After a successful rename, the user profile holds exactly one primary `external_id` (the new value) and one deprecated external ID (the old value).

        Subsequent rename calls on the same profile are permitted: each rename creates an additional deprecated external ID, so a profile may accumulate one primary `external_id` and multiple deprecated external IDs over time. However, the `new_external_id` value must not already exist on any Braze profile, either as a primary or a deprecated external ID.

        The endpoint does not log data points and does not affect MAU counts. All historical user data—events, purchases, attributes, campaign engagement—remains attached to the same profile.

        ## Bulk migrations

        For migrations involving large user populations, batch users into groups of up to 50 and send each batch as a separate API call. The endpoint is subject to a rate limit of 1,000 requests per minute. At maximum batch size (50 objects per request), this allows up to 50,000 user renames per minute.

        Each rename object in the batch is processed independently. A failure on one object does not block the others in the same request. The response body distinguishes successful renames (listed in the `external_ids` array) from failed ones (listed in the `rename_errors` array with an index reference back to the position of the failing object in the request array).

        When running bulk migrations:

        1. Iterate through the full user population in batches of up to 50 pairs.
        2. On each response, inspect both `external_ids` (success) and `rename_errors` (failure) to identify any users that need to be retried.
        3. Collect failed objects and schedule retry batches separately. Common failure causes include the `new_external_id` already being in use, or the `current_external_id` being a deprecated ID rather than a primary ID.
        4. Log successes and failures against your own records so the migration state is tracked outside Braze.

        ## Verifying the current external ID

        During a migration, you may need to confirm which external ID is the active primary identifier on a given profile—for example, when determining whether a specific user has already been migrated, or when troubleshooting a failed rename. Use the [`/users/export/ids` endpoint]({{site.baseurl}}/api/endpoints/export/user_data/post_users_identifier/) for this purpose.

        The export endpoint resolves both primary and deprecated external IDs to the same underlying profile and always returns the current primary `external_id` in the response. This means you can query any known identifier for a user—old or new—and the response will contain the canonical primary ID. This is a reliable way to determine migration state.

        To check only the external ID (rather than pulling the full profile), pass `fields_to_export` with only the `external_id` field.

        ## Recommended migration workflow

        For most migration use cases, the recommended sequence is:

        1. **Test in staging** — Run the full rename-and-verify flow against a development or staging workspace before touching production.
        2. **Rename in batches** — Use the `/users/external_ids/rename` endpoint in batches of up to 50, handling `rename_errors` on each response and queuing failed pairs for retry.
        3. **Verify** — After each batch (or at the end of migration), spot-check profiles using `/users/export/ids` to confirm the expected primary `external_id` is set.
        4. **Maintain the deprecation window** — Keep deprecated external IDs active for as long as any system (including legacy app versions in the field) may still reference the old IDs. Don't rush this step.
        5. **Remove deprecated IDs** — Once all systems are confirmed to be using the new IDs, use [`/users/external_ids/remove`]({{site.baseurl}}/api/endpoints/user_data/external_id_migration/post_external_ids_remove) in batches of up to 50 to clean up.

        If you're also migrating your SDK integration (for example, changing the value passed to `changeUser`), coordinate the API-side rename with the app release schedule so that the new external ID is in use on both the server and the client before deprecated IDs are removed.

        ## Frequently asked questions

        ### Does this impact MAU?

        No, because the number of users stays the same, they have a new `external_id`.

        ### Does user behavior change historically?

        No, because the user is still the same, and all their historical behavior is still connected to them.

        ### Can it be run on development or staging workspaces?

        Yes. In fact, we highly recommend running a test migration on a staging or development workspace, and ensuring everything has gone smoothly before executing on production data.

        ### Does this log data points?

        This feature does not log data points.

        ### What is the recommended deprecation period?

        We have no hard limit on how long you can keep deprecated external IDs around, but we highly recommend removing them after there is no longer a need to reference users by the deprecated ID.

        ### How many deprecated external IDs can a profile have?

        A user profile can hold one primary `external_id` and any number of deprecated external IDs accumulated through successive rename operations. There is no documented cap on the number of deprecated IDs a single profile can hold, but Braze recommends removing them as soon as they are no longer needed.
      operationId: renameExternalIds
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RenameExternalIdsRequest'
            examples:
              rename:
                summary: Rename an external ID
                value:
                  external_id_renames:
                    - current_external_id: existing_external_id
                      new_external_id: new_external_id
      responses:
        "201":
          description: |
            The request succeeded and the external IDs were queued for renaming. No action needed.

            The response will confirm all successful renames, as well as unsuccessful renames with any associated errors. Error messages in the `rename_errors` field will reference the index of the object in the array of the original request.

            The `message` field will return `success` for any valid request. More specific errors are captured in the `rename_errors` array. The `message` field returns an error in the case of:

            - Invalid API key
            - Empty `external_id_renames` array
            - `external_id_renames` array with more than 50 objects
            - Rate limit hit (more than 1,000 requests per minute)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RenameExternalIdsResponse'
              examples:
                success:
                  summary: All external IDs renamed
                  value:
                    message: success
                    external_ids:
                      - current_external_id: existing_external_id
                        new_external_id: new_external_id
                    rename_errors: []
                partial_success:
                  summary: Some renames failed
                  value:
                    message: success
                    external_ids:
                      - current_external_id: existing_external_id
                        new_external_id: new_external_id
                    rename_errors:
                      - [1, new_external_id is already in use]
                      - [2, Cannot rename a deprecated external ID]
        "400":
          description: |
            Bad request. To resolve it:

            - **The `external_id_renames` value isn't an array:** Pass `external_id_renames` as an array of objects.
            - **The `external_id_renames` array is empty:** Include at least one rename object.
            - **More than 50 renames were provided:** Send 50 or fewer renames per request.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                external_id_renames_not_array:
                  summary: The external_id_renames value isn't an array
                  value:
                    message: "'external_id_renames' must be an array."
                external_id_renames_empty:
                  summary: The external_id_renames array is empty
                  value:
                    message: "'external_id_renames' must include at least one element."
                too_many_renames:
                  summary: More than 50 renames
                  value:
                    message: Max input length exceeded for 'external_id_renames'.
        "401":
          description: |
            Unauthorized. The REST API key is missing, malformed, or sent to the wrong REST endpoint. Send the key as `Authorization: Bearer YOUR_REST_API_KEY` to the correct [REST endpoint]({{site.baseurl}}/api/basics/#endpoints). For more causes, see [Errors and responses]({{site.baseurl}}/api/errors/#fatal-errors).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                invalid_api_key:
                  summary: Invalid API key
                  value:
                    message: 'Invalid API key: YOUR_REST_API_KEY'
        "403":
          description: Access denied. The REST API key doesn't have the required permission. Use a REST API key that has the `users.external_ids.rename` permission.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                access_denied:
                  summary: Missing permission
                  value:
                    message: Access Denied
        "429":
          description: |
            Rate limited. You exceeded the rate limit for this endpoint. Slow your request rate and retry with exponential backoff. See [API rate limits]({{site.baseurl}}/api/api_limits/).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                over_rate_limit:
                  summary: Over rate limit
                  value:
                    message: You have exceeded your limit of 1000 requests per minute. Please contact your account executive to increase your limit. If you do not have their info, you may contact Braze directly at https://www.braze.com/contact/.
        5XX:
          description: |
            Internal server error. An unexpected error occurred on the Braze server. Retry with exponential backoff. If the error persists, contact [Support]({{site.baseurl}}/braze_support/).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: REST API key
      description: |
        REST API keys are created in the Braze dashboard at **Settings → APIs and
        Identifiers → API Keys**. The key must include the `users.external_ids.rename` permission.
        Pass the key as `Authorization: Bearer YOUR_REST_API_KEY`.
  schemas:
    ExternalIdRename:
      title: External ID rename object
      type: object
      description: The `current_external_id` and `new_external_id` cannot be the same.
      required: [current_external_id, new_external_id]
      properties:
        current_external_id:
          type: string
          description: The `current_external_id` must be the user's primary ID, and cannot be a deprecated ID. If the value passed as `current_external_id` is itself a deprecated ID on the profile, the call will fail. Before retrying a failed rename, use the [`/users/export/ids` endpoint]({{site.baseurl}}/api/endpoints/export/user_data/post_users_identifier/) to confirm which ID is currently primary.
          example: existing_external_id
        new_external_id:
          type: string
          description: The `new_external_id` must not already be in use as either a primary ID or a deprecated ID. Attempting to rename to an ID that is already stored as a deprecated ID returns a "new_external_id is already in use" error.
          example: new_external_id
    RenameExternalIdsRequest:
      title: Rename external IDs request
      type: object
      required: [external_id_renames]
      properties:
        external_id_renames:
          type: array
          minItems: 1
          maxItems: 50
          items:
            $ref: '#/components/schemas/ExternalIdRename'
          description: Up to 50 rename objects are allowed per request. View request example and the following limitations for the structure of the external identifier rename object.
    RenameError:
      title: Rename error
      type: array
      description: The index of the rename object in the request's `external_id_renames` array, followed by the minor error message for that object.
      minItems: 2
      maxItems: 2
      items:
        oneOf:
          - type: integer
            title: Index
          - type: string
            title: Error message
      example: [1, new_external_id is already in use]
    RenameExternalIdsResponse:
      title: Rename external IDs response
      type: object
      properties:
        message:
          type: string
          description: Status message.
          example: success
        external_ids:
          type: array
          description: Successful rename operations. Each entry is the rename object from the request.
          items:
            $ref: '#/components/schemas/ExternalIdRename'
        rename_errors:
          type: array
          description: Unsuccessful rename operations, as an array of arrays. Each inner array holds the index of the object in the original request array and a minor error message.
          items:
            $ref: '#/components/schemas/RenameError'
    ErrorResponse:
      title: Error
      type: object
      properties:
        message:
          type: string
          description: Human-readable error message.
