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

    To use this endpoint, you must have an [API key]({{site.baseurl}}/api/basics) with the `users.track.bulk` permission.

    If you're making server-to-server calls behind a firewall, you may need to allowlist your Braze REST endpoint (for example, `rest.iad-01.braze.com`). For more information, see [API endpoints]({{site.baseurl}}/api/basics#api-definitions).

    ## Rate limit

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

    For most customers, this endpoint has a base speed limit of 50 requests per second.

    Customers on newer contracts may instead have burst (per-second) and steady (per-hour) limits based on contracted monthly active users.

    Each `/users/track/bulk` request has a payload limit of 2 MB and can include up to 1,000 objects total across attributes, events, and purchases, depending on your account's bulk rate-limit policy.

    Each object can update one user, so a single request can update up to your account's request object limit of different users. Additionally, each request can contain a maximum of 100 objects per user profile across attributes, events, and purchases.
  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/bulk:
    post:
      summary: Create and update users (bulk)
      operationId: trackUsersBulk
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TrackBulkRequest'
            examples:
              bulk_update_profiles:
                summary: Bulk update user profiles in one request
                description: Update up to your account's request object limit of user profiles in one request.
                value:
                  attributes:
                    - external_id: user1
                      string_attribute: fruit
                      boolean_attribute_1: true
                      integer_attribute: 25
                      array_attribute:
                        - banana
                        - apple
                    - external_id: user2
                      string_attribute: vegetables
                      boolean_attribute_1: false
                      integer_attribute: 25
                      array_attribute:
                        - broccoli
                        - asparagus
              attributes_and_events:
                summary: Send attributes and events in one request
                description: Include attributes and events in the same request, up to your account's total object limit.
                value:
                  attributes:
                    - external_id: user1
                      string_attribute: fruit
                      boolean_attribute_1: true
                      integer_attribute: 25
                      array_attribute:
                        - banana
                        - apple
                  events:
                    - external_id: user2
                      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
              attributes_batch:
                summary: Bulk attributes update
                value:
                  attributes:
                    - external_id: user1
                      string_attribute: fruit
                    - external_id: user2
                      string_attribute: vegetables
      responses:
        "201":
          description: |
            The request was accepted and queued. Non-fatal, per-object issues are returned in the `errors` array; unaffected data is still processed. No action needed. Review any messages in the `errors` array.

            Successful messages return the following response, shown in the **Successful message** example.

            If your request is successful but has non-fatal errors (for example, one invalid event object in a large batch), you receive the following response, shown in the **Successful message with non-fatal errors** example.

            Non-fatal errors include:

            - **The data point credit key is invalid:** Remove the invalid credit key, or use a valid one.

            If you receive the error "provided external_id is blacklisted and disallowed", your request may include a "dummy user." For more information, see [Spam blocking]({{site.baseurl}}/user_archival#spam-blocking).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TrackBulkResponse'
              examples:
                success:
                  summary: Successful message
                  value:
                    message: success
                    attributes_processed: 2
                success_with_errors:
                  summary: Successful message with non-fatal errors
                  value:
                    message: success
                    attributes_processed: 1
                    events_processed: 1
                    errors:
                      - type: "'time' must be an ISO 8601 timestamp"
                        input_array: events
                        index: 1
                invalid_credit_key:
                  summary: Invalid data point credit key
                  value:
                    message: success
                    attributes_processed: 2
                    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.
            - **The request body is larger than 2 MB:** Split the request so each body is 2 MB or smaller.
            - **The request exceeds the maximum total updates allowed:** Reduce the number of updates per request (up to 10,000, or 1,000 under the newer rate-limit policy).
            - **A single user has more than 100 updates in the request:** Send 100 or fewer updates per user per request.
            - **Legacy purchase ingestion is disabled for this workspace:** Remove the `purchases` array and use eCommerce recommended events instead.

            If your request has a fatal error, you receive the following response: a `message` that describes the fatal error, and an `errors` array. For status codes and associated error messages that Braze returns when your request has a fatal error, see [Fatal errors & responses]({{site.baseurl}}/api/errors#fatal-errors).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              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"
                body_too_large:
                  summary: Request body larger than 2 MB
                  value:
                    message: Maximum request body size exceeded
                too_many_updates:
                  summary: Too many total updates
                  value:
                    message: Maximum total updates exceeded
                too_many_updates_per_user:
                  summary: More than 100 updates for one user
                  value:
                    message: Maximum updates per user exceeded
                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/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.track.bulk` permission.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                access_denied:
                  summary: Missing permission
                  value:
                    message: Access Denied
        "404":
          description: Not found. The endpoint isn't enabled for this workspace. Contact your Braze account manager to enable this endpoint.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                feature_not_enabled:
                  summary: Endpoint not enabled
                  value:
                    message: Feature not enabled
        "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 50 requests per second. 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.track.bulk` 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
    TrackAttributesObject:
      title: User attributes object
      type: object
      description: See [user attributes object]({{site.baseurl}}/api/objects_filters/user_attributes_object).
      additionalProperties: true
      properties:
        external_id:
          type: string
        user_alias:
          $ref: '#/components/schemas/UserAlias'
        braze_id:
          type: string
        email:
          type: string
        phone:
          type: string
    TrackEventObject:
      title: Event object
      type: object
      description: See [events object]({{site.baseurl}}/api/objects_filters/event_object).
      additionalProperties: true
      required: [name, time]
      properties:
        external_id:
          type: string
        user_alias:
          $ref: '#/components/schemas/UserAlias'
        braze_id:
          type: string
        email:
          type: string
        phone:
          type: string
        app_id:
          type: string
        name:
          type: string
        time:
          type: string
        properties:
          type: object
          additionalProperties: true
    TrackPurchaseObject:
      title: Purchase object
      type: object
      description: See [purchases object]({{site.baseurl}}/api/objects_filters/purchase_object).
      additionalProperties: true
      required: [product_id, currency, price, time]
      properties:
        external_id:
          type: string
        user_alias:
          $ref: '#/components/schemas/UserAlias'
        braze_id:
          type: string
        email:
          type: string
        phone:
          type: string
        app_id:
          type: string
        product_id:
          type: string
        currency:
          type: string
        price:
          type: number
        quantity:
          type: integer
          default: 1
        time:
          type: string
        properties:
          type: object
          additionalProperties: true
    TrackBulkRequest:
      title: Create and update users (bulk) request
      type: object
      description: For each request object, you must include one of `external_id`, `user_alias`, `braze_id`, `email`, or `phone`.
      properties:
        attributes:
          type: array
          description: See [user attributes object]({{site.baseurl}}/api/objects_filters/user_attributes_object)
          items:
            $ref: '#/components/schemas/TrackAttributesObject'
        events:
          type: array
          description: See [events object]({{site.baseurl}}/api/objects_filters/event_object)
          items:
            $ref: '#/components/schemas/TrackEventObject'
        purchases:
          type: array
          description: See [purchases object]({{site.baseurl}}/api/objects_filters/purchase_object)
          items:
            $ref: '#/components/schemas/TrackPurchaseObject'
    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`.
    TrackBulkResponse:
      title: Create and update users (bulk) response
      type: object
      properties:
        message:
          type: string
          example: success
        attributes_processed:
          type: integer
          description: If attributes are included in the request, this returns an integer of the number of external IDs with attributes that Braze queued for processing.
        events_processed:
          type: integer
          description: If events are included in the request, this returns an integer of the number of events that Braze queued for processing.
        purchases_processed:
          type: integer
          description: If purchases are included in the request, this returns an integer of the number of purchases that Braze queued for processing.
        errors:
          type: array
          description: Non-fatal errors encountered while processing the request.
          items:
            $ref: '#/components/schemas/NonFatalError'
    ErrorResponse:
      title: Error
      type: object
      properties:
        message:
          type: string
          description: The error message describing why the request failed.
        errors:
          type: array
          description: Non-fatal errors encountered while processing the request.
          items:
            $ref: '#/components/schemas/NonFatalError'
