> ## Documentation Index
> Fetch the complete documentation index at: https://docs.0xmonaco.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Python, Go, C++ & More

> Use Python directly, or generate typed clients from Monaco's Buf Schema Registry module

Use this page when the TypeScript, React, or Rust SDKs are not the right fit. You have two integration paths:

| Path | Use when |
| - | - |
| Python REST | You want a direct Python backend integration over HTTP/JSON. |
| Generated clients | You want typed gRPC clients for Go, Python, C++, Java, C#, Kotlin, Swift, Ruby, PHP, TypeScript, or another Buf-supported target. |

## Python REST

This example uses Python with Monaco's REST API. Public market data does not require authentication; trading and account routes require a Monaco client ID plus a wallet-authorized ed25519 session key.

### Prerequisites

```bash theme={null}
pip install requests eth-account eth-utils pynacl
```

You'll need a secp256k1 private key for an Ethereum-compatible wallet and a Monaco `clientId`.

### Market Data

No authentication is required to read trading pairs.

```python theme={null}
import requests

BASE_URL = "https://staging.apimonaco.xyz"
API_PREFIX = "/api"
CLIENT_ID = "YOUR_CLIENT_ID"

session = requests.Session()

pairs = session.get(
    f"{BASE_URL}{API_PREFIX}/market/pairs",
    params={"isActive": "true", "pageSize": 20},
).json()["tradingPairs"]

for pair in pairs[:5]:
    print(f"{pair['symbol']}  tick={pair['tickSize']}  min={pair['minOrderSize']}")

pair = next(pair for pair in pairs if pair["symbol"] == "SEI/USDC")
pair_id = pair["id"]
```

### Authenticate

Monaco authenticates with a wallet-authorized ed25519 **session key**. Generate a keypair locally, have the wallet sign a challenge that commits to it, then sign every authenticated request with the session key. No tokens are issued.

```python theme={null}
from eth_account import Account
from eth_account.messages import encode_defunct
from eth_utils import to_hex
from nacl.signing import SigningKey

PRIVATE_KEY = "0xYOUR_PRIVATE_KEY"

acct = Account.from_key(PRIVATE_KEY)
address = acct.address

session_key = SigningKey.generate()
sessionPublicKey = session_key.verify_key.encode().hex()

challenge = session.post(
    f"{BASE_URL}{API_PREFIX}/auth/challenge",
    json={
        "address": address,
        "clientId": CLIENT_ID,
        "sessionPublicKey": sessionPublicKey,
    },
).json()

sig = Account.sign_message(
    encode_defunct(text=challenge["message"]),
    private_key=PRIVATE_KEY,
)
signature = to_hex(bytes(sig.signature))

session.post(
    f"{BASE_URL}{API_PREFIX}/auth/verify",
    json={
        "address": address,
        "signature": signature,
        "nonce": challenge["nonce"],
        "clientId": CLIENT_ID,
        "sessionPublicKey": sessionPublicKey,
    },
).raise_for_status()
```

### Sign Requests

This guide uses legacy signing, where every authenticated request carries `X-Monaco-PublicKey`, `X-Monaco-Timestamp`, and `X-Monaco-Signature`, and the signature covers `METHOD\npath?query\ntimestamp_ms\nSHA256_hex(body)`. Monaco also accepts [RFC 9421 HTTP message signatures](/reference/http-message-signatures) over the same session key; a Python client can implement either, but never both on one request. Serialize the body yourself so the bytes you hash are exactly the bytes you send:

```python theme={null}
import hashlib
import json
import time

def signed_request(method, path, body_obj=None):
    request_path = f"{API_PREFIX}{path}"
    body = json.dumps(body_obj).encode() if body_obj is not None else b""
    timestamp_ms = str(int(time.time() * 1000))
    body_hash = hashlib.sha256(body).hexdigest()
    signing_string = f"{method}\n{request_path}\n{timestamp_ms}\n{body_hash}"
    signature = session_key.sign(signing_string.encode()).signature.hex()
    headers = {
        "X-Monaco-PublicKey": sessionPublicKey,
        "X-Monaco-Timestamp": timestamp_ms,
        "X-Monaco-Signature": signature,
        "Content-Type": "application/json",
    }
    return session.request(method, f"{BASE_URL}{request_path}", data=body, headers=headers)
```

