Place orders on Manifest, Solana's orderbook DEX. Returns unsigned transactions for client-side signing.
Base URL: /v1
Create one or more orders on a Manifest market. Returns a base64-encoded VersionedTransaction that you sign and submit to the Solana network. All decimal conversion is handled internally by the API.
import { Keypair, VersionedTransaction, Connection } from "@solana/web3.js";
const MANIFEST_ORDERS_URL = "https://manifest-orders.fly.dev";
const connection = new Connection("https://api.mainnet-beta.solana.com");
const wallet = Keypair.fromSecretKey(/* your key */);
// 1. Build the order transaction
const response = await fetch(${MANIFEST_ORDERS_URL}/v1/orders, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
maker: wallet.publicKey.toBase58(),
baseMint: "So11111111111111111111111111111111111111112",
quoteMint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
orders: [
{
size: "1.1",
price: "150",
side: "sell",
orderType: "limit",
},
],
computeUnitPrice: "auto",
}),
});
const { transaction } = await response.json();
// 2. Deserialize and sign (API already signed with any ephemeral keypairs)
const tx = VersionedTransaction.deserialize(Buffer.from(transaction, "base64"));
tx.sign([wallet]);
// 3. Send
const sig = await connection.sendRawTransaction(tx.serialize());
console.log("Submitted:", sig);
use solana_client::rpc_client::RpcClient;
use solana_sdk::{
signature::{Keypair, Signer},
transaction::VersionedTransaction,
};
use base64::Engine;
use serde::{Deserialize, Serialize};
#[derive(Serialize)]
struct Order {
size: String,
price: String,
side: String,
#[serde(rename = "orderType")]
order_type: String,
}
#[derive(Serialize)]
struct CreateOrdersRequest {
maker: String,
#[serde(rename = "baseMint")]
base_mint: String,
#[serde(rename = "quoteMint")]
quote_mint: String,
orders: Vec<Order>,
#[serde(rename = "computeUnitPrice")]
compute_unit_price: String,
}
#[derive(Deserialize)]
struct CreateOrdersResponse {
transaction: String,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let rpc = RpcClient::new("https://api.mainnet-beta.solana.com");
let wallet = Keypair::new(); // load your keypair
// 1. Build the order transaction
let client = reqwest::blocking::Client::new();
let resp: CreateOrdersResponse = client
.post("https://manifest-orders.fly.dev/v1/orders")
.json(&CreateOrdersRequest {
maker: wallet.pubkey().to_string(),
base_mint: "So11111111111111111111111111111111111111112".into(),
quote_mint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v".into(),
orders: vec![Order {
size: "1.1".into(),
price: "150".into(),
side: "sell".into(),
order_type: "limit".into(),
}],
compute_unit_price: "auto".into(),
})
.send()?
.json()?;
// 2. Deserialize and sign (API already signed with any ephemeral keypairs)
let tx_bytes = base64::engine::general_purpose::STANDARD
.decode(&resp.transaction)?;
let mut tx: VersionedTransaction = bincode::deserialize(&tx_bytes)?;
tx.try_sign(&[&wallet], *tx.message.recent_blockhash())?;
// 3. Send
let sig = rpc.send_transaction(&tx)?;
println!("Submitted: {sig}");
Ok(())
}
{
"maker": "YourWalletPubkey...",
"baseMint": "So11111111111111111111111111111111111111112",
"quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"orders": [
{
"size": "1.1",
"price": "150",
"side": "sell",
"orderType": "limit"
}
],
"computeUnitPrice": "auto"
}
| Parameter | Type | Required | Description |
|---|---|---|---|
maker | string | Yes | Base58 public key of the wallet placing the order(s). |
payer | string | No | Base58 public key of the wallet paying for the transaction. Defaults to maker. |
baseMint | string | Yes | Base token mint address (e.g. SOL). |
quoteMint | string | Yes | Quote token mint address (e.g. USDC). |
orders | array | Yes | Array of 1–20 order objects. |
computeUnitPrice | "auto" or number | No | "auto" targets 1000 lamports for transaction priority. A number sets the exact microLamports per CU. Omit to skip. |
| Field | Type | Required | Description |
|---|---|---|---|
size | string | Yes | Amount of base token in human-readable units (e.g. "1.1" for 1.1 SOL). The API handles decimal conversion internally. |
price | string | Yes | Price in quote tokens per base token (e.g. "150" for 150 USDC/SOL). The API handles decimal conversion internally. |
side | string | Yes | "buy" or "sell". |
orderType | string | Yes | One of: limit, reverse, timeInForce, global. |
clientOrderId | number | No | Client-specified order ID. Defaults to 0. |
spreadBps | number | Reverse only | Spread in basis points. Required when orderType is reverse. If < 1, uses ReverseTight encoding (0.0001 bps precision). If >= 1, uses Reverse encoding (0.1 bps precision). |
expirySlots | number | TIF only | Number of Solana slots until the order expires. Required when orderType is timeInForce. The API fetches the current slot and sets lastValidSlot = currentSlot + expirySlots. |
limit — Standard limit order. Stays on the book until filled or cancelled.reverse — Reverse order that automatically re-places after being filled at a spread from the fill price. Requires spreadBps.timeInForce — Limit order that expires after a given number of slots. Requires expirySlots.global — Global order that deposits into the Manifest global account for cross-market capital efficiency. Cannot be used when creating a new market.{
"transaction": "AQAAAAAAAAAA...",
"requestId": "550e8400-e29b-41d4-a716-446655440000"
}
| Field | Type | Description |
|---|---|---|
transaction | string | Base64-encoded VersionedTransaction. If the API created new accounts (market, wrapper), the transaction is already partially signed with those ephemeral keypairs. Just add your wallet signature and submit. Uses Address Lookup Tables when available. |
requestId | string | UUID for tracking this request. |
{
"error": "invalid request",
"cause": "order[0]: size and price are required",
"code": 400
}
| Field | Type | Description |
|---|---|---|
error | string | Short error category. |
cause | string | Detailed error message. |
code | number | HTTP status code. |
maker, baseMint, quoteMint are required and must be valid base58 public keys.orders must contain 1–20 orders.size, price, side, and orderType.side must be "buy" or "sell".reverse orders require spreadBps >= 0.timeInForce orders require expirySlots > 0.global orders cannot be placed on a market that doesn't exist yet.spreadBps must be representable at the encoding precision (0.1 bps for Reverse, 0.0001 bps for ReverseTight).# Sell 1.1 SOL at 150 USDC/SOL
curl -X POST https://manifest-orders.fly.dev/v1/orders \
-H "Content-Type: application/json" \
-d '{
"maker": "YourWalletPubkey...",
"baseMint": "So11111111111111111111111111111111111111112",
"quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"orders": [{
"size": "1.1",
"price": "150",
"side": "sell",
"orderType": "limit"
}],
"computeUnitPrice": "auto"
}'
# Two sell orders at different prices
curl -X POST https://manifest-orders.fly.dev/v1/orders \
-H "Content-Type: application/json" \
-d '{
"maker": "YourWalletPubkey...",
"baseMint": "So11111111111111111111111111111111111111112",
"quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"orders": [
{ "size": "0.5", "price": "150", "side": "sell", "orderType": "limit", "clientOrderId": 1 },
{ "size": "0.5", "price": "160", "side": "sell", "orderType": "limit", "clientOrderId": 2 }
],
"computeUnitPrice": "auto"
}'
# Reverse order with 10 bps spread
curl -X POST https://manifest-orders.fly.dev/v1/orders \
-H "Content-Type: application/json" \
-d '{
"maker": "YourWalletPubkey...",
"baseMint": "So11111111111111111111111111111111111111112",
"quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"orders": [{
"size": "1.1",
"price": "150",
"side": "sell",
"orderType": "reverse",
"spreadBps": 10
}],
"computeUnitPrice": "auto"
}'
# Expires in ~1 minute (150 slots)
curl -X POST https://manifest-orders.fly.dev/v1/orders \
-H "Content-Type: application/json" \
-d '{
"maker": "YourWalletPubkey...",
"baseMint": "So11111111111111111111111111111111111111112",
"quoteMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"orders": [{
"size": "1.1",
"price": "150",
"side": "sell",
"orderType": "timeInForce",
"expirySlots": 150
}],
"computeUnitPrice": "auto"
}'