# Mass update profile

Profiles centralize data and events from multiple sources (Apps, Websites, APIs) in a single place based on the Custom ID.

Use `/profiles/mass-update` for large-scale periodic imports. Learn more about selecting the right endpoint here: [Profile updates: choosing the right API endpoint](https://doc.batch.com/developer/api/cep/profiles/..#profile-updates-choosing-the-right-api-endpoint).

## API Description

## Mass Update

> Update one or multiple profile's data and track events

```json
{"openapi":"3.1.0","info":{"title":"Batch - REST API","version":"2.9"},"tags":[{"name":"Profiles"}],"servers":[{"url":"https://api.batch.com/{version}","description":"production","variables":{"version":{"default":"2.11","description":"Version of the API"}}}],"security":[{"rest_key":[]}],"components":{"securitySchemes":{"rest_key":{"type":"http","scheme":"bearer","description":"## API Key Authentication\n\nAuthentication is required in order to interact with Batch's APIs.\n\nBatch implements authentication using API Keys, that we call the \"REST API Key\".\nYou can find it on your dashboard.\n\nPlease make sure that you keep this key secret. You should never use it in client apps to call APIs from there as it would\neasily be extractable.\n\n### How to authenticate\n\nIn order to authenticate your requests, add your REST API Key in the `Authorization` header and prefix it by `Bearer`. Example: `Authorization: Bearer bcd38d9rfb38ra28`.\n"}},"parameters":{"HeaderProjectKey":{"in":"header","name":"X-Batch-Project","description":"The unique project key, identifying a project on the Batch platform","schema":{"type":"string"},"required":true}},"schemas":{"BulkMassUpdateProfile":{"description":"Edit multiple profiles at once. You can specify at most 10 000 operations or the API call will be rejected.","type":"array","items":{"$ref":"#/components/schemas/EditProfile"}},"EditProfile":{"type":"object","required":["identifiers"],"properties":{"identifiers":{"$ref":"#/components/schemas/ProfileIdentifiers"},"attributes":{"$ref":"#/components/schemas/EditProfileAttributes"},"events":{"description":"Events to track on the profile. This array cannot weigh more than 150kB or have more than 15 elements and individual events cannot weigh more than 25kB. If one of these limits are exceeded, the complete Profile API call will be rejected.","type":"array","maxItems":15,"items":{"$ref":"#/components/schemas/TrackProfileEvent"}}}},"ProfileIdentifiers":{"description":"Specifies which profile to target. Exactly one of custom_id or installation must be provided.\n","oneOf":[{"$ref":"#/components/schemas/CustomID"},{"$ref":"#/components/schemas/Installation"}]},"CustomID":{"type":"object","required":["custom_id"],"properties":{"custom_id":{"description":"Custom user ID of the profile to perform the operation on.","type":"string","maxLength":512}}},"Installation":{"type":"object","required":["installation"],"properties":{"installation":{"$ref":"#/components/schemas/ProfileInstallationIdentifier"}}},"ProfileInstallationIdentifier":{"description":"Batch installation identifier.","type":"object","required":["apikey","installation_id"],"properties":{"apikey":{"description":"API key of the installation.","type":"string"},"installation_id":{"description":"Installation identifier generated by the SDK.","type":"string"}}},"EditProfileAttributes":{"description":"Attributes to write on the profile. Keys are the attributes names. You can set up to 50 attributes on a profile per operation: requests exceeding this limit will be ignored. Some keys are documented as they're reserved, but extra data is supported: See [the attributes documentation](https://doc.batch.com/developer/api/cep/profiles/update#the-attributes-object). This object cannot weigh more than 25kB or the entire Profile API request will be rejected.\n","type":"object","properties":{"$email_address":{"description":"Email address to write on the profile. Null to erase, omit to leave the email unmodified. Addresses must be valid, not longer than 256 characters.","type":["string","null"],"maxLength":256,"pattern":"^[^\\r\\n\\t@]+@[A-z0-9\\-\\.]+\\.[A-z0-9]+$"},"$email_marketing":{"description":"Set whether the profile should receive marketing emails or not. Set to null to reset, omit to leave unmodified.","type":["string","null"],"enum":["subscribed","unsubscribed"]},"$phone_number":{"description":"Phone number to write on the profile. Null to erase, omit to leave the phone number unmodified. The number must conform to the [E.164 international standard](https://en.wikipedia.org/wiki/E.164).","type":["string","null"]},"$sms_marketing":{"description":"Set whether the profile should receive marketing SMS or not. Set to null to reset, omit to leave unmodified.","type":["string","null"],"enum":["subscribed","unsubscribed"]},"$email_open_tracking_consent":{"description":"Set whether the profile has given consent to email open tracking. Set to null to reset, omit to leave unmodified.\n","type":["string","null"],"enum":["granted","denied"]},"$timezone":{"description":"Timezone to set on the profile. Set to null to erase, omit to leave unmodified. Value must be an IANA TZ Identifier. Example: `Europe/Paris`. You can find an non exhaustive list of available TZ identifiers [here](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones).\n","type":["string","null"]},"$language":{"description":"Custom language to set on the profile. Set to null to erase, omit to leave unmodified. Language codes must conform to a subset of BCP 47 language tags. See [our documentation](https://doc.batch.com/api/campaigns/advanced#language-and-country-codes) for a list of supported languages.\n","type":["string","null"]},"$region":{"description":"Custom country code to set on the profile. Set to null to erase, omit to leave unmodified. Country codes must conform to the ISO 3166-1 alpha-2 standard. See [our documentation](https://doc.batch.com/api/campaigns/advanced#language-and-country-codes) for a list of supported languages.\n","type":["string","null"]},"$topic_preferences":{"description":"Subscription topics associated with the profile. Set to an array of strings to replace all topics, `null` to erase all topics, or use `$add`/`$remove` for partial updates. Each topic must be lowercase and match the pattern `[a-z0-9_-]`, with a maximum length of 300 characters. A maximum of 25 topics can be sent per request. A profile can have at most 1500 topics.\n","oneOf":[{"type":"array","description":"Replace all topics with this list.","items":{"type":"string","pattern":"^[a-z0-9_-]{1,300}$"},"maxItems":25},{"type":"null","description":"Erase all topics."},{"type":"object","description":"Partial update — add or remove topics without replacing the full list.","properties":{"$add":{"type":"array","description":"Topics to add to the profile. Elements already present will be moved to the end.","items":{"type":"string","pattern":"^[a-z0-9_-]{1,300}$"},"maxItems":25},"$remove":{"type":"array","description":"Topics to remove from the profile.","items":{"type":"string","pattern":"^[a-z0-9_-]{1,300}$"},"maxItems":25}},"additionalProperties":false}]}},"additionalProperties":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"object"},{"type":"boolean"},{"type":"array","items":{"type":"string"}}]}},"TrackProfileEvent":{"type":"object","required":["name"],"properties":{"name":{"description":"Event name. Cannot be empty, must not be longer than 30 chars and not contain any special character ([a-z0-9_]).","type":"string","pattern":"[a-z0-9_]","maxLength":30},"time":{"description":"UTC date in a RFC 3339 format. The time date and time an event occurred. You can track events that happened in the last 24 hours, and no events in the future. If this parameter is not included in your request, Batch will use the time the event arrives at the server.\n","type":"string"},"attributes":{"$ref":"#/components/schemas/TrackEventAttributes"}}},"TrackEventAttributes":{"description":"Event attributes. Keys are the attribute names. Some keys are documented as they're reserved, but extra data is supported. See [the event attributes documentation](https://doc.batch.com/developer/api/cep/profiles/update#the-events-object) for more info.","type":"object","properties":{"$label":{"type":"string","description":"Event label. Must be a string, will automatically be bridged as label for application event compatiblity.","maxLength":200},"$tags":{"type":"array","items":{"type":"string"},"description":"Event tags. Must be an array of string, will automatically be bridged as tags for application event compatiblity. Tags must not be longer than 64 characters.","maxItems":10}},"additionalProperties":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"object"},{"type":"boolean"},{"type":"array","items":{}}]}},"SuccessResponse":{"description":"Success response. The API call was entirely valid and will be processed as requested.","type":"object","required":["code"],"properties":{"code":{"description":"Success status code","type":"string","enum":["SUCCESS","SUCCESS_WITH_PARTIAL_ERRORS"]},"errors":{"description":"Array of errors that occurred while validating the request. Only present if code is `SUCCESS_WITH_PARTIAL_ERRORS`.","type":"array","items":{"$ref":"#/components/schemas/PartialSuccessResponseErrors"}}}},"PartialSuccessResponseErrors":{"description":"A validation error.","type":"object","required":["bulk_index","category","reason"],"properties":{"category":{"description":"What part of the operation the error applies to. For example, `attribute` means that the error came from one of the profile attributes. Depending on the error category, other keys might be available to help you pinpoint where the error occurred.","type":"string","enum":["attribute","event","event_name","event_attribute","identifier","attribute_limit"]},"bulk_index":{"description":"Index of what bulk operation (requests' top level array) the error occurred in.","type":"number"},"reason":{"description":"Human readable reason explaining what caused the error.","type":"string"},"attribute":{"description":"Only applicable when `category` is `attribute`, `attribute_limit` or `event_attribute`. Name of the profile attribute that caused the error.","type":"string"},"event_index":{"description":"Only applicable when `category` is `event`, `event_name` or `event_attribute`. Index of the event that caused the error.","type":"number"}}},"Error":{"type":"object","required":["error_message","error_code"],"properties":{"error_message":{"description":"A human readable error message","type":"string"},"error_code":{"description":"Error code","type":"string"}}}},"responses":{"202":{"description":"Request accepted, will be processed asynchronously","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/SuccessResponse"}]}}}},"400":{"description":"The request is malformed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The Rest API Key is not valid for this project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Batch's services are under maintenance. Please try again later","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/profiles/mass-update":{"post":{"operationId":"profile_mass_update","tags":["Profiles"],"summary":"Mass Update","description":"Update one or multiple profile's data and track events","parameters":[{"$ref":"#/components/parameters/HeaderProjectKey"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkMassUpdateProfile"}}}},"responses":{"202":{"$ref":"#/components/responses/202"},"400":{"$ref":"#/components/responses/400"},"401":{"$ref":"#/components/responses/401"},"429":{"$ref":"#/components/responses/429"},"500":{"$ref":"#/components/responses/500"},"503":{"$ref":"#/components/responses/503"}}}}}}
```

## Update

> Update one or multiple profile's data and track events

```json
{"openapi":"3.1.0","info":{"title":"Batch - REST API","version":"2.9"},"tags":[{"name":"Profiles"}],"servers":[{"url":"https://api.batch.com/{version}","description":"production","variables":{"version":{"default":"2.11","description":"Version of the API"}}}],"security":[{"rest_key":[]}],"components":{"securitySchemes":{"rest_key":{"type":"http","scheme":"bearer","description":"## API Key Authentication\n\nAuthentication is required in order to interact with Batch's APIs.\n\nBatch implements authentication using API Keys, that we call the \"REST API Key\".\nYou can find it on your dashboard.\n\nPlease make sure that you keep this key secret. You should never use it in client apps to call APIs from there as it would\neasily be extractable.\n\n### How to authenticate\n\nIn order to authenticate your requests, add your REST API Key in the `Authorization` header and prefix it by `Bearer`. Example: `Authorization: Bearer bcd38d9rfb38ra28`.\n"}},"parameters":{"HeaderProjectKey":{"in":"header","name":"X-Batch-Project","description":"The unique project key, identifying a project on the Batch platform","schema":{"type":"string"},"required":true}},"schemas":{"BulkEditProfile":{"description":"Edit multiple profiles at once. You can specify at most 200 operations or the API call will be rejected.","type":"array","items":{"$ref":"#/components/schemas/EditProfile"}},"EditProfile":{"type":"object","required":["identifiers"],"properties":{"identifiers":{"$ref":"#/components/schemas/ProfileIdentifiers"},"attributes":{"$ref":"#/components/schemas/EditProfileAttributes"},"events":{"description":"Events to track on the profile. This array cannot weigh more than 150kB or have more than 15 elements and individual events cannot weigh more than 25kB. If one of these limits are exceeded, the complete Profile API call will be rejected.","type":"array","maxItems":15,"items":{"$ref":"#/components/schemas/TrackProfileEvent"}}}},"ProfileIdentifiers":{"description":"Specifies which profile to target. Exactly one of custom_id or installation must be provided.\n","oneOf":[{"$ref":"#/components/schemas/CustomID"},{"$ref":"#/components/schemas/Installation"}]},"CustomID":{"type":"object","required":["custom_id"],"properties":{"custom_id":{"description":"Custom user ID of the profile to perform the operation on.","type":"string","maxLength":512}}},"Installation":{"type":"object","required":["installation"],"properties":{"installation":{"$ref":"#/components/schemas/ProfileInstallationIdentifier"}}},"ProfileInstallationIdentifier":{"description":"Batch installation identifier.","type":"object","required":["apikey","installation_id"],"properties":{"apikey":{"description":"API key of the installation.","type":"string"},"installation_id":{"description":"Installation identifier generated by the SDK.","type":"string"}}},"EditProfileAttributes":{"description":"Attributes to write on the profile. Keys are the attributes names. You can set up to 50 attributes on a profile per operation: requests exceeding this limit will be ignored. Some keys are documented as they're reserved, but extra data is supported: See [the attributes documentation](https://doc.batch.com/developer/api/cep/profiles/update#the-attributes-object). This object cannot weigh more than 25kB or the entire Profile API request will be rejected.\n","type":"object","properties":{"$email_address":{"description":"Email address to write on the profile. Null to erase, omit to leave the email unmodified. Addresses must be valid, not longer than 256 characters.","type":["string","null"],"maxLength":256,"pattern":"^[^\\r\\n\\t@]+@[A-z0-9\\-\\.]+\\.[A-z0-9]+$"},"$email_marketing":{"description":"Set whether the profile should receive marketing emails or not. Set to null to reset, omit to leave unmodified.","type":["string","null"],"enum":["subscribed","unsubscribed"]},"$phone_number":{"description":"Phone number to write on the profile. Null to erase, omit to leave the phone number unmodified. The number must conform to the [E.164 international standard](https://en.wikipedia.org/wiki/E.164).","type":["string","null"]},"$sms_marketing":{"description":"Set whether the profile should receive marketing SMS or not. Set to null to reset, omit to leave unmodified.","type":["string","null"],"enum":["subscribed","unsubscribed"]},"$email_open_tracking_consent":{"description":"Set whether the profile has given consent to email open tracking. Set to null to reset, omit to leave unmodified.\n","type":["string","null"],"enum":["granted","denied"]},"$timezone":{"description":"Timezone to set on the profile. Set to null to erase, omit to leave unmodified. Value must be an IANA TZ Identifier. Example: `Europe/Paris`. You can find an non exhaustive list of available TZ identifiers [here](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones).\n","type":["string","null"]},"$language":{"description":"Custom language to set on the profile. Set to null to erase, omit to leave unmodified. Language codes must conform to a subset of BCP 47 language tags. See [our documentation](https://doc.batch.com/api/campaigns/advanced#language-and-country-codes) for a list of supported languages.\n","type":["string","null"]},"$region":{"description":"Custom country code to set on the profile. Set to null to erase, omit to leave unmodified. Country codes must conform to the ISO 3166-1 alpha-2 standard. See [our documentation](https://doc.batch.com/api/campaigns/advanced#language-and-country-codes) for a list of supported languages.\n","type":["string","null"]},"$topic_preferences":{"description":"Subscription topics associated with the profile. Set to an array of strings to replace all topics, `null` to erase all topics, or use `$add`/`$remove` for partial updates. Each topic must be lowercase and match the pattern `[a-z0-9_-]`, with a maximum length of 300 characters. A maximum of 25 topics can be sent per request. A profile can have at most 1500 topics.\n","oneOf":[{"type":"array","description":"Replace all topics with this list.","items":{"type":"string","pattern":"^[a-z0-9_-]{1,300}$"},"maxItems":25},{"type":"null","description":"Erase all topics."},{"type":"object","description":"Partial update — add or remove topics without replacing the full list.","properties":{"$add":{"type":"array","description":"Topics to add to the profile. Elements already present will be moved to the end.","items":{"type":"string","pattern":"^[a-z0-9_-]{1,300}$"},"maxItems":25},"$remove":{"type":"array","description":"Topics to remove from the profile.","items":{"type":"string","pattern":"^[a-z0-9_-]{1,300}$"},"maxItems":25}},"additionalProperties":false}]}},"additionalProperties":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"object"},{"type":"boolean"},{"type":"array","items":{"type":"string"}}]}},"TrackProfileEvent":{"type":"object","required":["name"],"properties":{"name":{"description":"Event name. Cannot be empty, must not be longer than 30 chars and not contain any special character ([a-z0-9_]).","type":"string","pattern":"[a-z0-9_]","maxLength":30},"time":{"description":"UTC date in a RFC 3339 format. The time date and time an event occurred. You can track events that happened in the last 24 hours, and no events in the future. If this parameter is not included in your request, Batch will use the time the event arrives at the server.\n","type":"string"},"attributes":{"$ref":"#/components/schemas/TrackEventAttributes"}}},"TrackEventAttributes":{"description":"Event attributes. Keys are the attribute names. Some keys are documented as they're reserved, but extra data is supported. See [the event attributes documentation](https://doc.batch.com/developer/api/cep/profiles/update#the-events-object) for more info.","type":"object","properties":{"$label":{"type":"string","description":"Event label. Must be a string, will automatically be bridged as label for application event compatiblity.","maxLength":200},"$tags":{"type":"array","items":{"type":"string"},"description":"Event tags. Must be an array of string, will automatically be bridged as tags for application event compatiblity. Tags must not be longer than 64 characters.","maxItems":10}},"additionalProperties":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"object"},{"type":"boolean"},{"type":"array","items":{}}]}}}},"paths":{"/profiles/update":{"post":{"operationId":"profile_update","tags":["Profiles"],"summary":"Update","description":"Update one or multiple profile's data and track events","parameters":[{"$ref":"#/components/parameters/HeaderProjectKey"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkEditProfile"}}}}}}}}
```

### Rate Limiting

To ensure fair usage and platform stability, the `/profiles/mass-update` endpoint is subject to rate limiting, following the [Token Bucket](https://en.wikipedia.org/wiki/Token_bucket) algorithm:

* **API rate:** Up to **10000 profile updates per second** are allowed.
* **Burst capacity:** No burst
* If you exceed these limits, the API will respond with an HTTP **429 Too Many Requests** error. When you receive this error, please wait a few seconds before retrying, as further attempts may continue to be rejected until your rate falls back within the allowed limits.

Note that our API rate limit is measured in **updates per second**.

Unlike other API rate limits which are often measured in requests per second or minute, our rate is calculated based on the number of **Custom IDs** processed within your requests.

**What constitutes one "update"?** One update corresponds to the processing associated with a single **Custom ID** included in your request. For example, if a request contains data for 10 different Custom IDs, it will consume 10 updates from your rate limit, regardless of the number of attributes updated or events tracked for each individual Custom ID within that same request.

This unit of measurement has been chosen to effectively manage the processing load, particularly when utilizing bulk operations. Processing multiple Custom IDs in a single bulk request is more efficient, and tracking the rate by the number of IDs processed (updates) ensures fair usage and system stability under heavy load from bulk submission.

## Request structure

### Route

The Profile API exposes a POST endpoint that allows to update a batch of profiles:

`/profiles/mass-update`

You can update one or several profiles via this endpoint, within the limit of 10 000 profiles.

### Headers and authentication

See [Overview → Using Project APIs](https://doc.batch.com/developer/api/cep/..#request-headers-and-authentication).

See [update](https://doc.batch.com/developer/api/cep/profiles/update "mention") for more details & examples on the request payload & error management.

### Failure

If the POST data does not meet the API requirements you will receive an actionable error message. Contact us at <support@batch.com> if you need further support.

* `AUTHENTICATION_INVALID` (HTTP status code: 401, error\_code: 10)
* `ROUTE_NOT_FOUND` (HTTP status code: 404, error\_code: 20)
* `MISSING_PARAMETER` (HTTP status code: 400, error\_code: 30)
* `MALFORMED_PARAMETER` (HTTP status code: 400, error\_code: 31)
* `MALFORMED_JSON_BODY` (HTTP status code: 400, error\_code: 32)
* `SERVER_ERROR` (HTTP status code: 500, error\_code: 1)
* `MAINTENANCE_ERROR` (HTTP status code: 503, error\_code: 2)
* `TOO_MANY_REQUESTS` (HTTP status code: 429, error\_code: 60)

If you get a "too many requests" response, please wait for at least 5 seconds before trying again. Further requests might still return this error.

```json
{
    "error_code": "MALFORMED_PARAMETER",
    "error_message": "Invalid project key project_062ay7ywmgvqccwanj647mmqm1smq2k"
}
```
