

# Users API Reference

API endpoints for managing users.

## List Users

`GET` `https://api.igloohome.co/works/users`

Returns a plain array of user records. Unlike other list endpoints, this response is not wrapped in `{payload: [...]}` and does not support pagination.

### Request Example

```bash
curl -X GET "https://api.igloohome.co/works/users" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Accept: application/json"
```

```go
package main

import (
	"fmt"
	"io"
	"net/http"
)

func main() {
	url := "https://api.igloohome.co/works/users"
	req, _ := http.NewRequest("GET", url, nil)
	req.Header.Set("Authorization", "Bearer YOUR_ACCESS_TOKEN")
	req.Header.Set("Accept", "application/json")

	res, _ := http.DefaultClient.Do(req)
	defer res.Body.Close()

	body, _ := io.ReadAll(res.Body)
	fmt.Println(string(body))
}
```

```javascript
const res = await fetch("https://api.igloohome.co/works/users", {
  method: "GET",
  headers: {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Accept": "application/json"
  }
});

const data = await res.json();
console.log(data);
```

```python
import requests

url = "https://api.igloohome.co/works/users"
headers = {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Accept": "application/json"
}
response = requests.get(url, headers=headers)
print(response.json())
```

```php
<?php
$curl = curl_init();

curl_setopt_array($curl, [
    CURLOPT_URL => "https://api.igloohome.co/works/users",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "GET",
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer YOUR_ACCESS_TOKEN",
        "Accept: application/json"
    ]
]);

$response = curl_exec($curl);
curl_close($curl);

echo $response;
```

```kotlin
val client = OkHttpClient()

val request = Request.Builder()
    .url("https://api.igloohome.co/works/users")
    .method("GET", null)
    .addHeader("Authorization", "Bearer YOUR_ACCESS_TOKEN")
    .addHeader("Accept", "application/json")
    .build()

val response = client.newCall(request).execute()
println(response.body?.string())
```

```swift
import Foundation

var request = URLRequest(url: URL(string: "https://api.igloohome.co/works/users")!)
request.httpMethod = "GET"
request.setValue("Bearer YOUR_ACCESS_TOKEN", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Accept")

let task = URLSession.shared.dataTask(with: request) { data, response, error in
    if let data = data {
        print(String(data: data, encoding: .utf8) ?? "")
    }
}
task.resume()
```

### Responses

`200 OK. Raw array, not '{payload}'-wrapped.`
`400 '{message: "Company ID missing", code: "COMPANY_ID_MISSING"}'.`
`401 Unauthorized, invalid or expired authorization token`
`402-account-suspended Payment Required. Account is billing-suspended or past its trial grace period.`
`402-trial-ended Payment Required. iglooworks API trial has ended.`
`500 '{message: "Internal server error", code: "INTERNAL_SERVER_ERROR"}'.`

**Response body — `400`:**

- **`message`** `string`
- **`code`** `string`

**Response body — `402-account-suspended`:**

- **`error`** `string`

**Response body — `402-trial-ended`:**

- **`error`** `string`

**Response body — `500`:**

- **`message`** `string`
- **`code`** `string`

**Example response — `400`:**

```json
{
  "code": "string",
  "message": "string"
}
```

**Example response — `402-account-suspended`:**

```json
{
  "error": "account.payment.is.suspended"
}
```

**Example response — `402-trial-ended`:**

```json
{
  "error": "30 days iglooworks API trial has ended"
}
```

**Example response — `500`:**

```json
{
  "code": "string",
  "message": "string"
}
```

## Create User

`POST` `https://api.igloohome.co/works/users`

Creates the user and sends them an invitation.

### Body Parameters

Content-Type: `application/json`

- **`email`** `string<email>` *required*
- **`firstName`** `string` *required*
- **`lastName`** `string` *required*
- **`userType`** `string` *required*
  - Allowed values: `ADMIN`, `MANAGER`, `GUEST`
- **`departmentRef`** `array of string`\
  Department IDs. Required for non-ADMIN users in multi-department accounts; not allowed in single-department accounts; ignored for ADMIN (admins get all departments).
