> This page is for Taurus PROTECT, version v3.58 (default).
> For other versions, use one of these documentation indexes:
> - v3.58 (default): https://taurushq.ferndocs.com/protect-capital/v3.58/llms.txt
> - v3.56: https://taurushq.ferndocs.com/protect-capital/v3.56/llms.txt
> - v3.54: https://taurushq.ferndocs.com/protect-capital/v3.54/llms.txt
> - v3.52: https://taurushq.ferndocs.com/protect-capital/v3.52/llms.txt
> - v3.50: https://taurushq.ferndocs.com/protect-capital/v3.50/llms.txt
> - v3.48: https://taurushq.ferndocs.com/protect-capital/v3.48/llms.txt
> - v3.46: https://taurushq.ferndocs.com/protect-capital/v3.46/llms.txt
> - v3.44: https://taurushq.ferndocs.com/protect-capital/v3.44/llms.txt
> - v3.42: https://taurushq.ferndocs.com/protect-capital/v3.42/llms.txt
> - v3.40: https://taurushq.ferndocs.com/protect-capital/v3.40/llms.txt
> - v3.38: https://taurushq.ferndocs.com/protect-capital/v3.38/llms.txt

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://taurushq.ferndocs.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://taurushq.ferndocs.com/_mcp/server.

# Create a change

POST https://your-protect-instance.example.com/api/rest/v1/changes
Content-Type: application/json

Taurus-PROTECT has a robust change approval system where each change must be approved by admins or in some cases, superadmins. This endpoint can be used to make change requests to users, wallets, whitelisted addresses, and more. 

This endpoint creates a new change which is then sent to admins or in some cases superadmins for approval. It is the same endpoint that powers the PROTECT web and desktop applications.  

Entities represent what is being changed. For example, a user, a group, a wallet, etc. The action represents what is being done to the entity. For example, creating a new user, updating an existing user, deleting a user, etc. Each entity can accept different fields which are passed to the API as JSON in the `changes` parameter. 

The following table lists the supported entities, actions and valid change fields.

## Entity Actions & Valid Change Fields

| `Entity`                  | `Supported Actions`                                                       | `Valid Change Fields`                                                                                                                                         |
|:---------------------------|:-----------------------------------------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `User`                    | `create`, `update`, `delete`, `resetpassword`, `resettotp`, `resetkeycontainer` | `firstname`, `lastname`, `status`, `roles`, `externaluserid`, `username`, `publickey`, `email`, `userid`, `keycontainer`                                      |
| `Group`                   | `create`, `update`, `delete`                                                 | `name`, `externalgroupid`, `description`, `groupemail`                                                                                                         |
| `UserGroup`               | `create`, `update`, `delete`                                                 | `name`, `externalgroupid`, `description`                                                                                                                       |
| `Exchange`                | `create`, `update`, `delete`                                                 | `name`, `symbol`, `country`, `website`                                                                                                                         |
| `BusinessRule`            | `create`, `update`, `delete`                                                 | `rulekey`, `rulevalue`, `rulewalletid`                                                                                                                         |
| `Rule`                    | `create`, `update`, `delete`                                                 | `name`, `description`, `condition`, `action`                                                                                                                   |
| `Price`                   | `create`, `update`, `delete`                                                 | `blockchain`, `currencyfrom`, `currencyto`, `decimals`, `rate`, `source`, `currencyfromid`, `currencytoid`                                                    |
| `TPAction`                | `create`, `update`, `delete`                                                 | `label`, `autoApprove`, `trigger`, `tasks`, `state`                                                                                                            |
| `FeePayer`                | `create`, `update`, `delete`                                                 | `name`, `network`, `blockchain`, `address`                                                                                                                     |
| `SecurityDomain`          | `create`, `update`, `delete`                                                 | `name`, `description`, `mode`, `openid_configuration_url`                                                                                                      |
| `UserApiKey`              | `create`, `update`, `delete`                                                 | `key`, `description`, `permissions`                                                                                                                           |
| `VisibilityGroup`         | `create`, `update`, `delete`                                                 | `name`, `description`, `members`                                                                                                                              |
| `UserVisibilityGroup`     | `create`, `update`, `delete`                                                 | `userid`, `visibilitygroupid`                                                                                                                                  |
| `Wallet`                  | `create`, `update`, `delete`                                                 | `address`, `network`, `type`, `balance`                                                                                                                       |
| `WhitelistedAddress`      | `create`, `update`, `delete`                                                 | `address`, `network`, `type`, `description`                                                                                                                   |
| `ManualAccountFreeze`     | `create`, `update`, `delete`                                                 | `account`, `reason`, `duration`                                                                                                                               |
| `ManualUTXOFreeze`        | `create`, `update`, `delete`                                                 | `utxo`, `reason`, `duration`                                                                                                                                  |
| `autotransfereventhandler`| `create`, `update`, `delete`                                                 | `monitored_wallet_id`, `payer_address_id`, `trigger_type`, `minimum_fiat_value_token`, `transfer_amount_factor_percentage`, `status`                          |

