Summary and recommendation
Braze exposes two distinct API surfaces that serve different user populations and must not be conflated. The REST API (base URL is region-specific, e.g., https://rest.iad-01.braze.com) manages end-user/customer profiles via endpoints under /users/track, /users/delete, /users/export, and /users/merge.
The SCIM 2.0 API (https://dashboard.braze.com/scim/v2) manages internal dashboard users and requires a Pro or Enterprise plan with SAML SSO configured.
Authentication tokens are separate for each surface - REST API keys are workspace-scoped and generated under Settings > API Keys; the SCIM token is generated once under Settings > Security Settings and cannot be retrieved after initial creation.
Stitchflow connects to Braze through an MCP server with ~100 deep IT/identity integrations, covering both the REST and SCIM surfaces where plan access permits.
API quick reference
| Has user API | Yes |
| Auth method | API Key (Bearer token in Authorization header or api_key body param) |
| Base URL | Official docs |
| SCIM available | Yes |
| SCIM plan required | Pro or Enterprise (SAML SSO must be configured) |
Authentication
Auth method: API Key (Bearer token in Authorization header or api_key body param)
Setup steps
- Log in to the Braze dashboard and navigate to Settings > API Keys.
- Click 'Create New API Key' and assign a name and the required endpoint permissions.
- Copy the generated API key value.
- Pass the key in the Authorization header as 'Bearer {api_key}' on all REST API requests.
- Select the correct regional base URL for your Braze instance (e.g., iad-01, iad-02, eu-01).
Required scopes
| Scope | Description | Required for |
|---|---|---|
| users.track | Create or update user profiles via /users/track | Creating and updating end-user profiles |
| users.delete | Delete user profiles via /users/delete | Deleting end-user profiles |
| users.export.ids | Export user profiles by external_id or braze_id | Reading/exporting individual user profiles |
| users.export.segment | Export all users in a segment | Bulk user export by segment |
| users.merge | Merge two user profiles | Merging duplicate user profiles |
| users.alias.new | Create new user aliases | Alias-based user identification |
User object / data model
| Field | Type | Description | On create | On update | Notes |
|---|---|---|---|---|---|
| external_id | string | Developer-defined unique user identifier | required (or user_alias) | required to target existing user | Immutable once set; used as primary lookup key |
| braze_id | string | Braze-generated internal user identifier | auto-assigned | can be used as alternative to external_id | Read-only; returned in export responses |
| first_name | string | User's first name | optional | optional | |
| last_name | string | User's last name | optional | optional | |
| string | User's email address | optional | optional | Used for email channel targeting | |
| phone | string | User's phone number in E.164 format | optional | optional | Required for SMS channel |
| email_subscribe | string | Email subscription state: opted_in, subscribed, unsubscribed | optional | optional | |
| push_subscribe | string | Push subscription state: opted_in, subscribed, unsubscribed | optional | optional | |
| country | string | ISO 3166-1 alpha-2 country code | optional | optional | |
| language | string | ISO 639-1 two-letter language code | optional | optional | |
| time_zone | string | IANA time zone name (e.g., America/New_York) | optional | optional | |
| dob | string | Date of birth in YYYY-MM-DD format | optional | optional | |
| gender | string | M, F, O, N, P, or U | optional | optional | |
| home_city | string | User's home city | optional | optional | |
| custom_attributes | object | Key-value pairs of custom profile attributes | optional | optional | Supports string, number, boolean, array, date types; max 255 chars per key |
| user_alias | object | Alias object {alias_name, alias_label} for anonymous users | optional (alternative to external_id) | optional | Used when external_id is not yet known |
| image_url | string | URL of user's profile image | optional | optional | |
| push_tokens | array | Array of push token objects per app/platform | optional | optional | Typically set by SDK, not REST API |
Core endpoints
Create or Update User Profile
- Method: POST
- URL:
https://rest.iad-01.braze.com/users/track - Watch out for: Up to 75 attribute objects per call. Passing an external_id that does not exist creates a new profile (upsert behavior). Batching is critical for throughput.
Request example
POST /users/track
{
"attributes": [{
"external_id": "user123",
"first_name": "Jane",
"email": "jane@example.com",
"custom_attributes": {"plan": "gold"}
}]
}
Response example
{
"message": "success",
"attributes_processed": 1,
"errors": []
}
Delete Users
- Method: POST
- URL:
https://rest.iad-01.braze.com/users/delete - Watch out for: Deletion is permanent and irreversible. Up to 50 external_ids per request.
Request example
POST /users/delete
{
"external_ids": ["user123", "user456"]
}
Response example
{
"deleted": 2,
"message": "success"
}
Export Users by ID
- Method: POST
- URL:
https://rest.iad-01.braze.com/users/export/ids - Watch out for: Max 50 external_ids per call. Use fields_to_export to limit payload size.
Request example
POST /users/export/ids
{
"external_ids": ["user123"],
"fields_to_export": ["first_name","email","custom_attributes"]
}
Response example
{
"message": "success",
"users": [{
"external_id": "user123",
"first_name": "Jane",
"email": "jane@example.com"
}]
}
Export Users by Segment
- Method: POST
- URL:
https://rest.iad-01.braze.com/users/export/segment - Watch out for: Asynchronous - results are delivered to callback_endpoint or an S3/Azure bucket. Not suitable for real-time lookups.
Request example
POST /users/export/segment
{
"segment_id": "seg_abc123",
"callback_endpoint": "https://yourserver.com/callback",
"fields_to_export": ["external_id","email"]
}
Response example
{
"message": "success"
}
Merge Users
- Method: POST
- URL:
https://rest.iad-01.braze.com/users/merge - Watch out for: The 'merge' source profile is deleted after merge. Up to 50 merge pairs per request.
Request example
POST /users/merge
{
"merge_updates": [{
"identifier_to_merge": {"external_id": "anon_user"},
"identifier_to_keep": {"external_id": "user123"}
}]
}
Response example
{
"message": "success"
}
Create User Alias
- Method: POST
- URL:
https://rest.iad-01.braze.com/users/alias/new - Watch out for: Up to 50 alias objects per request. Alias label + name combination must be unique.
Request example
POST /users/alias/new
{
"user_aliases": [{
"external_id": "user123",
"alias_name": "alias_abc",
"alias_label": "my_system"
}]
}
Response example
{
"message": "success",
"aliases_processed": 1
}
SCIM: Get Dashboard User
- Method: GET
- URL:
https://dashboard.braze.com/scim/v2/Users/{id} - Watch out for: SCIM manages dashboard (admin) users, not end-user profiles. Requires Pro/Enterprise plan and SAML SSO configured.
Request example
GET /scim/v2/Users/dGVzdEBicmF6ZS5jb20
Authorization: Bearer {scim_token}
Response example
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"id": "dGVzdEBicmF6ZS5jb20",
"userName": "test@braze.com",
"name": {"givenName": "Test", "familyName": "User"}
}
SCIM: Create Dashboard User
- Method: POST
- URL:
https://dashboard.braze.com/scim/v2/Users - Watch out for: SCIM token is separate from REST API keys; generated under Settings > Security Settings. Dashboard URL varies by region.
Request example
POST /scim/v2/Users
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName": "newuser@example.com",
"name": {"givenName": "New", "familyName": "User"}
}
Response example
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"id": "bmV3dXNlckBleGFtcGxlLmNvbQ",
"userName": "newuser@example.com"
}
Rate limits, pagination, and events
- Rate limits: Rate limits vary by endpoint. Most user data endpoints share a per-workspace limit. Limits reset every minute.
- Rate-limit headers: Yes
- Retry-After header: No
- Rate-limit notes: Braze returns X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers. Batching multiple attribute/event objects in a single /users/track call is strongly recommended to stay within limits. Limits are per REST API key workspace.
- Pagination method: cursor
- Default page size: 500
- Max page size: 500
- Pagination pointer: cursor
| Plan | Limit | Concurrent |
|---|---|---|
| Default (all plans) | /users/track: 3,000 requests/3 seconds (batching up to 75 events/purchases/attributes per call); /users/delete: 20,000/minute; /users/export/ids: 2,500/minute | 0 |
- Webhooks available: Yes
- Webhook notes: Braze supports outbound webhooks as a campaign/Canvas channel to send HTTP requests to external systems when user events occur. Braze also supports Currents (a paid data streaming product) for high-volume event export.
- Alternative event strategy: Braze Currents streams raw event data to S3, GCS, Azure, Segment, mParticle, Amplitude, and other partners in near real-time.
- Webhook events: Custom event triggered (via webhook campaign), Purchase event triggered (via webhook campaign), Canvas step reached (via webhook step), Email open/click/bounce (via Currents), Push open/bounce (via Currents), SMS delivery/opt-out (via Currents), Subscription state change (via Currents)
SCIM API status
SCIM available: Yes
SCIM version: 2.0
Plan required: Pro or Enterprise (SAML SSO must be configured)
Endpoint: https://dashboard.braze.com/scim/v2
Supported operations: GET /Users (list dashboard users), GET /Users/{id} (get single dashboard user), POST /Users (create dashboard user), PUT /Users/{id} (replace dashboard user), DELETE /Users/{id} (delete dashboard user)
Limitations:
- Manages Braze dashboard (admin) users only - not end-user/customer profiles
- SAML SSO must be enabled before SCIM provisioning works
- SCIM token is generated once and stored securely; cannot be retrieved after initial creation
- PATCH (partial update) is not documented as supported; use PUT for updates
- Group (team) provisioning via SCIM is not supported
- Dashboard URL is region-specific (e.g., dashboard-01.braze.com for US)
Common scenarios
Three scenarios cover the majority of programmatic use cases. First, syncing CRM profiles to Braze on signup: POST to /users/track with external_id, email, and custom_attributes - this is an upsert, so a missing external_id silently creates a new profile rather than returning an error.
batch up to 75 attribute objects per call to stay within the 3,000 requests/3-second rate limit.
Second, SCIM-based dashboard user provisioning via an IdP such as Okta: configure SAML SSO first, generate the SCIM token, point Okta at the SCIM base URL, and user assignment/unassignment in Okta maps directly to POST and DELETE on /scim/v2/Users - group/team provisioning is not supported.
Third, GDPR right-to-erasure: POST to /users/delete with up to 50 external_ids per request; deletion is immediate and irreversible with no soft-delete or recovery path, so export any compliance-required data before calling the endpoint.
Sync CRM user profile to Braze on signup
- On user signup in your CRM, call POST /users/track with the user's external_id, email, first_name, last_name, and any relevant custom_attributes.
- Batch multiple new users (up to 75) in a single /users/track call to stay within rate limits.
- Store the external_id in your CRM as the canonical Braze identifier for future updates.
- On subsequent profile changes, call /users/track again with the same external_id to update attributes.
Watch out for: /users/track is an upsert - if the external_id already exists the profile is updated; if not, a new profile is created. Ensure external_ids are stable and unique to avoid duplicate profiles.
Provision and deprovision dashboard users via SCIM (Okta)
- Enable SAML SSO in Braze under Settings > Security Settings and configure Okta as the IdP.
- Generate a SCIM API token in Braze under Settings > Security Settings > SCIM Provisioning.
- In Okta, add the Braze app from the Okta Integration Network and enter the SCIM base URL (https://dashboard.braze.com/scim/v2) and token.
- Assign users to the Braze app in Okta; Okta will POST /scim/v2/Users to create dashboard accounts.
- When a user is unassigned in Okta, Okta sends DELETE /scim/v2/Users/{id} to remove dashboard access.
Watch out for: SCIM only manages dashboard (admin) users. End-user/customer profiles are managed via the REST API. Group/team provisioning is not supported via SCIM.
GDPR right-to-erasure: delete an end-user profile
- Receive deletion request and look up the user's external_id in your system.
- Call POST /users/delete with the external_id (up to 50 per request).
- Confirm the response returns {"deleted": 1, "message": "success"}.
- Log the deletion timestamp and external_id for compliance records.
- If the user has multiple profiles (e.g., anonymous alias), identify all braze_ids via /users/export/ids and include them in the delete call.
Watch out for: Deletion is immediate and irreversible. There is no soft-delete or recovery mechanism. Ensure you have exported any data needed for compliance records before deleting.
Why building this yourself is a trap
The most common integration pitfalls fall into three categories. Region mismatch: the REST base URL is cluster-specific (iad-01 through iad-06 for US, eu-01 for EU), and using the wrong cluster returns 401 errors that can be misread as auth failures.
Async export: /users/export/segment is asynchronous and delivers results to a callback URL or cloud storage bucket - it is not suitable for real-time lookups and will block pipelines that expect a synchronous response.
Object limits: /users/track accepts up to 75 objects per call, /users/delete and /users/merge accept up to 50; exceeding these limits returns a 400 error, not a partial success.
Additionally, custom attribute keys are case-sensitive, cannot start with a dollar sign, and are capped at 255 characters - schema mismatches here fail silently on some attribute types.
Automate Braze workflows without one-off scripts
Stitchflow builds and maintains end-to-end IT automation across your SaaS stack, including apps without APIs. Built for exactly how your company works, with human approvals where they matter.