Skip to content

L2 Methods

L2 methods sign every request with HMAC-SHA256 using the API credentials you obtained through L1 methods (see L1 Methods).

L2 methods need a fully authenticated client — signer, credentials, and signature type all in place.

use std::str::FromStr;
use openfish_client_sdk::POLYGON;
use openfish_client_sdk::auth::{LocalSigner, Signer};
use openfish_client_sdk::clob::{Client, Config};
let private_key = std::env::var("OPENFISH_PRIVATE_KEY")?;
let signer = LocalSigner::from_str(&private_key)?
.with_chain_id(Some(POLYGON));
let client = Client::new("https://api.openfish.fun", Config::default())?
.authentication_builder(&signer)
.authenticate()
.await?;
// Client is now ready for L2 methods

Send a single signed order to the CLOB.

use openfish_client_sdk::clob::types::Side;
use openfish_client_sdk::types::dec;
let order = client
.limit_order()
.token_id("TOKEN_ID".parse()?)
.price(dec!(0.50))
.size(dec!(10))
.side(Side::Buy)
.build()
.await?;
let signed = client.sign(&signer, order).await?;
let response = client.post_order(signed).await?;

Response fields:

FieldTypeDescription
order_idstringUUID of the placed order
statusstringlive, matched, delayed, or CANCELED
successbooleanWhether the order was accepted
error_msgstringError description if unsuccessful
trade_idsstring[]IDs of trades generated by immediate fills

Send up to 15 signed orders in a single batch.

let signed_orders = vec![signed_bid, signed_ask];
let responses = client.post_orders(signed_orders).await?;

Cancel a single order.

let resp = client.cancel_order("ORDER_ID").await?;
println!("Canceled: {:?}", resp.canceled);

Cancel multiple orders at once.

let resp = client.cancel_orders(&["ORDER_ID_1", "ORDER_ID_2"]).await?;

Cancel every open order across all markets.

let resp = client.cancel_all_orders().await?;

Cancel orders scoped to a specific market or token.

use openfish_client_sdk::clob::types::request::CancelMarketOrderRequest;
let request = CancelMarketOrderRequest::builder()
.market("CONDITION_ID".parse()?)
.build();
let resp = client.cancel_market_orders(&request).await?;

Fetch a single order by ID.

let order = client.order("ORDER_ID").await?;
println!("{}: {} {} at {}", order.id, order.side, order.original_size, order.price);

List open orders with optional filters and cursor-based pagination.

use openfish_client_sdk::clob::types::request::OrdersRequest;
// All open orders
let page = client.orders(&OrdersRequest::default(), None).await?;
println!("{} orders", page.data.len());
// Filtered by market
let request = OrdersRequest::builder()
.market("CONDITION_ID".parse()?)
.build();
let page = client.orders(&request, None).await?;
// Next page using cursor
let next_page = client.orders(&request, Some(page.next_cursor)).await?;

Retrieve your trade history with optional filters.

use openfish_client_sdk::clob::types::request::TradesRequest;
// All trades
let page = client.trades(&TradesRequest::default(), None).await?;
for trade in &page.data {
println!("{}: {} {} at {} ({})",
trade.id, trade.side, trade.size, trade.price, trade.status);
}
// Filtered by market
let request = TradesRequest::builder()
.market("CONDITION_ID".parse()?)
.build();
let market_trades = client.trades(&request, None).await?;

Trade filter parameters:

FieldDescription
idFilter by trade ID
maker_addressFilter by maker address
marketFilter by condition ID
asset_idFilter by token ID
beforeTrades before this cursor
afterTrades after this cursor

Inspect your balance and allowance for USDC or conditional tokens.

use openfish_client_sdk::clob::types::request::BalanceAllowanceRequest;
// USDC balance
let ba = client.balance_allowance(&BalanceAllowanceRequest {
asset_type: "COLLATERAL".to_string(),
token_id: None,
}).await?;
println!("USDC balance: {}, allowance: {}", ba.balance, ba.allowance);
// Conditional token balance
let ba = client.balance_allowance(&BalanceAllowanceRequest {
asset_type: "CONDITIONAL".to_string(),
token_id: Some("TOKEN_ID".to_string()),
}).await?;

Force a refresh of the cached balance and allowance.

client.update_balance_allowance(&UpdateBalanceAllowanceRequest {
asset_type: "COLLATERAL".to_string(),
token_id: None,
}).await?;

Look up your rewards earnings.

use openfish_client_sdk::clob::types::request::UserRewardsEarningRequest;
let request = UserRewardsEarningRequest::builder().build();
let earnings = client.rewards_earning(&request).await?;

List all API keys tied to your account.

let keys = client.api_keys().await?;
println!("{} API keys", keys.api_keys.len());

Revoke the currently authenticated API key.

client.delete_api_key().await?;

Fetch event notifications. Records are automatically purged after 48 hours.

let notifs = client.notifications().await?;
for n in &notifs {
println!("Type {}: {:?}", n.notification_type, n.payload);
}

Notification types:

TypeDescription
1Order cancelled
2Order filled
4Market resolved

Dismiss specific notifications.

client.drop_notifications(&["NOTIFICATION_ID"]).await?;

The heartbeat endpoint keeps your session alive. If no valid heartbeat arrives within 10 seconds, all open orders are cancelled.

With the heartbeats feature enabled, the SDK handles heartbeats automatically in the background:

// Heartbeats start automatically on authenticate()
let client = Client::new("https://api.openfish.fun", Config::default())?
.authentication_builder(&signer)
.authenticate()
.await?;
// Heartbeats are running in the background

To send manually:

let resp = client.post_heartbeat(None).await?; // None for first call
let resp = client.post_heartbeat(Some(resp.heartbeat_id)).await?;

  • L1 Methods — Derive API credentials -> l1
  • Public Methods — Read market data without auth -> public
  • Builder Methods — Attributed order placement -> builder