This endpoint allows tenants to insert/add new customers or update attributes for existing customers in batch.
| Time | Status | User Agent | |
|---|---|---|---|
Retrieving recent requests… | |||
This endpoint allows tenants to insert/add new customers or update attributes for existing customers in batch.
This API endpoint enables registration of one or more customers in real-time, once a customer is assigned a persistent Customer ID. It is possible to send a single customer or up to 1000 customers in the same API call. By doing this, data about these customers can be accumulated right away. If Optimove does not recognize the provided Customer ID, we will use it to register the new customer.
If a customer is being registered immediately, they will retain the values that were reported upon registration or updated since then. When new, richer information is reported in batch data delivered to Optimove, it will update this customer data and attributes.
How It Works
The endpoint is asynchronous. A call that passes validation is acknowledged immediately with 202 Accepted — it does not mean the customers in the payload have been processed yet.
- You send a batch of customers to
PUT /Customers/UpsertCustomers, optionally including aCallbackUrl. - Optimove validates the envelope — batch size, payload size, required fields. If the envelope is invalid, the request is rejected and nothing in it is processed.
- A valid batch is accepted with
202and queued for processing. The response body carries atraceId. - Each customer in the batch is then processed individually and is either inserted, updated, or rejected.
- When every customer in the batch has finished processing, a single status message is sent to your
CallbackUrl. No intermediate messages are sent for individual stages, including validation.
Without aCallbackUrl, you will not know what happened to your dataThe
202response confirms only that the batch was accepted. It says nothing about whether the customers in it were inserted, updated, skipped or rejected.That outcome is reported only in the status message sent to your
CallbackUrl. If you do not supply one, the status message is never delivered, it is not stored, and there is no API for retrieving it afterwards — you will have no way of knowing whether your data was updated. Supply aCallbackUrlon every call whose result matters to you.
For Optimove's general API rate limit, see the Understanding API Rate Limits reference.
Important: Data Processing & Campaign TimingPlease be aware of a daily processing cycle. It's possible for a customer sent during this processing window to only become visible in Optimove after the next daily cycle completes.
Crucially, if you need to update data for a campaign launching the following day, you must send those updates before the daily process begins.
Notes
- Batch Limit: You can update up to 1000 customers in a single API call. A payload containing more than 1000 customers is rejected in full.
- Size Limit: The maximum allowed payload size per call is 1 MB. A larger payload is rejected in full with
413 Payload Too Large. - Attribute Limit: There is no limit on the number of attributes you can update per customer, provided the total request payload remains under the 1 MB size limit.
CustomerIDis expected to be persistent in representing the same customer in future events and batch data deliveries.- Attributes are identified by their
RealFieldNamevalues. You can retrieve all available customer attribute names and a description of each using the GetCustomerAttributeList function or by accessing the Customer Attributes list in Optimove's interface and exporting the list. - When updating an attribute, the attribute values supplied in this call overwrite any previous values in the database.
- This endpoint is currently not supported in environments where ID mapping is applied.
- You can send a request with only
CustomerIdand no attributes. In that case, the customer will be registered without any additional attributes. To do this, you must sendAttributesas an empty array ([]), notnull, because null attributes are not accepted.
This endpoint is available only to tenants who have the Customer Ingestion feature enabled. If the feature is not enabled for your tenant, the call returns
403with an error message saying so. Contact your Customer Success Manager to have it enabled.
How Long Before a Customer Is Added
New or updated customer data is not reflected in Optimove immediately. How long it takes depends on where you're checking and the request rate coming from your tenant.
Where to check
Once a batch has been processed, you can find the customer on the Customer 360 page or in Customer Explorer.
Test results in Customer 360 after you've received the status message for that batch on your
CallbackUrl. Customer Explorer can take up to an additional 10 minutes to reflect the change, depending on which attributes were updated.
Processing time
Requests to this endpoint are queued and processed sequentially in batches, to support a high volume of concurrent requests. How long an individual batch takes to process depends on your tenant's request rate:
- Low request rate — for example, sending individual requests roughly once a minute rather than streaming continuously: a batch can take up to 4 minutes, from the moment the request is sent until it is fully reflected in the system.
- Medium-to-high request rate — a constant, streamed flow of requests: the system performs best under sustained load. As long as total customers across all requests from your tenant stay under 20,000 per minute, an individual batch is typically fully processed in around 1 minute. Each additional full batch of 2,000 customers above that threshold adds roughly 1 minute of extra wait time, and can affect the processing time of subsequent requests too.
Request Structure
Endpoint
PUT https://api4.optimove.net/Customers/UpsertCustomers (US) · PUT https://api5.optimove.net/Customers/UpsertCustomers (EU)
Authenticate with your API key in the X-API-KEY header.
This payload is a JSON object with two top-level properties: an array called Customers and a string called CallBackUrl. The Customers array contains customer objects, each with a CustomerId field and an Attributes array, where each element is an object composed of RealFieldName and Value string fields. The CallBackUrl field defines the URL endpoint to which the system will send an asynchronous callback after processing the request.
General Fields
| Field | Data Type | Required | Description |
|---|---|---|---|
Customers | Array | Yes | An array of objects containing all customers in this request. Minimum 1, maximum 1000. |
CallbackUrl | String | No | Optional callback URL for post-processing. This will capture the status message. |
Customer Object Fields:
| Field | Data Type | Required | Description |
|---|---|---|---|
CustomerId | String | Yes | Unique identifier for the customer as registered in clients systems. |
Attributes | Array | No | An array of objects that describe each attribute update. Send [] for a customer with no attribute updates — null is not accepted. |
Attribute Object Fields:
| Field | Data Type | Required | Description |
|---|---|---|---|
RealFieldName | String | Yes | Name of the field being updated. |
Value | String | No | Value to be assigned to the field. If NULL value is provided any existing values will be nullified. |
Sample Request
{
"Customers": [
{
"CustomerId": "hello2",
"Attributes": [
{
"RealFieldName": "BALANCE",
"Value": "12"
},
{
"RealFieldName": "COUNTRY",
"Value": "IL"
}
]
},
{
"CustomerId": "Carlinhos",
"Attributes": [
{
"RealFieldName": "LIFECYCLESTAGE",
"Value": "New"
},
{
"RealFieldName": "COUNTRY",
"Value": "UK"
}
]
}
],
"CallbackUrl": "https://tenantname.requestcatcher.com/test"
}Response Codes
The immediate HTTP response tells you whether the batch was accepted, not whether the customers in it were processed. Processing outcomes arrive later, in the status message.
| Code | Meaning | What it means here |
|---|---|---|
202 | Accepted | The batch passed envelope validation and was queued for processing. The response body contains a traceId. Individual customers may still be rejected later — check the status message. |
400 | Bad Request | The payload failed validation: a required field is missing, the JSON is malformed, or the batch contains more than 1000 customers. Nothing in the request is processed. |
401 | Unauthorized | The X-API-KEY header is missing or invalid. |
403 | Forbidden | The Customer Ingestion feature is not enabled for your tenant. The response carries an error message stating this. Contact your Customer Success Manager. |
413 | Payload Too Large | The request body exceeds the 1 MB limit. Nothing in the request is processed — split the batch and resend. |
500 | Server Error | An unexpected error occurred on Optimove's side. Retry with backoff; if it persists, contact Support. |
Sample accepted response
{
"traceId": "b66ca444-c10b-4587-8dfb-95fd37c86291"
}Store the traceId. It is the correlation key between the request you sent and the status message that arrives at your callback URL.
Status Messages
If you supply a CallbackUrl, Optimove sends a single POST request to that URL once every customer in the batch has finished processing. The status message is the authoritative record of what happened to the batch — it replaces the individual rejection callbacks previously sent by this endpoint.
Status messages are not storedA status message is generated once and delivered to your callback URL. It is not retained, and there is no API for retrieving it on demand. If your endpoint is unavailable when the message is sent, the outcome of that batch is lost.
Status Message Fields
| Field | Data Type | Description |
|---|---|---|
status | String | Batch outcome. One of success (every customer processed) or partial success (at least one customer rejected). |
traceId | String | Correlation ID returned when the batch was accepted. |
totalCustomers | Integer | Number of customers in the batch, as evaluated by Optimove. |
insertedCustomers | Integer | Number of customers newly registered by this batch. |
updatedCustomers | Integer | Number of existing customers whose attributes were updated. |
rejectedCustomers | Integer | Number of customers that were not processed. See rejections. |
skippedAttributes | Array | Attribute names that were ignored during processing, including any attribute that does not exist in your database configuration. Skipped attributes do not reject the customer — the rest of that customer's update is applied. |
rejections | Array | One object per rejected customer, describing why it was rejected. |
Rejection Object Fields:
| Field | Data Type | Description |
|---|---|---|
customerId | String | The client customer ID that was rejected. |
reason | String | Description of why the customer was rejected. See the list below. |
existing | Boolean | true if the customer already existed in Optimove, false if the rejection was for a new customer. |
Rejection reasons
- Empty attribute list is not allowed — the payload for an existing customer contained an empty list of attribute updates.
- Updates for attribute
{RealFieldName}are not allowed — the payload contains an attribute that is forbidden to be updated using this process. Currently this includes INTERNAL and REALTIME attributes, as well as attributes from the list of restricted attributes. - Unable to convert
{RealFieldName}value to type{ATTRIBUTE_TYPE}— the payload contains an attribute value that does not correspond to its data type in the database configuration.
An attribute that does not exist in your database configuration is not a rejection reason. It is skipped and reported in skippedAttributes, and the rest of that customer's update is applied normally.
Example: partial success
{
"status": "partial success",
"traceId": "1111-2222-3333-4444",
"totalCustomers": 1000,
"insertedCustomers": 500,
"updatedCustomers": 400,
"rejectedCustomers": 100,
"skippedAttributes": [
"MyExampleAttribute"
],
"rejections": [
{
"customerId": "some-customer",
"reason": "Unable to convert 'MyExampleAttribute' value to type 'bigint'",
"existing": true
}
]
}Error Handling
Input Errors
The following error types will appear in the errors array in the response to the API request.
Errors while using this endpoint typically occur due to invalid input or a missing required field.
Example for reference:
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "00-1885aa03207df32c3c6bd9ed6f57838c-74dd6db0e400caa4-00",
"errors": {
"CustomerID": [
"The CustomerID field is required."
]
}
}Processing Errors
Errors raised while processing individual customers are reported in the rejections array of the status message sent to your CallbackUrl, not in the response to the API call. See Status Messages above.
202Accepted
500Server Error