## Entity specific processing rules

The `changes` API implements CRUD semantics on various entities, where each entity type has its own processing rules. Here are some of the entity-specific rules that apply. Note that this list is non-exhaustive.

### All Entities

- You cannot create a change which already exists. The API will return an error.
- Once a change has been created, it cannot be edited. You must reject the change and create a new one.
- Once approved, changes are applied immediately by PROTECT.

### `User`

- Super admin users cannot be deleted.
- A user's `Super Admin` role cannot be removed.
- Only `firstname`, `lastname`, `email`, `username`, `status` and `roles` can be changed for Super Admin users.
- All users must have an `externalUserID` (typically an email address).

### `Groups`

- If SSO is enabled, groups changed via SCIM cannot be changed manually.
- Groups are automatically reset for SSO users on the next login, creating a change request.

### Account Freezes

- There are two different entities for account freezes (manualaccountbalancefreeze, manualutxofreeze) depending on if a blockchain is account based (e.g., Ethereum) or utxo based (e.g., Bitcoin). For examples on how to freeze funds see the [develop and integrate guide.](https://docs.taurushq.com/protect-capitalnull/null#freezing-funds-in-protect-1)


Reference: https://taurushq.ferndocs.com/protect-capital/reference/changes/create

## Authentication

- `Authorization` header (bearer token, required) — Bearer authentication of the form `Bearer <token>`, where token is your auth token.

## Request

### Body (application/json)

This endpoint expects a tgvalidatordCreateChangeRequest.

- `action` (string, required) — Can be one of the following: `create` `update` `delete` `resetpassword` `resettotp` `resetkeycontainer` `assign` `unassign`
- `entity` (string, required) — Can be one of the following: `user` `group` `usergroup` `businessrule` `exchange` `price` `action` `feepayer` `userapikey` `securitydomain` `taurusnetworkparticipant` `visibilitygroup` `uservisibilitygroup` `manualaccountbalancefreeze` `manualutxofreeze` `wallet` `whitelistedaddress` `autotransfereventhandler`
- `entityId` (string, optional) — The id of the entity to change.
- `changes` (map from string to string, optional) — This field is only mandatory if the action is 'create' or 'update'. It includes the actual changes to be made to the entity. [Click here](https://taurus.readme.io/protect-capital/docs/changes) to see a list of fields for each entity.
- `changeComment` (string, optional) — A comment for describing the change request.
- `entityUUID` (string, optional) — The uuid of the entity being changed.

## Response

### 200

A successful response.

- `result` (tgvalidatordCreateChangeResult, optional)

## Errors

### 400 Bad Request Error

Bad Request: indicates that the server cannot or will not process the request due to something that is perceived to be a client error (for example, malformed request syntax, invalid request message framing, or deceptive request routing)

- `any`

### 401 Unauthorized Error

Unauthorized: indicates that the client request has not been completed because it lacks valid authentication credentials for the requested resource

- `any`

### 403 Forbidden Error

Forbidden: indicates that the server understands the request but refuses to authorize it

- `any`

### 404 Not Found Error

Not Found: indicates that the server cannot find the requested resource

- `any`

### 500 Internal Server Error

Internal Server Error: indicates that the server encountered an unexpected condition that prevented it from fulfilling the request

- `any`

### 503 Service Unavailable Error

Service Unavailable: indicates that the server is not ready to handle the request.

- `any`

## Types

### tgvalidatordCreateChangeResult

- `id` (string, optional)

## Examples

**Request**

```json
{
  "action": "create",
  "entity": "user",
  "changes": {
    "email": "johndoe@company.com",
    "externaluserid": "johndoe123",
    "firstname": "John",
    "lastname": "Doe",
    "roles": "requestcreator",
    "status": "active"
  }
}
```

**Response**

```json
{
  "result": {
    "id": "2744"
  }
}
```

**SDK Code**

```python
import requests

url = "https://your-protect-instance.example.com/api/rest/v1/changes"

payload = {
    "action": "create",
    "entity": "user",
    "changes": {
        "email": "johndoe@company.com",
        "externaluserid": "johndoe123",
        "firstname": "John",
        "lastname": "Doe",
        "roles": "requestcreator",
        "status": "active"
    }
}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript
const url = 'https://your-protect-instance.example.com/api/rest/v1/changes';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"action":"create","entity":"user","changes":{"email":"johndoe@company.com","externaluserid":"johndoe123","firstname":"John","lastname":"Doe","roles":"requestcreator","status":"active"}}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

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

func main() {

	url := "https://your-protect-instance.example.com/api/rest/v1/changes"

	payload := strings.NewReader("{\n  \"action\": \"create\",\n  \"entity\": \"user\",\n  \"changes\": {\n    \"email\": \"johndoe@company.com\",\n    \"externaluserid\": \"johndoe123\",\n    \"firstname\": \"John\",\n    \"lastname\": \"Doe\",\n    \"roles\": \"requestcreator\",\n    \"status\": \"active\"\n  }\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

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

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://your-protect-instance.example.com/api/rest/v1/changes")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"action\": \"create\",\n  \"entity\": \"user\",\n  \"changes\": {\n    \"email\": \"johndoe@company.com\",\n    \"externaluserid\": \"johndoe123\",\n    \"firstname\": \"John\",\n    \"lastname\": \"Doe\",\n    \"roles\": \"requestcreator\",\n    \"status\": \"active\"\n  }\n}"

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://your-protect-instance.example.com/api/rest/v1/changes")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"action\": \"create\",\n  \"entity\": \"user\",\n  \"changes\": {\n    \"email\": \"johndoe@company.com\",\n    \"externaluserid\": \"johndoe123\",\n    \"firstname\": \"John\",\n    \"lastname\": \"Doe\",\n    \"roles\": \"requestcreator\",\n    \"status\": \"active\"\n  }\n}")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://your-protect-instance.example.com/api/rest/v1/changes', [
  'body' => '{
  "action": "create",
  "entity": "user",
  "changes": {
    "email": "johndoe@company.com",
    "externaluserid": "johndoe123",
    "firstname": "John",
    "lastname": "Doe",
    "roles": "requestcreator",
    "status": "active"
  }
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://your-protect-instance.example.com/api/rest/v1/changes");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"action\": \"create\",\n  \"entity\": \"user\",\n  \"changes\": {\n    \"email\": \"johndoe@company.com\",\n    \"externaluserid\": \"johndoe123\",\n    \"firstname\": \"John\",\n    \"lastname\": \"Doe\",\n    \"roles\": \"requestcreator\",\n    \"status\": \"active\"\n  }\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [
  "action": "create",
  "entity": "user",
  "changes": [
    "email": "johndoe@company.com",
    "externaluserid": "johndoe123",
    "firstname": "John",
    "lastname": "Doe",
    "roles": "requestcreator",
    "status": "active"
  ]
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://your-protect-instance.example.com/api/rest/v1/changes")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```