- **`mobileNumber`** `string`\
  Requires mobileCountryCode in the same request. Must be unique within the account.
- **`mobileCountryCode`** `string`\
  Required if mobileNumber is set. Prefix such as `+65`, prepended to mobileNumber.
- **`mfaPreference`** `boolean`

### Request Example

```bash
curl -X POST "https://api.igloohome.co/works/users" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "departmentRef": "value",
    "email": "value",
    "firstName": "value",
    "lastName": "value",
    "mfaPreference": "value",
    "mobileCountryCode": "value",
    "mobileNumber": "value",
    "userType": "value"
  }'
```

```go
package main

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
)

func main() {
	url := "https://api.igloohome.co/works/users"
	payload := []byte(`{
		"departmentRef": "value",
		"email": "value",
		"firstName": "value",
		"lastName": "value",
		"mfaPreference": "value",
		"mobileCountryCode": "value",
		"mobileNumber": "value",
		"userType": "value"
	}`)

	req, _ := http.NewRequest("POST", url, bytes.NewBuffer(payload))
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer YOUR_ACCESS_TOKEN")
	req.Header.Set("Accept", "application/json")

	res, _ := http.DefaultClient.Do(req)
	defer res.Body.Close()

	body, _ := io.ReadAll(res.Body)
	fmt.Println(string(body))
}
```

```javascript
const res = await fetch("https://api.igloohome.co/works/users", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "departmentRef": "value",
    "email": "value",
    "firstName": "value",
    "lastName": "value",
    "mfaPreference": "value",
    "mobileCountryCode": "value",
    "mobileNumber": "value",
    "userType": "value"
  })
});

const data = await res.json();
console.log(data);
```

```python
import requests

url = "https://api.igloohome.co/works/users"
headers = {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Accept": "application/json"
}
payload = {
    "departmentRef": "value",
    "email": "value",
    "firstName": "value",
    "lastName": "value",
    "mfaPreference": "value",
    "mobileCountryCode": "value",
    "mobileNumber": "value",
    "userType": "value"
}
response = requests.post(url, headers=headers, json=payload)
print(response.json())
```

```php
<?php
$curl = curl_init();

curl_setopt_array($curl, [
    CURLOPT_URL => "https://api.igloohome.co/works/users",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "POST",
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer YOUR_ACCESS_TOKEN",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS => json_encode([
        "departmentRef" => "value",
        "email" => "value",
        "firstName" => "value",
        "lastName" => "value",
        "mfaPreference" => "value",
        "mobileCountryCode" => "value",
        "mobileNumber" => "value",
        "userType" => "value"
    ])
]);

$response = curl_exec($curl);
curl_close($curl);

echo $response;
```

```kotlin
val client = OkHttpClient()

val mediaType = "application/json".toMediaType()
val body = """
    {
        "departmentRef": "value",
        "email": "value",
        "firstName": "value",
        "lastName": "value",
        "mfaPreference": "value",
        "mobileCountryCode": "value",
        "mobileNumber": "value",
        "userType": "value"
    }
""".trimIndent().toRequestBody(mediaType)

val request = Request.Builder()
    .url("https://api.igloohome.co/works/users")
    .method("POST", body)
    .addHeader("Authorization", "Bearer YOUR_ACCESS_TOKEN")
    .addHeader("Accept", "application/json")
    .addHeader("Content-Type", "application/json")
    .build()

val response = client.newCall(request).execute()
println(response.body?.string())
```

```swift
import Foundation

var request = URLRequest(url: URL(string: "https://api.igloohome.co/works/users")!)
request.httpMethod = "POST"
request.setValue("Bearer YOUR_ACCESS_TOKEN", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let payload: [String: Any] = [
    "departmentRef": "value",
    "email": "value",
    "firstName": "value",
    "lastName": "value",
    "mfaPreference": "value",
    "mobileCountryCode": "value",
    "mobileNumber": "value",
    "userType": "value"
]
request.httpBody = try? JSONSerialization.data(withJSONObject: payload)

let task = URLSession.shared.dataTask(with: request) { data, response, error in
    if let data = data {
        print(String(data: data, encoding: .utf8) ?? "")
    }
}
task.resume()
```

