Skip to Content

POST /action

Execute trading actions using protobuf-encoded messages. This endpoint handles all authenticated operations including session creation, order placement, and cancellation.

Request

Headers:

NameValue
Content-Typeapplication/octet-stream

Body:

The request body is a binary payload containing:

  1. Varint-encoded length of the Action message
  2. Serialized Action protobuf message
  3. Ed25519 signature (64 bytes)
┌─────────────────┬────────────────────────┬─────────────────┐ │ Length (varint) │ Action (protobuf) │ Signature (64B) │ └─────────────────┴────────────────────────┴─────────────────┘

Protobuf Schema

Download the schema from https://zo-devnet.n1.xyz/schema.proto

Generate bindings:

# Python curl https://zo-devnet.n1.xyz/schema.proto -o schema.proto protoc --python_out=. schema.proto

Action Types

CreateSession

Creates an authenticated session for trading. Must be signed with user wallet key.

message CreateSession { bytes user_pubkey = 1; // 32-byte user public key bytes session_pubkey = 2; // 32-byte session public key int64 expiry_timestamp = 3; // Session expiration (Unix seconds) }

PlaceOrder

Places a new order. Must be signed with session key.

message PlaceOrder { uint64 session_id = 1; uint32 market_id = 2; Side side = 3; // ASK = 0, BID = 1 FillMode fill_mode = 4; // LIMIT = 0, POST_ONLY = 1, IMMEDIATE_OR_CANCEL = 2, FILL_OR_KILL = 3 uint64 price = 5; // Price * 10^priceDecimals uint64 size = 6; // Size * 10^sizeDecimals }

CancelOrder

Cancels an existing order. Must be signed with session key.

message CancelOrder { uint64 session_id = 1; uint64 order_id = 2; }

Signing

User Signing (for CreateSession)

Sign the hex-encoded message bytes:

import binascii def user_sign(key, msg: bytes) -> bytes: """Sign using user wallet key (hex-encoded).""" payload = binascii.hexlify(msg) return key.sign(payload)

Session Signing (for PlaceOrder, CancelOrder)

Sign the raw message bytes:

def session_sign(key, msg: bytes) -> bytes: """Sign using session key (raw bytes).""" return key.sign(msg)

Example: Python

Complete example for creating a session and placing an order:

import requests import binascii from google.protobuf.internal import encoder, decoder from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey import schema_pb2 # Generated from schema.proto API_URL = "https://zo-devnet.n1.xyz" def get_varint_bytes(value): return encoder._VarintBytes(value) def read_varint(buffer, offset=0): return decoder._DecodeVarint32(buffer, offset) def execute_action(action, signing_key, sign_func): """Serialize, sign, and send an action.""" payload = action.SerializeToString() length_prefix = get_varint_bytes(len(payload)) message = length_prefix + payload signature = sign_func(signing_key, message) resp = requests.post( f"{API_URL}/action", data=message + signature, headers={"Content-Type": "application/octet-stream"} ) resp.raise_for_status() # Parse receipt msg_len, pos = read_varint(resp.content, 0) receipt = schema_pb2.Receipt() receipt.ParseFromString(resp.content[pos:pos + msg_len]) return receipt # Create session def create_session(user_key, session_key, server_time): action = schema_pb2.Action() action.current_timestamp = server_time action.nonce = 0 action.create_session.user_pubkey = user_key.public_key().public_bytes_raw() action.create_session.session_pubkey = session_key.public_key().public_bytes_raw() action.create_session.expiry_timestamp = server_time + 3600 def user_sign(key, msg): return key.sign(binascii.hexlify(msg)) receipt = execute_action(action, user_key, user_sign) return receipt.create_session_result.session_id # Place order def place_order(session_key, session_id, market_id, side, price, size): action = schema_pb2.Action() action.current_timestamp = int(requests.get(f"{API_URL}/timestamp").json()) action.place_order.session_id = session_id action.place_order.market_id = market_id action.place_order.side = side action.place_order.fill_mode = schema_pb2.FillMode.LIMIT action.place_order.price = price action.place_order.size = size receipt = execute_action(action, session_key, lambda k, m: k.sign(m)) return receipt

Response

Returns a protobuf Receipt message:

message Receipt { uint64 action_id = 1; oneof kind { Error err = 32; CreateSessionResult create_session_result = 33; PlaceOrderResult place_order_result = 34; CancelOrderResult cancel_order_result = 35; // ... other results } }

Error Handling

Check the err field for error codes:

if receipt.HasField("err"): error_name = schema_pb2.Error.Name(receipt.err) print(f"Action failed: {error_name}")

Common errors:

  • INSUFFICIENT_FUNDS - Not enough balance
  • INVALID_SIGNATURE - Signature verification failed
  • SESSION_EXPIRED - Session has expired
  • ORDER_NOT_FOUND - Order doesn’t exist (for cancel)
Last updated on