> For the complete documentation index, see [llms.txt](https://docs.vomevolunteer.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.vomevolunteer.com/resources/database/profiles/write-operations.md).

# Write Operations

Vome API offers endpoints to create, update or upsert (create and/or update) profiles directly in your Vome database.

***

**How we does Vome identify a profile in your database?**\
\
We offer 3 flexible ways for your team to identify profiles from your Vome database.<br>

1. **Email address (default method)**: The email address field is a **username** in the Vome system, and therefore can be used to match profiles from other systems.<br>

   *<mark style="color:orange;">For example, let's say you want to update existing profiles in your Vome database. One of the profiles getting updated will be Bill Smith (who has an email of <bill@domain.com>). When sending a PUT request to update profiles, we will check to see if there is a profile with the email <bill@domain.com> to update).</mark>*<br>
2. **Vome ID:** Every profile on Vome has a unique identifier string value associated with their account. You can access these Vome ID values when retrieving profiles\
   \
   *<mark style="color:orange;">For example, let's say you want to update existing profiles in your Vome database. One of the profiles getting updated will be Bill Smith (who has a Vome ID equal to "123"). When sending a PUT request to update profiles, we will check to see if there is a profile with the Vome ID of "123" to update).</mark>*<br>
3. **Custom ID field**: On Vome, we offer the ability for admins to create **custom fields** in their database. We offer a **field type** called "**Unique ID**" which allows you to add Unique ID values and associate them with profiles.\
   \
   *<mark style="color:orange;">For example, you can create a Vome database field. The field type would be "Unique ID" and the name of the field entered is "Salesforce ID". By doing so, we can then match profiles based on this user value for this custom field.</mark>*<br>

#### Endpoints

```plaintext
POST api/profiles/bulk-create/
PUT api/profiles/bulk-update/
PUT api/profiles/bulk-upsert/
```

#### API specification

* **unique\_identifier** (`object`): Includes the setting of how you would like to identify users from your database.
  * **identifier\_type** (`integer` | `null`):
    * `0` = Email
    * `1` = Vome ID
    * `2` = Custom Field - Unique ID
  * **unique\_id** (`string` | `null`): If the **identifier\_type** is set to **Custom Field - Unique ID**, this would be the ID of the field from Vome.
    * *For example, if you created a new field on the Vome database calle**d Salesforce User ID**, when retrieving a profile using our endpoint, you will see this field has an **associated field ID**, which can be used here.*<br>
* **invite\_user\_to\_vome** (`boolean`| `null`): Whether you choose to invite the new user to claim their profile on Vome. If you choose to make this **False**, the profile will remain **Offline** in your database unless invited in the future.
* **invite\_language** (`string` | `null`): You can pass "EN" or "FR".
  * If you choose to invite the user to claim their profile, indicate whether you want to send the invitation in English or French
* **invite\_message** (`string` | `null`): You can send HTML inside of a string.
  * If you choose to invite the user to claim their profile, you can include a custom message to be included in the email notification sent to them.
* **users\_data** (`array` | `null`): An array storing profile and other related information to the user. For complete information about the fiels that relate to the user profile, please review the Profile object.

#### Profile-level fields

These keys sit on each entry of **users\_data**, alongside **profile\_data**, **emergency\_contact**, **medical\_information**, **occupation\_info** and **custom\_field\_data**.

Every field here is optional, and an omitted key leaves the stored value untouched. That means you can send a narrow payload to change one thing without clearing everything else on the profile.

* **sites** (`array` | `null`): A list of site names or site IDs to assign this profile to. Names are matched exactly against the sites in your organization, and you can mix names and IDs in the same array. Sites are **added** to the profile's existing site memberships, so sending this key never removes a site the profile already belongs to.
* **tags** (`array` | `null`): A list of profile tag titles or tag IDs to apply to this profile. Like sites, tags are **added** to what the profile already has. Tags must already exist: create them first with `POST api/profile-tags/bulk-create/`. Unknown tags are skipped and reported back.
* **groups** (`array` | `null`): A list of group names or group IDs to add this profile to. Groups must already exist: create them first with `POST api/groups/bulk-create/`. Unknown groups are skipped and reported back.
* **group\_role** (`integer` | `null`): The role to give this profile in the groups listed above. `0` for Member, `1` for Leader. Omit it to leave the role of any existing membership unchanged.
* **start\_user\_date** (`string` | `null`): The date this profile started with your organization, as `YYYY-MM-DD`. This is what drives years of service and tenure reporting.
* **kiosk\_code** (`string` | `null`): The profile's kiosk PIN. Validated against your organization's PIN policy and must be unique within your organization.
* **prior\_logged\_hours** (`number` | `null`): Hours this profile logged before they joined Vome.
* **prior\_logged\_hours\_date** (`string` | `null`): The date those prior hours were accrued up to, as an ISO 8601 timestamp.
* **logged\_hours\_off\_vome** (`number` | `null`): Hours this profile logged outside Vome. Setting this records an entry in the profile's hours history.

{% hint style="warning" %}
Group names are not unique in Vome. If a name in **groups** matches more than one group, we skip it and tell you rather than guessing, because guessing would put people in the wrong group. Send the group ID instead.
{% endhint %}

#### Fields inside profile\_data

In addition to the fields listed on the Profile object, **profile\_data** accepts:

* **gender\_text** (`string`): Free-text gender description. Only meaningful when **gender** is `2` (Other).
* **address\_city**, **address\_state**, **address\_country**, **address\_postal\_code** (`string`): The structured parts of the profile's address, which appear as their own columns in your Vome database. These are independent of the free-text **address** field, so you can send either one, or both.

{% hint style="info" %}
If a single field on one profile cannot be accepted (for example a kiosk PIN that is already taken), we import the rest of that profile and report just that field back in the response. One bad value never fails the whole batch.
{% endhint %}

#### Example Request Payload

```json
{
    "unique_identifier": {
        "identifier_type":0, //Email address
        "unique_custom_field": "" 
    },
    "invite_user_to_vome": true,
    "invite_language": "EN",
    "invite_message": "<p>We cannot wait for you to claim your profile!</p>",
    "users_data": [
        {
            "emergency_contact": {
                "name": "Jon Smith",
                "phone_number": "5555555555",
                "relationship": "Father"
            },
            "medical_information": {
                "description": "Allergies to peanuts",
                "has_medical_info": "true"
            },
            "occupation_info":{
                "occupation":0, //Student
                "occupation_institution_name":"University of Memphis"
            },
            "profile_data": {
                "id":"d2fcbe43-1eba-419e-a489-3d471f7658ff",
                "first_name": "Lily",
                "last_name": "Smith",
                "email":"lily.smith123@domain.com",
                "phone_number": "555555555",
                "date_of_birth": "1998-06-06",
                "gender": 1, //Female
                "address": "7 Freedom Trail, Medway, Norfolk, MA, USA",
                "address_city": "Medway",
                "address_state": "MA",
                "address_country": "USA",
                "address_postal_code": "02053",
                "address_coordinates": [ 
                    "42.14579519999999",
                    "-71.4391298"
                ]
            },
            "sites": [
                "Downtown Branch",
                "8f1c2b7e-5a93-4d16-9a0e-2c74be5f1d88"
            ],
            "tags": [
                "Board Member",
                "ec007482-7c9a-4ec0-963d-8cb0048ff2fc"
            ],
            "groups": [
                "64fd9793-0b67-4b02-a163-f2a7216292af"
            ],
            "group_role": 1, //Leader
            "start_user_date": "2024-01-15",
            "kiosk_code": "4821",
            "prior_logged_hours": 120.5,
            "prior_logged_hours_date": "2023-12-31T00:00:00Z",
            "logged_hours_off_vome": 8,
            "custom_field_data": [
                {
                    "custom_field_id": "395fd06d-48ca-41a0-be0c-3cd22fdad976",
                    "custom_field_name": "Salesforce ID",
                    "custom_field_user_value": "fe8fwe7f7897487r87hb"
                },
                {
                    "custom_field_id": "78c03e94-097b-4f00-8aaa-6b7e4ddf1e93",
                    "custom_field_name": "T-shirt size",
                    "custom_field_user_value": "Medium"
                }

            ]
        }
    ]
}
```