### Responses

`201 Created.`
`400 Bad Request`
`401 Unauthorized, invalid or expired authorization token`
`402-account-suspended Payment Required. Account is billing-suspended or past its trial grace period.`
`402-trial-ended Payment Required. iglooworks API trial has ended.`
`403 Forbidden. One of: (1) the token is valid but lacks the required scope for this endpoint (no body); (2) the user revoked the OAuth client's access ('{error: "The user has revoked access for this application..."}').`
`409 USER_ALREADY_EXISTS.`
`500 FLAT_ORG_DEPT_NOT_FOUND, COGNITO_CREATE_FAILED, COGNITO_REF_MISSING, USER_RECORD_CREATION_FAILED.`

**Response body — `201`:**

- **`message`** `string`
- **`user`** `object`

**Response body — `400`:**

- **`message`** `string`
- **`code`** `string`

**Response body — `402-account-suspended`:**

- **`error`** `string`

**Response body — `402-trial-ended`:**

- **`error`** `string`

**Response body — `403`:**

- **`error`** `string`

**Response body — `409`:**

- **`message`** `string`
- **`code`** `string`

**Response body — `500`:**

- **`message`** `string`
- **`code`** `string`

**Example response — `201`:**

```json
{
  "message": "string",
  "user": {}
}
```

**Example response — `400`:**

```json
{
  "code": "string",
  "message": "string"
}
```

**Example response — `402-account-suspended`:**

```json
{
  "error": "account.payment.is.suspended"
}
```

**Example response — `402-trial-ended`:**

```json
{
  "error": "30 days iglooworks API trial has ended"
}
```

**Example response — `403`:**

```json
{
  "error": "string"
}
```

**Example response — `409`:**

```json
{
  "code": "string",
  "message": "string"
}
```

**Example response — `500`:**

```json
{
  "code": "string",
  "message": "string"
}
```

## Update User

`PUT` `https://api.igloohome.co/works/users/{id}`

### Path Parameters

| Parameter | Type | Required |
| --- | --- | --- |
| id | string | Yes |

### Body Parameters

Content-Type: `application/json`

- **`fullName`** `string`\
  Full name as one string. Create uses `firstName` and `lastName`; update takes `fullName` instead.
- **`mobileCountryCode`** `string`
- **`mobileNumber`** `string`\
  Requires mobileCountryCode in the same request. Must be unique within the account.
- **`lang`** `string`
- **`userType`** `string`
  - Allowed values: `ADMIN`, `MANAGER`, `GUEST`
- **`departmentRef`** `array of string`\
  Department IDs. Replaces the user's current departments. Not allowed for single-department accounts or when userType is ADMIN.
- **`mfaPreference`** `boolean`

### Request Example

```bash
curl -X PUT "https://api.igloohome.co/works/users/{id}" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "departmentRef": "value",
    "fullName": "value",
    "lang": "value",
    "mfaPreference": "value",
    "mobileCountryCode": "value",
    "mobileNumber": "value",
    "userType": "value"
  }'
```

```go
package main

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
)

func main() {
	url := "https://api.igloohome.co/works/users/{id}"
	payload := []byte(`{
		"departmentRef": "value",
		"fullName": "value",
		"lang": "value",
		"mfaPreference": "value",
		"mobileCountryCode": "value",
		"mobileNumber": "value",
		"userType": "value"
	}`)

	req, _ := http.NewRequest("PUT", url, bytes.NewBuffer(payload))
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer YOUR_ACCESS_TOKEN")
	req.Header.Set("Accept", "application/json")

	res, _ := http.DefaultClient.Do(req)
	defer res.Body.Close()

	body, _ := io.ReadAll(res.Body)
	fmt.Println(string(body))
}
```

```javascript
const res = await fetch("https://api.igloohome.co/works/users/{id}", {
  method: "PUT",
  headers: {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "departmentRef": "value",
    "fullName": "value",
    "lang": "value",
    "mfaPreference": "value",
    "mobileCountryCode": "value",
    "mobileNumber": "value",
    "userType": "value"
  })
});

const data = await res.json();
console.log(data);
```

