---
openapi: 3.0.3
info:
  title: Braze REST API – Create and update users (synchronous)
  description: |
    ## Prerequisites

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

    Customers using the API for server-to-server calls may need to allowlist `rest.iad-01.braze.com` if they're behind a firewall.

    ## Rate limit

    **Note:**
    Each custom attribute sent in a request to `/users/track/sync` consumes a data point. For more information, see [Data points]({{site.baseurl}}/user_guide/data/infrastructure/data_points).

    We apply a base speed limit of 500 requests per minute to this endpoint for all customers. Each `/users/track/sync` request can contain up to one event object, one attribute object, or one purchase object. Each object (event, attribute, and purchase arrays) can update one user each.
  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/track/sync:
    post:
      summary: Create and update users (synchronous)
      operationId: trackUsersSync
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TrackSyncRequest'
            examples:
              attribute_by_external_id:
                summary: Update a custom attribute by external ID
                value:
                  attributes:
                    - external_id: xyz123
                      string_attribute: fruit
                      boolean_attribute_1: true
                      integer_attribute: 25
                      array_attribute:
                        - banana
                        - apple
              event_by_email:
                summary: Update a custom event by email
                value:
                  events:
                    - email: test@example.com
                      app_id: your_app_identifier
                      name: rented_movie
                      time: "2022-12-06T19:20:45+01:00"
                      properties:
                        release:
                          studio: FilmStudio
                          year: "2022"
                        cast:
                          - name: Actor1
                          - name: Actor2
              purchase_by_user_alias:
                summary: Update a purchase event by user alias
                value:
                  purchases:
                    - user_alias:
                        alias_name: device123
                        alias_label: my_device_identifier
                      app_id: 11ae5b4b-2445-4440-a04f-bf537764c9ad
                      product_id: Completed Order
                      currency: USD
                      price: 219.98
                      time: "2022-12-06T19:20:45+01:00"
                      properties:
                        products:
                          - name: Monitor
                            category: Gaming
                            product_amount: 19.99
                          - name: Gaming Keyboard
                            category: "Gaming "
                            product_amount: 199.99
              one_attribute:
                summary: Update one attribute object
                value:
                  attributes:
                    - external_id: xyz123
                      string_attribute: fruit
      responses:
        "201":
          description: |
            Braze processed the request. The response includes the updated user profile fields. No action needed.

            When using this endpoint's request parameters, you should receive one of the following responses: a successful message, a message with fatal errors, or a message with processing errors.

            Successful messages return the following response, which includes information about the user profile data that Braze updated.

            Non-fatal errors include:

            - **The data point credit key is invalid:** Remove the invalid credit key, or use a valid one.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TrackSyncResponse'
              examples:
                attribute_by_external_id:
                  summary: Update a custom attribute by external ID
                  value:
                    users:
                      - external_id: xyz123
                        custom_attributes:
                          string_attribute: fruit
                          boolean_attribute_1: true
                          integer_attribute: 25
                          array_attribute:
                            - banana
                            - apple
                    message: success
                event_by_email:
                  summary: Update a custom event by email
                  value:
                    users:
                      - email: test@example.com
                        custom_events:
                          - name: rented_movie
                            first: "2022-01-001T00:00:00.000Z"
                            last: "2022-12-06T18:20:45.000Z"
                            count: 10
                    message: success
                purchase_by_user_alias:
                  summary: Update a purchase event by user alias
                  value:
                    users:
                      - user_alias:
                          alias_name: device123
                          alias_label: my_device_identifier
                        purchase_events:
                          - product_id: Completed Order
                            first: "2013-07-16T19:20:30+01:00"
                            last: "2022-12-06T18:20:45.000Z"
                            count: 3
                    message: success
                invalid_credit_key:
                  summary: Invalid data point credit key
                  value:
                    users:
                      - external_id: xyz123
                        custom_attributes:
                          string_attribute: fruit
                    message: success
                    errors:
                      - type: Invalid data point credit key
        "400":
          description: |
            Bad request. To resolve it:

            - **No valid `attributes`, `events`, or `purchases` were provided:** Include at least one valid attribute, event, or purchase object.
            - **The request body, or an entry within an array, isn't a JSON object:** Send a JSON object, and make each array entry an object.
            - **The `attributes` value isn't an array:** Pass `attributes` as an array of objects.
            - **The `events` value isn't an array:** Pass `events` as an array of objects.
            - **The `purchases` value isn't an array:** Pass `purchases` as an array of objects.
            - **More than one attribute, event, or purchase was included:** Include exactly one attribute, custom event, or purchase per request.
            - **Legacy purchase ingestion is disabled for this workspace:** Remove the `purchases` array and use eCommerce recommended events instead.

            If your message has a fatal error, you'll receive the following response: a `message` that describes the fatal error, and an `errors` array.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationErrorResponse'
              examples:
                no_valid_data:
                  summary: No valid attributes, events, or purchases
                  value:
                    message: Valid data must be provided in the 'attributes', 'events', or 'purchases' fields.
                not_json_object:
                  summary: Not a JSON object
                  value:
                    message: JSON hash not provided
                attributes_not_array:
                  summary: The attributes value isn't an array
                  value:
                    message: "'attributes' must be an array"
                events_not_array:
                  summary: The events value isn't an array
                  value:
                    message: "'events' must be an array"
                purchases_not_array:
                  summary: The purchases value isn't an array
                  value:
                    message: "'purchases' must be an array"
                more_than_one_object:
                  summary: More than one attribute, event, or purchase
                  value:
                    message: Only one attribute, custom event, or purchase may be included in this request.
                legacy_purchases_disabled:
                  summary: Legacy purchase ingestion is disabled
                  value:
                    message: Legacy purchase ingestion is disabled. The 'purchases' array must not be provided. Use eCommerce recommended events instead.
        "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/ValidationErrorResponse'
              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.track.sync` permission.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationErrorResponse'
              examples:
                access_denied:
                  summary: Missing permission
                  value:
                    message: Access Denied
        "404":
          description: |
            Not found. To resolve it:

            - **The endpoint isn't enabled for this workspace:** Contact your Braze account manager to enable this endpoint.
            - **Braze couldn't find a user profile for the identifier in the request:** Check the identifier in the request. Braze returns this message in the `error` key.

            If Braze accepts the request but can't finish processing it, you'll receive a response with an `error` key instead of `message`.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ValidationErrorResponse'
                  - $ref: '#/components/schemas/ErrorResponse'
              examples:
                feature_not_enabled:
                  summary: Endpoint not enabled
                  value:
                    message: Feature not enabled
                user_not_found:
                  summary: User not found
                  value:
                    error: The provided user could not be found.
        "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/ValidationErrorResponse'
              examples:
                over_rate_limit:
                  summary: Over rate limit
                  value:
                    message: You have exceeded your limit of 500 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/.
        "500":
          description: |
            Internal server error. Braze couldn't finish processing the request, or the request timed out. Retry with exponential backoff. If the error persists, contact [Support]({{site.baseurl}}/braze_support/). Braze returns this message in the `error` key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                internal_error:
                  summary: Processing failed or timed out
                  value:
                    error: An internal error occurred.
        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/ValidationErrorResponse'
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.track.sync` permission.
        Pass the key as `Authorization: Bearer YOUR_REST_API_KEY`.
  schemas:
    UserAlias:
      title: User alias
      type: object
      required: [alias_name, alias_label]
      properties:
        alias_name:
          type: string
        alias_label:
          type: string
    TrackSyncObject:
      title: Track object
      type: object
      additionalProperties: true
      properties:
        external_id:
          type: string
        user_alias:
          $ref: '#/components/schemas/UserAlias'
        braze_id:
          type: string
        email:
          type: string
        phone:
          type: string
    TrackSyncRequest:
      title: Create and update users (synchronous) request
      type: object
      description: Each object in `attributes`, `events`, and `purchases` must include one of `external_id`, `user_alias`, `braze_id`, `email`, or `phone`.
      properties:
        attributes:
          type: array
          maxItems: 1
          description: An array with one attributes object. See [user attributes object]({{site.baseurl}}/api/objects_filters/user_attributes_object)
          items:
            $ref: '#/components/schemas/TrackSyncObject'
        events:
          type: array
          maxItems: 1
          description: An array with one event object. See [events object]({{site.baseurl}}/api/objects_filters/event_object)
          items:
            $ref: '#/components/schemas/TrackSyncObject'
        purchases:
          type: array
          maxItems: 1
          description: An array with one purchase object. See [purchases object]({{site.baseurl}}/api/objects_filters/purchase_object)
          items:
            $ref: '#/components/schemas/TrackSyncObject'
    SyncUserResult:
      title: Updated user profile
      type: object
      additionalProperties: true
      properties:
        custom_attributes:
          type: object
          additionalProperties: true
          description: The custom attributes as a result of the request. Braze lists only custom attributes from the request.
        custom_events:
          type: array
          description: The custom events as a result of the request. Braze lists only custom events from the request.
          items:
            type: object
            additionalProperties: true
        purchase_events:
          type: array
          description: The purchase events as a result of the request. Braze lists only purchase events from the request.
          items:
            type: object
            additionalProperties: true
    TrackSyncResponse:
      title: Create and update users (synchronous) response
      type: object
      properties:
        users:
          type: array
          description: |
            The user profile updated by the request, identified by the identifier you sent.

            If Braze can't find a user profile for the identifier in the request, such as when `_update_existing_only` is `true` and no matching profile exists, the endpoint returns `404 Not Found` instead of an empty `users` array.
          items:
            $ref: '#/components/schemas/SyncUserResult'
        message:
          type: string
          example: success
        errors:
          type: array
          description: Non-fatal errors encountered while processing the request.
          items:
            $ref: '#/components/schemas/NonFatalError'
    NonFatalError:
      title: Non-fatal error
      type: object
      required: [type]
      properties:
        type:
          type: string
          description: Description of the validation issue.
        input_array:
          type: string
          enum: [attributes, events, purchases]
          description: Which top-level array the offending object came from.
        index:
          type: integer
          description: Zero-based index of the offending object within `input_array`.
    ValidationErrorResponse:
      title: Error
      type: object
      required: [message]
      description: |
        Returned when Braze rejects the request before processing it, such as
        a missing permission, an invalid body, or a rate limit.
      properties:
        message:
          type: string
          description: The error message describing why the request failed.
        errors:
          type: array
          description: Non-fatal errors encountered while validating the request.
          items:
            $ref: '#/components/schemas/NonFatalError'
    ErrorResponse:
      title: Processing error
      type: object
      required: [error]
      description: |
        Returned when Braze accepts the request but can't finish processing it.
        Unlike validation errors, this response reports the failure under an
        `error` key rather than `message`.
      properties:
        error:
          type: string
          description: The reason the request failed.
