> For the complete documentation index, see [llms.txt](https://help.enterprise.ledger.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://help.enterprise.ledger.com/api-documentation/tutorials/api-administrator/first-steps-as-an-api-user.md).

# Create an account

### Prerequisite

To perform the following steps, your API Administrator must:

* [be registered](/api-documentation/tutorials/first-steps-as-an-api-user/register-a-new-api-user.md) and part of the right admin rule.
* [be authenticated](/api-documentation/tutorials/first-steps-as-an-api-user/authenticate-as-an-api-user.md)&#x20;

### Create an account with policy

{% hint style="warning" %}
To ensure complete security in your workspace and handle on-chain requests using our security module, follow these guidelines to create accounts and prevent errors:

* Maximum 200 accounts per hour (including the validation of their requests)
* Create the accounts in sequence: create account 1 > approve account 1 request > Create account 2...
  {% endhint %}

#### Building your request payload:

To build a payload to create a new account with policy, we need to know:

* the account type (e.g, `TRC20_LIKE`)
* the account index (e.g, `0`)
* the account name (max 19 characters, no special characters, e.g, `USDT 1`)
* the account currency (e.g, `tron`)
* the name of the policy used (e.g, `Multipolicy 1`)
* (if token) the parent id (e.g, `95`)
* (if token) the contract address (e.g, `TCFLL5dx5ZJdKnWuesXxi1VPwjLVmWZZy9`)

*See the* [*create request reference*](/api-documentation/reference/api-reference/requests/create.md) *for more information.*

The resulting request payload is the following:

```json
{
  "data": {
    "account_type": "TRC20_LIKE",
    "account_data": {
      "index": 0,
      "name": "JST",
      "currency": "tron",
      "policy_name": "Multipolicy 1",
      "parent_id": 95,
      "contract_address": "TCFLL5dx5ZJdKnWuesXxi1VPwjLVmWZZy9"
    }
  },
  "type": "CREATE_ACCOUNT"
}
```

### Approve a request

Once you created your request, you need to approve the challenge as the request creator before other administrators are notified to approve. To approve a request, you'll need to follow these steps:

#### Get the challenge

Given a `request_id`, first need to fetch the HSM challenge:

{% tabs %}
{% tab title="Bash" %}

```bash
curl --request GET \
  --url https://api.vault.ledger.com/requests/{{request_id}}/challenge \
  --header 'authorization: Bearer {{access_token}}' \
  --header 'content-type: application/json' \
  --header 'x-ledger-workspace: minivault'
```

{% endtab %}

{% tab title="JSON" %}

```json
{
"challenge": "eyJhbnRpcmVwbGF5IjoiM0JCMzdERkIxREYxRkQ5REUzNEZDQUZCQkVGNjZDQjVDMUVEMTU3MzEzNTRGQjAxNDZEQ0MyMjk3NjdEMzVCMSIsImRhdGEiOnsidHJhbnNhY3Rpb25fZGF0YSI6eyJhY2NvdW50X25hbWUiOiJDbGllbnRBIENPTCBUQlRDIDEiLCJhbW91bnQiOiIxMDAiLCJjdXJyZW5jeSI6ImJpdGNvaW4gdGVzdG5ldCIsIm1heF9mZWVzIjoiMjExIiwicmVjaXBpZW50IjoidGIxcTl3ZXh3OXB6amtsajd5cWxkNmczbGVqeHpyMHdndndoengwbmVrIn0sInRyYW5zYWN0aW9uX3R5cGUiOiJCSVRDT0lOX0xJS0VfU0VORCJ9LCJ0eXBlIjoiQVBQUk9WRV9UUkFOU0FDVElPTiJ9",
"id": 29
}
```

{% endtab %}
{% endtabs %}

#### Decoding the challenge

Decode the challenge to validate that the instructions HSM received is the same as the one you passed in your request:

{% tabs %}
{% tab title="Python" %}

```python
import jwt

// decode the challenge
challenge_data_bytes = jwt.utils.base64url_decode(challenge)
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import * as crypto from 'crypto';
import * as jwt from 'jsonwebtoken';

// decode the challenge
const decodedString = atob(dataToSign);
const jsonObject = JSON.parse(decodedString);
```

{% endtab %}

{% tab title="Example" %}

```
{
  "antireplay": "0D1B06079EE2DDF9E5220EFC36F401B8A3BBE1F2124F9DC89615DC5BC4D0AFD1",
  "data": {
    "account_data": {
      "contract_address": "TLa2f6VPqDgRE67v1736s7bJ8Ray5wYjU7",
      "currency": "tron",
      "index": "2",
      "name": "TRC20 Account 2",
      "policy_name": "Test"
    },
    "account_type": "TRC20_LIKE"
  },
  "type": "CREATE_ACCOUNT"
}
```

{% endtab %}
{% endtabs %}

Carefully review that what you are about to sign is the right instructions matching your initial intention. This challenge is the trusted data signed by your administrator that will allow the HSM to sign the true account.

{% hint style="warning" %}
This is an important step, when decoding the challenge from the HSM this need to be the exact same information the account creator passed in `transaction_data`.
{% endhint %}

#### Signing the challenge

Sign the challenge with your user private key

{% tabs %}
{% tab title="Python" %}

```python
import jwt

def sign_challenge(challenge: bytes, private_key_hex: str) -> str:
    private_key_bytes = bytes.fromhex(private_key_hex)
    challenge_data_bytes = jwt.utils.base64url_decode(challenge)
    jws = jwt.PyJWS()
    jws: str = jws.encode(challenge_data_bytes, private_key_bytes, algorithm="ES256")
    return jws
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import * as crypto from 'crypto';
import * as jwt from 'jsonwebtoken';

// // Data to be signed
const challenge = "eyJhbnRpcmVwbGF5IjoiM0JCMzdERkIxREYxRkQ5REUzNEZDQUZCQkVGNjZDQjVDMUVEMTU3MzEzNTRGQjAxNDZEQ0MyMjk3NjdEMzVCMSIsImRhdGEiOnsidHJhbnNhY3Rpb25fZGF0YSI6eyJhY2NvdW50X25hbWUiOiJDbGllbnRBIENPTCBUQlRDIDEiLCJhbW91bnQiOiIxMDAiLCJjdXJyZW5jeSI6ImJpdGNvaW4gdGVzdG5ldCIsIm1heF9mZWVzIjoiMjExIiwicmVjaXBpZW50IjoidGIxcTl3ZXh3OXB6amtsajd5cWxkNmczbGVqeHpyMHdndndoengwbmVrIn0sInRyYW5zYWN0aW9uX3R5cGUiOiJCSVRDT0lOX0xJS0VfU0VORCJ9LCJ0eXBlIjoiQVBQUk9WRV9UUkFOU0FDVElPTiJ9"

// Json to be sign
const decodedString = atob(challenge);
const jsonObject = JSON.parse(decodedString);
console.log("----- Json to be signed ----")
console.log(jsonObject);
console.log("----------------------------")

// Load the private key
const private_key_bytes = `-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEILMAPH5tb765vxNGiAmAaeBvFZnRtzTqfG/ZWQHXxv1NoAoGCCqGSM49\nAwEHoUQDQgAE5iRVj/FjRl3RLNmY0E8os9nyo/lxsII/WiAgNMq8z7tGFZ+G55g4\nqQwYCbfDE9in554X5KVTJqn2EDFl95QNPA==\n-----END EC PRIVATE KEY-----`
const privateKey = crypto.createPrivateKey({
  key: private_key_bytes,
  format: 'pem'
});
const privateKeyPem = privateKey.export({ format: 'pem', type: 'sec1' });
console.log('\nLoaded Private Key (PEM/SEC1):\n', privateKeyPem);

// Sign the data using the private key
const decodedData = Buffer.from(challenge, 'base64').toString('hex');
const jws = jwt.sign(Buffer.from(decodedData, 'hex'), privateKeyPem, {
  algorithm: 'ES256',
  header: {
    alg: 'ES256',
    typ: 'JWT'
  }
});

console.log("----- JWS Token ----")
console.log(jws);
console.log("--------------------")
```

{% endtab %}

{% tab title="Example" %}

```
yJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJhbnRpcmVwbGF5IjoiM0JCMzdERkIxREYxRkQ5REUzNEZDQUZCQkVGNjZDQjVDMUVEMTU3MzEzNTRGQjAxNDZEQ0MyMjk3NjdEMzVCMSIsImRhdGEiOnsidHJhbnNhY3Rpb25fZGF0YSI6eyJhY2NvdW50X25hbWUiOiJDbGllbnRBIENPTCBUQlRDIDEiLCJhbW91bnQiOiIxMDAiLCJjdXJyZW5jeSI6ImJpdGNvaW4gdGVzdG5ldCIsIm1heF9mZWVzIjoiMjExIiwicmVjaXBpZW50IjoidGIxcTl3ZXh3OXB6amtsajd5cWxkNmczbGVqeHpyMHdndndoengwbmVrIn0sInRyYW5zYWN0aW9uX3R5cGUiOiJCSVRDT0lOX0xJS0VfU0VORCJ9LCJ0eXBlIjoiQVBQUk9WRV9UUkFOU0FDVElPTiJ9.F4NFOkcoQaAdxRwLQ_-QUal-XbBNhg-yjiTW_ycLmqA-wLrmpRpJ0owxjcf_QAkLyxWlkGpxH9gaymvsAl2KDA
```

{% endtab %}
{% endtabs %}

with private*key*bytes the PEM format bytes of the private key

```
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIDN4pKvYZtwGLC/XiUKdUjPJJGTRd1MQxVKsiaWEAY1OoAoGCCqGSM49
AwEHoUQDQgAEdcIngZ7X7X5sipnIuP3rt1w6mg3V9LQE4txm5cx0tvaDxon+W6Kx
CBtTMvPCR5D9a9Nab2cNEjvKePWyzOHqMg==
-----END EC PRIVATE KEY-----
```

**JSON Web Signature details**

And `jws` the signed challenge / jws object. The resulting `jws` consists of three parts: the JWS Header, the JWS Payload, and the JWS Signature. The three parts are base64url-encoded and concatenated in that order being separated by period ('.') characters.

#### Approve the request

Once you signed the challenge use it to post your approval on the approve request endpoint:

{% tabs %}
{% tab title="Bash" %}

```bash
curl --request POST \
  --url https://api.vault.ledger.com/requests/{{request_id}}/approve \
  --header 'authorization: Bearer {{access_token}}' \
  --header 'content-type: application/json' \
  --header 'x-ledger-workspace: <workspace name>' \
  --data '{
      "jws": "{{jws}}"
  }'
```

{% endtab %}

{% tab title="JSON" %}

```json
{
"created_by": {
  "id": 24
},
"created_on": "2024-01-24T08:07:08.007892+00:00",
"expired_at": "2024-01-31T08:07:08.007837+00:00",
"id": 29,
"status": "PENDING_APPROVAL",
"target_id": 305,
"target_type": "BITCOIN_LIKE_TRANSACTION",
"type": "CREATE_TRANSACTION"
}
```

{% endtab %}
{% endtabs %}

If the response status is 200, the response payload will be the request with its new status, in our case we are still waiting for another approval from a second user so the status stays in `PENDING_APPROVAL`.

Once this is done, the next important step is [approving the request](/api-documentation/tutorials/api-functionalities/approve-a-request.md) so the account is created.


---

# 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 dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://help.enterprise.ledger.com/api-documentation/tutorials/api-administrator/first-steps-as-an-api-user.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
