# Integration Guide

> A complete onboarding walkthrough for new developers, covering every key step from API Key application → authentication → wallet initialisation → trade signing.

## Environment & Prerequisites

| Environment | API Base URL                  |
| ----------- | ----------------------------- |
| Production  | `https://api.open.foreso.com` |

* **Blockchain**: BNB Smart Chain (Chain ID: 56)
* **Settlement token**: USDT (18-decimal precision)
* **Wallet types**: EOA primary wallet + Safe proxy wallet

***

## Step 1 — Apply for an API Key

All endpoints (including public market data) require an API Key signature. **You must apply for one first.**

After applying you will receive two values:

| Field        | Description                                   | Example                               |
| ------------ | --------------------------------------------- | ------------------------------------- |
| `key_id`     | Placed in the `apikey` header                 | `ak_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx` |
| `key_secret` | Used for HMAC signing — **never transmitted** | `sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx` |

***

## Step 2 — Request Signing (required for all endpoints)

Every request must include the following three headers:

```
apikey: <key_id>
X-API-Timestamp: <unix_second_timestamp>
X-API-Signature: sha256=<hex_signature>
```

**Signing algorithm:**

```
message = METHOD + "\n" + PATH + "\n" + TIMESTAMP + "\n" + BODY
signature = HMAC-SHA256(message, key_secret)
# Header: X-API-Signature: sha256=<hex_result>
# BODY: JSON with no extra whitespace; empty string for GET requests
```

**Python example:**

```python
import hmac, hashlib, time

def make_headers(method, path, body=""):
    ts = str(int(time.time()))
    message = f"{method}\n{path}\n{ts}\n{body}"
    sig = hmac.new(key_secret.encode(), message.encode(), hashlib.sha256).hexdigest()
    return {
        "apikey": key_id,
        "X-API-Timestamp": ts,
        "X-API-Signature": f"sha256={sig}",
        "Content-Type": "application/json",
    }
```

> ⚠️ The server allows a clock skew of ±3 seconds. Excessive drift will cause signature failures.

***

## Step 3 — Wallet Login to Obtain a JWT

Endpoints that require user identity (place order, query assets, etc.) also need `Authorization: Bearer <jwt_token>`. JWTs are valid for 24 hours.

**3.1 Get a Nonce**

```
POST /v1/users/nonce
Body: {"address": "0x<wallet_address>"}
Response.data.message → nonce message to sign
```

**3.2 Sign the Nonce (personal\_sign — not EIP-712)**

```python
from eth_account import Account
from eth_account.messages import encode_defunct

msg = encode_defunct(text=nonce_message)
signed = Account.from_key(private_key).sign_message(msg)
signature = "0x" + signed.signature.hex()
```

**3.3 Register / Login to Exchange for a JWT**

```
POST /v1/users/register
Body: {"address": "0x...", "signature": "0x...", "message": "<nonce_message>"}
Response.data.token → JWT Token
Response.data.proxyAddress → Safe proxy wallet address (if exists)
```

***

## Step 4 — Wallet Initialisation (three steps, done once)

```
[1] enable-trading  →  [2] enable-module  →  [3] whitelist
```

**4.1 Enable Trading (creates the Safe proxy wallet)**

```
POST /v1/users/enable-trading  (JWT required)
Response.data.proxyAddress → Safe proxy wallet address
```

**4.2 Enable the Module**

```
POST /v1/wallet/enable-module/sign-data
Body: {"safeAddress": "0x<proxy_wallet>"}
→ Returns EIP-712 SafeTx signing data (domain has no name/version fields)

POST /v1/wallet/enable-module/execute
Body: {"safeAddress": "0x...", "signature": "0x..."}
```

**4.3 Set Up Whitelist**

```
POST /v1/wallet/whitelist/prepare
Body: {"proxy_wallet": "0x<proxy_wallet>"}
→ Returns { targets[], nonce, expiration, moduleAddress, chainId, contract_config_id }
```

> ⚠️ The nonce must be left-shifted by 12 bits when signing: `nonce_for_signing = int(nonce) << 12`
>
> The EIP-712 struct field is `deadline`, but the API parameter is `expiration` — note the difference.

```
POST /v1/wallet/whitelist/execute
Body: {
  "proxy_wallet": "0x...",
  "targets": [...],
  "nonce": <original_nonce>,
  "expiration": <expiration>,
  "signature": "0x...",
  "contract_config_id": "..."
}
```

***

## Step 5 — Place Orders with EIP-712 Signing

Order key fields:

| Field                         | Value                                           |
| ----------------------------- | ----------------------------------------------- |
| `maker`                       | Proxy wallet address (Safe proxy wallet)        |
| `signer`                      | Primary wallet address (EOA, the actual signer) |
| `signatureType`               | Always `2` (SAFE type)                          |
| `makerAmount` / `takerAmount` | 18-decimal-precision integers                   |

* **Buy order**: maker = USDT amount, taker = share amount
* **Sell order**: maker = share amount, taker = USDT amount

> ⚠️ **Do not use `encode_typed_data`** to build the Order signature. You must encode manually with ABI encoding; otherwise on-chain signature verification will fail.

```
POST /v1/orders  (JWT + API Signature)
Body: {
  market_id, option_id, option_name, position_id,
  amount, shares, price, side, order_type,
  signature, signature_msg, nonce
}
```

***

## Step 6 — Query Assets & Balances

```
# True available balance = on-chain USDT total − locked amount from open orders
GET /v1/orders/query_lock_balance  → data.pending_buy_usdt
GET /v1/users/positions            → list of positions
GET /v1/users/claimable-stats      → claimable reward statistics
```

> ⚠️ Using only the on-chain total will misreport the balance; orders may fail with `balance insufficient`.

***

## Step 7 — Claim Rewards

```
POST /v1/users/redeem/all          → batch one-click claim (recommended)
POST /v1/users/redeem
Body: {"market_id": "..."}         → claim for a single market
```

***

## Authentication Headers

All API requests must include these three mandatory headers:

| Header            | Description                                                           |
| ----------------- | --------------------------------------------------------------------- |
| `apikey`          | API key ID                                                            |
| `X-API-Timestamp` | Current Unix timestamp (seconds); server allows ±3 seconds skew       |
| `X-API-Signature` | Request signature: `sha256=hex(HMAC-SHA256(message, api_key_secret))` |

Example:

```http
apikey: ak_xxxxxxxx
X-API-Timestamp: 1715750400
X-API-Signature: sha256=a3f2c1...
```

***

## Rate Limits

* **10 requests per second** per API key

***

## Common Errors

| Error                                   | Cause                                                    | Solution                                                                |
| --------------------------------------- | -------------------------------------------------------- | ----------------------------------------------------------------------- |
| `Invalid API key`                       | Incorrect key\_id or HMAC signature                      | Check the message concatenation order and body serialisation            |
| `balance insufficient`                  | Insufficient available balance (deducted by open orders) | Subtract `pending_buy_usdt` from the on-chain total                     |
| `InvalidSignature`                      | EIP-712 signature construction error                     | Use manual ABI encoding; `domain.name="CTFExchange"`; `signatureType=2` |
| `whitelist EIP-712 verification failed` | Nonce not left-shifted by 12 bits                        | `nonce_for_signing = int(nonce) << 12`                                  |
| `429 Too many requests`                 | Rate limit exceeded                                      | Reduce frequency; use a token-bucket controller                         |


---

# Agent Instructions: 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:

```
GET https://foreso.gitbook.io/usersguide/foreso-open-api/getting-started.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