```python
import requests

url = "https://api.igloohome.co/works/users/{id}"
headers = {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Accept": "application/json"
}
payload = {
    "departmentRef": "value",
    "fullName": "value",
    "lang": "value",
    "mfaPreference": "value",
    "mobileCountryCode": "value",
    "mobileNumber": "value",
    "userType": "value"
}
response = requests.put(url, headers=headers, json=payload)
print(response.json())
```

```php
<?php
$curl = curl_init();

curl_setopt_array($curl, [
    CURLOPT_URL => "https://api.igloohome.co/works/users/{id}",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "PUT",
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer YOUR_ACCESS_TOKEN",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS => json_encode([
        "departmentRef" => "value",
        "fullName" => "value",
        "lang" => "value",
        "mfaPreference" => "value",
        "mobileCountryCode" => "value",
        "mobileNumber" => "value",
        "userType" => "value"
    ])
]);

$response = curl_exec($curl);
curl_close($curl);

echo $response;
```

```kotlin
val client = OkHttpClient()

val mediaType = "application/json".toMediaType()
val body = """
    {
        "departmentRef": "value",
        "fullName": "value",
        "lang": "value",
        "mfaPreference": "value",
        "mobileCountryCode": "value",
        "mobileNumber": "value",
        "userType": "value"
    }
""".trimIndent().toRequestBody(mediaType)

val request = Request.Builder()
    .url("https://api.igloohome.co/works/users/{id}")
    .method("PUT", body)
    .addHeader("Authorization", "Bearer YOUR_ACCESS_TOKEN")
    .addHeader("Accept", "application/json")
    .addHeader("Content-Type", "application/json")
    .build()

val response = client.newCall(request).execute()
println(response.body?.string())
```

```swift
import Foundation

var request = URLRequest(url: URL(string: "https://api.igloohome.co/works/users/{id}")!)
request.httpMethod = "PUT"
request.setValue("Bearer YOUR_ACCESS_TOKEN", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let payload: [String: Any] = [
    "departmentRef": "value",
    "fullName": "value",
    "lang": "value",
    "mfaPreference": "value",
    "mobileCountryCode": "value",
    "mobileNumber": "value",
    "userType": "value"
]
request.httpBody = try? JSONSerialization.data(withJSONObject: payload)

let task = URLSession.shared.dataTask(with: request) { data, response, error in
    if let data = data {
        print(String(data: data, encoding: .utf8) ?? "")
    }
}
task.resume()
```

### Responses

`200 Updated. Returns '{message: "No changes provided to update", user}' if every provided field matched the existing value.`
`400 MOBILE_COUNTRY_CODE_REQUIRED, PHONE_NUMBER_IN_USE, DEPARTMENT_REF_NOT_ALLOWED, admin-cannot-have-department.`
`401 Unauthorized, invalid or expired authorization token`
`402-account-suspended Payment Required. Account is billing-suspended or past its trial grace period.`
`402-trial-ended Payment Required. iglooworks API trial has ended.`
`403 Forbidden. One of: (1) the token is valid but lacks the required scope for this endpoint (no body); (2) the user revoked the OAuth client's access ('{error: "The user has revoked access for this application..."}').`
`404 USER_NOT_FOUND.`

**Response body — `200`:**

- **`message`** `string`
- **`user`** `object`

**Response body — `400`:**

- **`message`** `string`
- **`code`** `string`

**Response body — `402-account-suspended`:**

- **`error`** `string`

**Response body — `402-trial-ended`:**

- **`error`** `string`

**Response body — `403`:**

- **`error`** `string`

**Response body — `404`:**

- **`message`** `string`
- **`code`** `string`

**Example response — `200`:**

```json
{
  "message": "string",
  "user": {}
}
```

**Example response — `400`:**

```json
{
  "code": "string",
  "message": "string"
}
```

**Example response — `402-account-suspended`:**

```json
{
  "error": "account.payment.is.suspended"
}
```

**Example response — `402-trial-ended`:**

```json
{
  "error": "30 days iglooworks API trial has ended"
}
```

