> For the complete documentation index, see [llms.txt](https://naviprotocol.gitbook.io/astros/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://naviprotocol.gitbook.io/astros/astros-perpetual/astros-api/basic-info.md).

# Basic Info

### General rules

* All API responses are JSON.
* All times and timestamps are Unix time in **milliseconds**.
* For `GET` requests, append parameters to the URL query string.
* `POST` requests use either `application/json` or `application/x-www-form-urlencoded`, as specified per endpoint.
* Endpoints that require authentication must include `APIKEY` and `signature` in the request headers.

When **Signature required** is `Yes`, add these headers:

| Header      | Description                                                           |
| ----------- | --------------------------------------------------------------------- |
| `APIKEY`    | Your API key (`app_key`)                                              |
| `signature` | HMAC-SHA256 signature of the request payload, keyed with `app_secret` |

### Access

| Network | REST                    | WebSocket                           |
| ------- | ----------------------- | ----------------------------------- |
| Mainnet | `https://api.astros.ag` | `wss://api.astros.ag/api/market/ws` |

### Apply for an API key

The API has three categories: **public queries**, **private queries**, and **private operations**. Private endpoints require an API key.

The platform issues an `app_key` and `app_secret` over a secure channel:

| Name         | Usage                                                             |
| ------------ | ----------------------------------------------------------------- |
| `app_key`    | Sent as the `APIKEY` request header                               |
| `app_secret` | Used to sign request payloads. Store securely and never expose it |

#### Prerequisites

Before you start:

1. **Sui wallet** — You need a Sui wallet and its private key.
2. **Registered Astros account** — Connect your wallet on Astros and sign in at least once.
3. **No open positions (recommended)** — Avoid creating an API key while you have active positions. After creating a key, avoid trading on the web UI with the same account, which can cause unexpected behavior.
4. **Dev environment (optional)** — Install language SDKs if you plan to call the API from code.

#### Quick start

**Step 1: Generate a wallet signature**

Node.js example (see Sample signature code for other languages):

```javascript
// npm install @mysten/sui
const { Ed25519Keypair } = require('@mysten/sui/keypairs/ed25519');
const { decodeSuiPrivateKey } = require('@mysten/sui/cryptography');

const PRIVATE_KEY = 'suiprivkey1xxx...';

async function createSignature() {
  const { secretKey } = decodeSuiPrivateKey(PRIVATE_KEY);
  const keypair = Ed25519Keypair.fromSecretKey(secretKey);

  const address = keypair.getPublicKey().toSuiAddress();
  const timestamp = Date.now();
  const label = 'my-trading-bot';

  // Exact line breaks matter
  const message = `Create API Key\nLabel: ${label}\nTimestamp: ${timestamp}`;

  const { signature } = await keypair.signPersonalMessage(
    new TextEncoder().encode(message)
  );

  console.log({ address, label, timestamp, signature });
}

createSignature();
```

**Step 2: Call the apply endpoint**

```bash
curl -X POST 'https://api.astros.ag/api/contract-sub-provider/user/apikey/apply' \
  -H 'Content-Type: application/json' \
  -d '{
    "address": "0x1234...",
    "label": "my-trading-bot",
    "timestamp": 1735200000000,
    "signature": "AML..."
  }'
```

**Step 3: Save the API secret**

`apiSecret` is shown **only once**. Store it immediately.

```json
{
  "code": 200,
  "msg": "SUCCESS",
  "data": {
    "apiKey": "UK_a1b2c3d4e5f6g7h8",
    "apiSecret": "sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "label": "my-trading-bot",
    "signType": 1,
    "status": 1,
    "createTime": "2025-12-26 10:00:00"
  }
}
```

{% hint style="warning" %}
After creation, the API key enters **manual review** (typically 1–2 business days). Trading with the key is only available after approval.
{% endhint %}

#### Create API key

`POST` `/api/contract-sub-provider/user/apikey/apply`

**Content-Type:** `application/json`\
**Auth:** Wallet personal-message signature (not HMAC)

**Message to sign**

```
Create API Key
Label: {label}
Timestamp: {timestamp}
```

**Request body**

| Name        | Type   | Required | Description                           |
| ----------- | ------ | -------- | ------------------------------------- |
| `address`   | String | Yes      | Sui wallet address                    |
| `label`     | String | Yes      | Human-readable key label              |
| `timestamp` | Number | Yes      | Unix time in milliseconds             |
| `signature` | String | Yes      | Wallet signature of the message above |

**Example request**

```bash
curl -X POST 'https://api.astros.ag/api/contract-sub-provider/user/apikey/apply' \
  -H 'Content-Type: application/json' \
  -d '{
    "address": "0x1234567890abcdef...",
    "label": "my-trading-bot",
    "timestamp": 1735200000000,
    "signature": "AMLxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx..."
  }'
```

**Example response**

```json
{
  "code": 200,
  "msg": "SUCCESS",
  "data": {
    "apiKey": "UK_a1b2c3d4e5f6g7h8",
    "apiSecret": "sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "label": "my-trading-bot",
    "signType": 1,
    "status": 1,
    "createTime": "2025-12-26 10:00:00"
  }
}
```

#### List API keys

`POST` `/api/contract-sub-provider/user/apikey/list`

**Content-Type:** `application/json`\
**Auth:** Wallet personal-message signature

**Message to sign**

```
List API Keys
Timestamp: {timestamp}
```

**Request body**

| Name        | Type   | Required | Description                           |
| ----------- | ------ | -------- | ------------------------------------- |
| `address`   | String | Yes      | Sui wallet address                    |
| `timestamp` | Number | Yes      | Unix time in milliseconds             |
| `signature` | String | Yes      | Wallet signature of the message above |

**Example request**

```bash
curl -X POST 'https://api.astros.ag/api/contract-sub-provider/user/apikey/list' \
  -H 'Content-Type: application/json' \
  -d '{
    "address": "0x1234567890abcdef...",
    "timestamp": 1735200000000,
    "signature": "AMLxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx..."
  }'
```

#### Delete API key

`POST` `/api/contract-sub-provider/user/apikey/remove`

**Content-Type:** `application/json`\
**Auth:** Wallet personal-message signature

**Message to sign**

```
Delete API Key
API Key: {apiKey}
Timestamp: {timestamp}
```

**Request body**

| Name        | Type   | Required | Description                           |
| ----------- | ------ | -------- | ------------------------------------- |
| `address`   | String | Yes      | Sui wallet address                    |
| `apiKey`    | String | Yes      | API key to delete                     |
| `timestamp` | Number | Yes      | Unix time in milliseconds             |
| `signature` | String | Yes      | Wallet signature of the message above |

**Example request**

```bash
curl -X POST 'https://api.astros.ag/api/contract-sub-provider/user/apikey/remove' \
  -H 'Content-Type: application/json' \
  -d '{
    "address": "0x1234567890abcdef...",
    "apiKey": "UK_a1b2c3d4e5f6g7h8",
    "timestamp": 1735200000000,
    "signature": "AMLxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx..."
  }'
```

**Example response**

```json
{
  "code": 200,
  "msg": "SUCCESS",
  "data": true
}
```

#### Sample signature code

**Node.js**

```javascript
// npm install @mysten/sui
const { Ed25519Keypair } = require('@mysten/sui/keypairs/ed25519');
const { decodeSuiPrivateKey } = require('@mysten/sui/cryptography');

async function signMessage(privateKey, message) {
  const { secretKey } = decodeSuiPrivateKey(privateKey);
  const keypair = Ed25519Keypair.fromSecretKey(secretKey);
  const address = keypair.getPublicKey().toSuiAddress();
  const { signature } = await keypair.signPersonalMessage(
    new TextEncoder().encode(message)
  );
  return { address, signature };
}

// Example: create API key
const message = `Create API Key\nLabel: test-apikey\nTimestamp: ${Date.now()}`;
const { address, signature } = await signMessage('suiprivkey1xxx...', message);
```

**Python**

```python
# pip3 install pynacl
import hashlib
import base64
from nacl.signing import SigningKey
from nacl.encoding import RawEncoder

def sign_message(private_key_bytes: bytes, message: str):
    signing_key = SigningKey(private_key_bytes)
    public_key = bytes(signing_key.verify_key)

    address = '0x' + hashlib.blake2b(
        bytes([0x00]) + public_key, digest_size=32
    ).digest().hex()

    msg_bytes = message.encode('utf-8')
    intent = bytes([3, 0, 0])
    if len(msg_bytes) < 128:
        bcs_len = bytes([len(msg_bytes)])
    else:
        bcs_len = bytes([len(msg_bytes) & 0x7F | 0x80, len(msg_bytes) >> 7])

    digest = hashlib.blake2b(intent + bcs_len + msg_bytes, digest_size=32).digest()
    signed = signing_key.sign(digest, encoder=RawEncoder)
    signature = base64.b64encode(bytes([0x00]) + signed.signature + public_key).decode()

    return address, signature
```

**Java**

```java
// dependency: org.bouncycastle:bcprov-jdk18on:1.77
import org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters;
import org.bouncycastle.crypto.signers.Ed25519Signer;
import org.bouncycastle.jcajce.provider.digest.Blake2b;

import java.nio.charset.StandardCharsets;
import java.util.Base64;

public String[] signMessage(byte[] privateKey, String message) throws Exception {
    Ed25519PrivateKeyParameters keyParams = new Ed25519PrivateKeyParameters(privateKey, 0);
    byte[] publicKey = keyParams.generatePublicKey().getEncoded();
    Blake2b.Blake2b256 blake2b = new Blake2b.Blake2b256();

    byte[] addrData = new byte[33];
    addrData[0] = 0x00;
    System.arraycopy(publicKey, 0, addrData, 1, 32);
    String address = "0x" + bytesToHex(blake2b.digest(addrData));

    byte[] msgBytes = message.getBytes(StandardCharsets.UTF_8);
    byte[] intent = {3, 0, 0};
    byte[] bcsLen = msgBytes.length < 128
        ? new byte[]{(byte) msgBytes.length}
        : new byte[]{(byte) (msgBytes.length & 0x7f | 0x80), (byte) (msgBytes.length >> 7)};
    byte[] intentMsg = concat(intent, bcsLen, msgBytes);
    byte[] digest = blake2b.digest(intentMsg);

    Ed25519Signer signer = new Ed25519Signer();
    signer.init(true, keyParams);
    signer.update(digest, 0, digest.length);
    byte[] sig = signer.generateSignature();

    byte[] result = new byte[97];
    result[0] = 0x00;
    System.arraycopy(sig, 0, result, 1, 64);
    System.arraycopy(publicKey, 0, result, 65, 32);

    return new String[]{address, Base64.getEncoder().encodeToString(result)};
}
```

#### Cautions

* After creating an API key, avoid trading on the web UI with the same account.
* Currently limited to **1 API key per account**.
* The API secret is shown only at creation time and cannot be retrieved later. Delete and recreate if lost.
* If you see `USER_NOT_EXIST`, connect your wallet and sign in at <https://astros.ag> before applying for an API key.
* New keys require manual review (typically 1–2 business days) before trading is enabled.

### Request signing (HMAC)

Private REST and WebSocket calls use **HMAC-SHA256** with `app_secret` as the key. The signature is a **lowercase hex** string.

#### Java example

```java
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

public class HMacUtil {
    public static String sha256(String message, String secret) throws Exception {
        Mac sha256HMAC = Mac.getInstance("HmacSHA256");
        SecretKeySpec secretKey = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
        sha256HMAC.init(secretKey);
        byte[] hash = sha256HMAC.doFinal(message.getBytes());

        StringBuilder hex = new StringBuilder();
        for (byte b : hash) {
            String stmp = Integer.toHexString(b & 0xFF);
            if (stmp.length() == 1) {
                hex.append('0');
            }
            hex.append(stmp);
        }
        return hex.toString().toLowerCase();
    }
}
```

#### String to sign

* Do **not** include the `signature` field itself.
* For query / form params, sort parameter names ascending and join as `key=value` with `&`.
* Spaces in parameter values are included as-is.
* Treat all values as strings when building the payload to sign.

| Request style                              | String to sign                                                   |
| ------------------------------------------ | ---------------------------------------------------------------- |
| `POST` `application/json`                  | Exact JSON body string (no extra spaces if your client minifies) |
| `POST` `application/x-www-form-urlencoded` | Sorted `key=value&...` string                                    |
| `GET` query string                         | Everything after `?` (sorted params recommended)                 |

**JSON body example**

```
{"symbol":"ETH","timestamp":"1679638652028"}
```

**Form / query example**

```
symbol=ETH&timestamp=1679638652028
```

### Response status

HTTP uses standard status codes.

Response body:

| Field   | Description                                   |
| ------- | --------------------------------------------- |
| `error` | `false` on success                            |
| `code`  | `200` on success; any other value is an error |
| `msg`   | Human-readable status                         |
| `data`  | Payload                                       |
| `sid`   | Request / trace id                            |

Any `code` other than `200` indicates an error with a corresponding message.