### Place and Cancel an Order

The API keeps `idempotencyKey` optional. Raw REST callers and generated Python bindings must supply their own keys for retry protection. Create and retain the key before serialization or signing. Persist the prepared payload and key before sending if recovery must survive a process restart.

```python theme={null}
from uuid import uuid4

order_request = {
    "idempotencyKey": str(uuid4()),
    "tradingPairId": pair_id,
    "orderType": "LIMIT",
    "side": "BUY",
    "price": "0.0100",
    "quantity": "0.1",
    "timeInForce": "GTC",
}
# Save order_request before sending; reuse it unchanged for recovery.
order = signed_request("POST", "/orders", order_request).json()

orderId = order["orderId"]
print(f"order {orderId}: {order['status']}")

cancel = signed_request("POST", "/orders/cancel", {"orderId": orderId}).json()
print(f"cancel: {cancel['status']}")
```

For a lost create response, pass the same `order_request` to `signed_request` again, which produces a fresh signature. Use a distinct key for every batch-create item, generated before signing the batch. Generated protobuf clients use the field name `idempotency_key`; populate it before `SerializeToString()` and retain the message for recovery. Protection lasts 24 hours after acceptance and retries do not extend it. Do not retry an unresolved submission after expiry. These examples do not retry automatically.

A `GTC` order rests on the book until filled or cancelled. See [Order Management](/developers/trade) for other time-in-force options.

## Generate gRPC Clients with BSR

Monaco publishes protobuf definitions to the [Buf Schema Registry](https://buf.build/monaco-sdk/api). Use BSR when you want generated gRPC clients in Go, Python, C++, Java, C#, Kotlin, Swift, Ruby, PHP, TypeScript, or another supported language.

### Install Buf

```bash theme={null}
brew install bufbuild/buf/buf
# or: curl -sSL https://buf.build/install.sh | sh
```

### Create `buf.gen.yaml`

Use the Monaco BSR module as the input and select plugins for your target language.

<CodeGroup>
  ```yaml Go theme={null}
  version: v2
  inputs:
    - module: buf.build/monaco-sdk/api:main
  plugins:
    - remote: buf.build/protocolbuffers/go
      out: gen/go
      opt:
        - paths=source_relative
    - remote: buf.build/grpc/go
      out: gen/go
      opt:
        - paths=source_relative
  ```

  ```yaml Python theme={null}
  version: v2
  inputs:
    - module: buf.build/monaco-sdk/api:main
  plugins:
    - remote: buf.build/protocolbuffers/python
      out: gen/python
    - remote: buf.build/grpc/python
      out: gen/python
  ```

  ```yaml C++ theme={null}
  version: v2
  inputs:
    - module: buf.build/monaco-sdk/api:main
  plugins:
    - remote: buf.build/protocolbuffers/cpp
      out: gen/cpp
    - remote: buf.build/grpc/cpp
      out: gen/cpp
  ```

  ```yaml TypeScript theme={null}
  version: v2
  inputs:
    - module: buf.build/monaco-sdk/api:main
  plugins:
    - remote: buf.build/bufbuild/es
      out: gen/ts
    - remote: buf.build/connectrpc/es
      out: gen/ts
  ```
</CodeGroup>

Browse the [BSR plugin catalog](https://buf.build/plugins) for other targets and swap the remote plugins into the same shape.

### Generate

```bash theme={null}
buf generate
```

The generated code is written to the `out:` directories you configured.

## REST Clients from OpenAPI

If you prefer REST in a language other than Python, generate a client from Monaco's OpenAPI spec. The spec is generated from the same protobuf contracts and powers the [REST API Reference](/api-reference), which is the source of truth for routes, request bodies, responses, and authentication headers.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.