**Example response — `403`:**

```json
{
  "error": "string"
}
```

**Example response — `404`:**

```json
{
  "code": "string",
  "message": "string"
}
```

## Delete User

`DELETE` `https://api.igloohome.co/works/users/{id}`

Behavior branches on whether the user has confirmed their invite yet: unconfirmed → cancels the invite and soft-deletes; confirmed → disables the user (`isEnabled: false`) and removes their eKey/MFA access instead of deleting the record outright.

### Path Parameters

| Parameter | Type | Required |
| --- | --- | --- |
| id | string | Yes |

### Request Example

```bash
curl -X DELETE "https://api.igloohome.co/works/users/{id}" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Accept: application/json"
```

```go
package main

import (
	"fmt"
	"io"
	"net/http"
)

func main() {
	url := "https://api.igloohome.co/works/users/{id}"
	req, _ := http.NewRequest("DELETE", url, nil)
	req.Header.Set("Authorization", "Bearer YOUR_ACCESS_TOKEN")
	req.Header.Set("Accept", "application/json")

	res, _ := http.DefaultClient.Do(req)
	defer res.Body.Close()

	body, _ := io.ReadAll(res.Body)
	fmt.Println(string(body))
}
```

```javascript
const res = await fetch("https://api.igloohome.co/works/users/{id}", {
  method: "DELETE",
  headers: {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Accept": "application/json"
  }
});

const data = await res.json();
console.log(data);
```

```python
import requests

url = "https://api.igloohome.co/works/users/{id}"
headers = {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Accept": "application/json"
}
response = requests.delete(url, headers=headers)
print(response.json())
```

```php
<?php
$curl = curl_init();

curl_setopt_array($curl, [
    CURLOPT_URL => "https://api.igloohome.co/works/users/{id}",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "DELETE",
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer YOUR_ACCESS_TOKEN",
        "Accept: application/json"
    ]
]);

$response = curl_exec($curl);
curl_close($curl);

echo $response;
```

```kotlin
val client = OkHttpClient()

val request = Request.Builder()
    .url("https://api.igloohome.co/works/users/{id}")
    .method("DELETE", null)
    .addHeader("Authorization", "Bearer YOUR_ACCESS_TOKEN")
    .addHeader("Accept", "application/json")
    .build()

val response = client.newCall(request).execute()
println(response.body?.string())
```

```swift
import Foundation

var request = URLRequest(url: URL(string: "https://api.igloohome.co/works/users/{id}")!)
request.httpMethod = "DELETE"
request.setValue("Bearer YOUR_ACCESS_TOKEN", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Accept")

let task = URLSession.shared.dataTask(with: request) { data, response, error in
    if let data = data {
        print(String(data: data, encoding: .utf8) ?? "")
    }
}
task.resume()
```

### Responses

`200 "User invitation cancelled successfully" or "User deactivated successfully".`
`401 Unauthorized, invalid or expired authorization token`
`402-account-suspended Payment Required. Account is billing-suspended or past its trial grace period.`
`402-trial-ended Payment Required. iglooworks API trial has ended.`
`404 USER_NOT_FOUND.`
`409 USER_ACCEPTED_INVITATION (trying to cancel an invite that was already accepted).`

**Response body — `200`:**

- **`message`** `string`
- **`user`** `object`

**Response body — `402-account-suspended`:**

- **`error`** `string`

**Response body — `402-trial-ended`:**

- **`error`** `string`

**Response body — `404`:**

- **`message`** `string`
- **`code`** `string`

**Response body — `409`:**

- **`message`** `string`
- **`code`** `string`

**Example response — `200`:**

```json
{
  "message": "string",
  "user": {}
}
```

**Example response — `402-account-suspended`:**

```json
{
  "error": "account.payment.is.suspended"
}
```

**Example response — `402-trial-ended`:**

```json
{
  "error": "30 days iglooworks API trial has ended"
}
```

**Example response — `404`:**

```json
{
  "code": "string",
  "message": "string"
}
```

**Example response — `409`:**

```json
{
  "code": "string",
  "message": "string"
}
```

