> For the complete documentation index, see [llms.txt](https://docs.mediarithmics.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.mediarithmics.io/setup-and-monitor/collect-and-manage-your-data/import-data-in-batch/import-profiles.md).

# Import profiles

Load CRM data and scoring into user profiles, and choose how existing profiles are overwritten.

## Your goal

Bring the timeless information you hold about your users - CRM fields, preferences, loyalty status, externally calculated scores - into the datamart as user profiles.

## Expected outcome

Profiles attached to the right UserPoints, in the right compartments, updated according to a strategy you chose deliberately.

## What a profile import does

The import performs `UPSERT` or `DELETE` operations on [user profiles](/setup-and-monitor/collect-and-manage-your-data/design-your-data-model-and-schema/user-identity/user-identifiers/user-account.md#when-importing-profiles). A profile is a summary of information about a user, typically imported from an existing information system such as a CRM or a login database.

## How to

{% stepper %}
{% step %}

### Create the document import

Document type `USER_PROFILE`, mime type `APPLICATION_X_NDJSON`. Only `ndjson` is supported for user profiles.

```bash
curl -X POST \
  https://api.mediarithmics.com/v1/datamarts/<DATAMART_ID>/document_imports \
  -H 'Authorization: <YOUR_API_TOKEN>' \
  -H 'Content-Type: application/json' \
  -d '{
    "document_type": "USER_PROFILE",
    "mime_type": "APPLICATION_X_NDJSON",
    "encoding": "utf-8",
    "name": "<YOUR_DOCUMENT_IMPORT_NAME>"
}'
```

{% endstep %}

{% step %}

### Create an execution with your profile commands

```bash
curl -X POST \
  https://api.mediarithmics.com/v1/datamarts/<DATAMART_ID>/document_imports/<DOCUMENT_IMPORT_ID>/executions \
  -H 'Authorization: <API_TOKEN>' \
  -H 'Content-Type: application/x-ndjson' \
  -d '{
        "operation": "UPSERT",
        "compartment_id": "<COMPARTMENT_ID>",
        "user_account_id": "<USER_ACCOUNT_ID>",
        "user_profile": {
              "firstname": "David",
              "lastname": "Guetta"
        }
      }'
```

{% endstep %}

{% step %}

### Read the result

Check `total_success`, `total_failure`, and the error file. See [reading the result](/setup-and-monitor/collect-and-manage-your-data/import-data-in-batch.md#reading-the-result).
{% endstep %}
{% endstepper %}

{% hint style="success" %}
You can upload many profiles at once. The data is `ndjson`, not `json` - profiles are separated by a line separator `\n`, not by commas.
{% endhint %}

## The profile import command

| Property          | Type             | Description                                                                                             |
| ----------------- | ---------------- | ------------------------------------------------------------------------------------------------------- |
| `operation`       | Enum             | `UPSERT` or `DELETE`.                                                                                   |
| `compartment_id`  | String, optional | The compartment ID, acting as an identifier together with `user_account_id`.                            |
| `user_account_id` | String, optional | The account ID, acting as an identifier together with `compartment_id`.                                 |
| `email_hash`      | String, optional | The email hash, acting as an identifier.                                                                |
| `user_agent_id`   | String, optional | The user agent ID, acting as an identifier.                                                             |
| `update_strategy` | Enum, optional   | Only considered when the operation is `UPSERT`. `PARTIAL_UPDATE`, `PARTIAL_DELETE`, or `FORCE_REPLACE`. |
| `user_profile`    | JSON object      | Mandatory when the operation is `UPSERT`. The profile object.                                           |

{% hint style="warning" %}
**Only one identifier is allowed per line.** Do not specify a user agent ID on a line that already carries an email hash.
{% endhint %}

{% hint style="warning" %}
Fill `$user_account_id` and `$compartment_id` **inside the profile object too**, even when the values are the same as the identifier used to route the import - the values are **not inherited** from the identifier information.

The compartment and account in the profile object can legitimately differ from the ones used to select the UserPoint.
{% endhint %}

## Choosing an update strategy

`update_strategy` decides what happens to the profile already stored.

| Strategy         | What it does                                                   | Use it when                                                                                                                                                                                          |
| ---------------- | -------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `FORCE_REPLACE`  | The profile is **completely replaced** by the object you pass. | Your source system is authoritative and sends the whole profile every time.                                                                                                                          |
| `PARTIAL_UPDATE` | Targeted updates, without overwriting the whole profile.       | You send deltas - a new loyalty card, a changed field. See [Enrich user profiles](/setup-and-monitor/collect-and-manage-your-data/import-data-in-batch/enrich-user-profiles.md).                     |
| `PARTIAL_DELETE` | Targeted deletion inside the profile.                          | You need to remove one object from an array rather than the whole profile. See [Enrich user profiles](/setup-and-monitor/collect-and-manage-your-data/import-data-in-batch/enrich-user-profiles.md). |

<details>

<summary><code>FORCE_REPLACE</code>, worked through</summary>

Stored profile:

```json
{
  "compartment_id": "<COMPARTMENT_ID>",
  "user_account_id": "<USER_ACCOUNT_ID>",
  "loyalty": {
    "cards": [
      { "benefits": 200, "card_id": "abc", "last_visit_date": "2024-01-01" }
    ]
  }
}
```

Import command:

```json
{
  "operation": "UPSERT",
  "compartment_id": "<COMPARTMENT_ID>",
  "user_account_id": "<USER_ACCOUNT_ID>",
  "update_strategy": "FORCE_REPLACE",
  "user_profile": {
    "compartment_id": "<COMPARTMENT_ID>",
    "user_account_id": "<USER_ACCOUNT_ID>",
    "loyalty": {
      "cards": [
        { "benefits": 500, "card_id": "xyz", "last_visit_date": "2025-01-01" }
      ]
    }
  }
}
```

Resulting profile - the previous card is **gone**, not merged:

```json
{
  "compartment_id": "<COMPARTMENT_ID>",
  "user_account_id": "<USER_ACCOUNT_ID>",
  "loyalty": {
    "cards": [
      { "benefits": 500, "card_id": "xyz", "last_visit_date": "2025-01-01" }
    ]
  }
}
```

</details>

## Legacy parameters

{% hint style="info" %}
`force_replace` and `merge_objects` are **legacy**. Use `update_strategy` instead. They are documented here because existing integrations still use them.
{% endhint %}

| Property        | Type    | Description                                                                                                                                                                                                                                               |
| --------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `force_replace` | Boolean | If `true`, the profile is completely replaced by the object in `user_profile`. If `false`, that object is merged with the existing profile.                                                                                                               |
| `merge_objects` | Boolean | Only considered when `force_replace` is `false`. Controls what happens between two objects sharing a property. `false` - the default - means the new object overrides the existing one. `true` means the new object is deep-merged into the existing one. |

<details>

<summary>What <code>merge_objects: true</code> does</summary>

Stored profile:

```json
{
  "my_property_1": "value1",
  "my_property_2": "value1",
  "my_array_property": ["value1"],
  "my_array_object_property": [
    { "my_sub_array_object_property_1": "value1", "my_sub_array_object_property_2": "value1" }
  ],
  "my_object_property": {
    "my_sub_object_property_1": "value1", "my_sub_object_property_2": "value1"
  }
}
```

Imported with `force_replace: false` and `merge_objects: true`:

```json
{
  "my_property_2": "value2",
  "my_property_3": "value3",
  "my_array_property": ["value2"],
  "my_array_object_property": [
    { "my_sub_array_object_property_2": "value2", "my_sub_array_object_property_3": "value3" }
  ],
  "my_object_property": {
    "my_sub_object_property_2": "value2", "my_sub_object_property_3": "value3"
  }
}
```

Result - scalars are overridden, arrays are appended to, objects are merged:

```json
{
  "my_property_1": "value1",
  "my_property_2": "value2",
  "my_property_3": "value3",
  "my_array_property": ["value1", "value2"],
  "my_array_object_property": [
    { "my_sub_array_object_property_1": "value1", "my_sub_array_object_property_2": "value1" },
    { "my_sub_array_object_property_2": "value2", "my_sub_array_object_property_3": "value3" }
  ],
  "my_object_property": {
    "my_sub_object_property_1": "value1",
    "my_sub_object_property_2": "value2",
    "my_sub_object_property_3": "value3"
  }
}
```

Note that arrays **grow** rather than being replaced, which is rarely what a nightly full export intends.

</details>

## Verify

* The execution reports the success count you expected, and the error file is empty.
* A known profile shows the fields you sent, in the compartment you targeted.
* A second import of the same file produces the result your strategy implies - replaced, merged, or appended.

## Troubleshooting

| Symptom                                              | Likely cause                                                                                    |
| ---------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
| The whole request fails                              | A property in the payload is not declared in the schema, or its type does not match the schema. |
| Profiles are created but empty                       | `$user_account_id` and `$compartment_id` were not filled inside the profile object.             |
| Arrays keep growing                                  | `merge_objects: true` merges arrays. Use `FORCE_REPLACE`, or a partial update with a key.       |
| "No profile id found while upserting a user profile" | The line does not carry a usable identifier.                                                    |

## Related pages

<table data-view="cards" data-search="false"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Enrich user profiles</strong></td><td>Targeted updates inside an existing profile.</td><td><a href="/setup-and-monitor/collect-and-manage-your-data/import-data-in-batch/enrich-user-profiles.md">Enrich user profiles</a></td></tr><tr><td><strong>Load profiles</strong></td><td>The same import through the Data loader interface.</td><td><a href="/setup-and-monitor/collect-and-manage-your-data/import-data-in-batch/data-loader/load-profiles.md">Load profiles</a></td></tr><tr><td><strong>User Account</strong></td><td>The compartment and account that identify a profile.</td><td><a href="/setup-and-monitor/collect-and-manage-your-data/design-your-data-model-and-schema/user-identity/user-identifiers/user-account.md">User Account</a></td></tr></tbody></table>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.mediarithmics.io/setup-and-monitor/collect-and-manage-your-data/import-data-in-batch/import-profiles.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
