# Builder Mode

> Non-custodial integration for building trading terminals on top of Opinion's prediction market.
>
> To request Builder access, Please kindly fill out this [short application form ](https://forms.gle/tqL84A5mMXjZ1xT86).&#x20;

## What is Builder Mode?

Builder mode lets you create your own trading application on top of Opinion's prediction market:

* **2,000 free gasless transactions per day** (order placement and cancellation)
* **Non-custodial**: you never handle user private keys; users sign with their own wallets
* **Full API coverage**: user management, order building, Safe transactions, and more

## Architecture

```
┌──────────────┐     ┌──────────────────┐     ┌────────────┐
│  Your App    │     │  Opinion Backend  │     │  BNB Chain  │
│  (Builder)   │────>│  (API + Relayer)  │────>│  (On-chain) │
│              │     │                   │     │             │
│ BuilderClient│<────│  - Order matching │<────│  - Safe     │
│ + UserClient │     │  - TX relay       │     │  - CTF      │
│              │     │  - Safe creation  │     │  - ERC20    │
└──────────────┘     └──────────────────┘     └────────────┘
```

**Three identities involved:**

| Wallet                  | What                               | Who Controls             |
| ----------------------- | ---------------------------------- | ------------------------ |
| **EOA** (signer)        | Signs orders and Safe transactions | User (private key)       |
| **Safe** (asset wallet) | Holds funds, executes trades       | Multi-sig (EOA is owner) |
| **Builder API key**     | Authenticates builder API calls    | Builder (your server)    |

## Quick Start

```python
from opinion_clob_sdk.builder_sdk import BuilderClient
from opinion_clob_sdk.user_client import UserClient

# 1. Initialize the builder client
builder = BuilderClient(
    host="https://openapi.opinion.trade",
    builder_apikey="YOUR_BUILDER_API_KEY",
    chain_id=56,
    rpc_url="https://bsc-dataseed.binance.org",
)

# 2. Create a user sub-account
result = builder.create_user("0xUserEOAAddress...")
user_apikey = result["apikey"]       # Save this! Only returned once.
safe_address = result["multi_sig_wallet"]

# 3. Enable trading (one-time)
tx_result = builder.build_enable_trading_tx(safe_address)
# User signs tx_result["eip712_data"] with their wallet
# signature = user_wallet.sign_typed_data(tx_result["eip712_data"])
# builder.submit_safe_tx(user_address, tx_result, signature)

# 4. Build and place an order
from opinion_clob_sdk.chain.py_order_utils.model.sides import BUY
from opinion_clob_sdk.chain.py_order_utils.model.order_type import LIMIT_ORDER

order_data = builder.build_order_for_signing(
    market_id=123,
    token_id="outcome_token_id",
    user_wallet_address=safe_address,
    side=BUY,
    order_type=LIMIT_ORDER,
    amount=10.0,
    price="0.5",
    signer_address="0xUserEOAAddress...",
)
# User signs order_data["struct_hash"] with their wallet
# signature = user_wallet.sign_hash(order_data["struct_hash"])
# builder.place_order_for_user_from_build_result(order_data, signature, safe_address)
```

## Constructor Parameters

<table><thead><tr><th width="190">Parameter</th><th width="83">Type</th><th width="136">Required</th><th>Description</th></tr></thead><tbody><tr><td><code>host</code></td><td>str</td><td>Yes</td><td>API host URL</td></tr><tr><td><code>builder_apikey</code></td><td>str</td><td>Yes</td><td>Builder API key (uses <code>builder-apikey</code> header)</td></tr><tr><td><code>chain_id</code></td><td>int</td><td>Yes</td><td>Blockchain chain ID (56 for BNB Chain)</td></tr><tr><td><code>rpc_url</code></td><td>str</td><td>No</td><td>RPC endpoint URL (required for Safe operations)</td></tr><tr><td><code>use_beta</code></td><td>bool</td><td>No</td><td>Use beta (test env) mode (default: <code>False</code>)</td></tr><tr><td><code>contract_addresses</code></td><td>dict</td><td>No</td><td>Override contract addresses (required if <code>use_beta=True</code>)</td></tr></tbody></table>

## API Reference

| Page                                                                                                                         | Methods                                                                                                          |
| ---------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| [Create User](https://docs.opinion.trade/developer-guide/opinion-clob-python-sdk/builder-mode/create-user)                   | `create_user()`                                                                                                  |
| [Get User](https://docs.opinion.trade/developer-guide/opinion-clob-python-sdk/builder-mode/get-user)                         | `get_user()`, `regenerate_user_apikey()`                                                                         |
| [Get Quote Tokens](https://docs.opinion.trade/developer-guide/opinion-clob-python-sdk/builder-mode/get-quote-tokens)         | `get_quote_tokens()`                                                                                             |
| [Get Market](https://docs.opinion.trade/developer-guide/opinion-clob-python-sdk/builder-mode/get-market)                     | `get_market()`, `get_orderbook()`                                                                                |
| [Build Order](https://docs.opinion.trade/developer-guide/opinion-clob-python-sdk/builder-mode/build-order)                   | `build_order_for_signing()`, `sign_order_with_private_key()`                                                     |
| [Place Order](https://docs.opinion.trade/developer-guide/opinion-clob-python-sdk/builder-mode/place-order)                   | `place_order_for_user()`, `place_order_for_user_from_build_result()`                                             |
| [Cancel Order](https://docs.opinion.trade/developer-guide/opinion-clob-python-sdk/builder-mode/cancel-order)                 | `cancel_order_for_user()`, `cancel_orders_batch_for_user()`, `cancel_all_orders_for_user()`, `get_user_orders()` |
| [Enable Trading](https://docs.opinion.trade/developer-guide/opinion-clob-python-sdk/builder-mode/enable-trading)             | `build_enable_trading_tx()`                                                                                      |
| [Split / Merge / Redeem](https://docs.opinion.trade/developer-guide/opinion-clob-python-sdk/builder-mode/split-merge-redeem) | `build_split_tx()`, `build_merge_tx()`, `build_redeem_tx()`, `build_withdraw_tx()`, `submit_safe_tx()`           |
| [UserClient](https://docs.opinion.trade/developer-guide/opinion-clob-python-sdk/builder-mode/userclient)                     | `UserClient` testing helper                                                                                      |

## Signing Patterns

There are two distinct signing patterns:

**Order signing** (gasless, for placing orders):

```python
build_result = builder.build_order_for_signing(...)
signature = user.sign_hash(build_result["struct_hash"])
```

**Safe TX signing** (relayed, for on-chain operations):

```python
tx_result = builder.build_enable_trading_tx(safe_address)
signature = user.sign_typed_data(tx_result["eip712_data"])
```

## Signature Types

<table><thead><tr><th width="171">Type</th><th width="146">Value</th><th>Description</th></tr></thead><tbody><tr><td>EOA</td><td>0</td><td>Direct EOA signature (maker == signer)</td></tr><tr><td>GNOSIS_SAFE</td><td>2</td><td>Gnosis Safe signature (maker != signer)</td></tr></tbody></table>

The type is determined automatically based on whether `signer_address` differs from `user_wallet_address`.

## Error Handling

```python
from opinion_clob_sdk.builder_sdk import BuilderError, InvalidParamError, ApiError

try:
    result = builder.create_user(address)
except InvalidParamError as e:
    # Bad input (invalid address, missing field)
    print(f"Invalid parameter: {e}")
except ApiError as e:
    # Backend error (user exists, rate limit, server error)
    print(f"API error: {e}")
except BuilderError as e:
    # General builder error (signing failure, etc.)
    print(f"Builder error: {e}")
```

Exception hierarchy: `BuilderError` > `InvalidParamError`, `ApiError`.
