Batch place orders
curl --request POST \
--url https://relay.bayse.markets/v1/pm/orders/batch \
--header 'Content-Type: application/json' \
--data '
{
"orders": [
{
"outcomeId": "<string>",
"side": "<string>",
"type": "<string>",
"amount": 123,
"currency": "<string>",
"price": 123,
"timeInForce": "<string>",
"postOnly": true,
"maxSlippage": 123,
"expiresAt": "<string>",
"stpMode": "<string>",
"clientOrderId": "<string>"
}
]
}
'import requests
url = "https://relay.bayse.markets/v1/pm/orders/batch"
payload = { "orders": [
{
"outcomeId": "<string>",
"side": "<string>",
"type": "<string>",
"amount": 123,
"currency": "<string>",
"price": 123,
"timeInForce": "<string>",
"postOnly": True,
"maxSlippage": 123,
"expiresAt": "<string>",
"stpMode": "<string>",
"clientOrderId": "<string>"
}
] }
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
orders: [
{
outcomeId: '<string>',
side: '<string>',
type: '<string>',
amount: 123,
currency: '<string>',
price: 123,
timeInForce: '<string>',
postOnly: true,
maxSlippage: 123,
expiresAt: '<string>',
stpMode: '<string>',
clientOrderId: '<string>'
}
]
})
};
fetch('https://relay.bayse.markets/v1/pm/orders/batch', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://relay.bayse.markets/v1/pm/orders/batch",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'orders' => [
[
'outcomeId' => '<string>',
'side' => '<string>',
'type' => '<string>',
'amount' => 123,
'currency' => '<string>',
'price' => 123,
'timeInForce' => '<string>',
'postOnly' => true,
'maxSlippage' => 123,
'expiresAt' => '<string>',
'stpMode' => '<string>',
'clientOrderId' => '<string>'
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://relay.bayse.markets/v1/pm/orders/batch"
payload := strings.NewReader("{\n \"orders\": [\n {\n \"outcomeId\": \"<string>\",\n \"side\": \"<string>\",\n \"type\": \"<string>\",\n \"amount\": 123,\n \"currency\": \"<string>\",\n \"price\": 123,\n \"timeInForce\": \"<string>\",\n \"postOnly\": true,\n \"maxSlippage\": 123,\n \"expiresAt\": \"<string>\",\n \"stpMode\": \"<string>\",\n \"clientOrderId\": \"<string>\"\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://relay.bayse.markets/v1/pm/orders/batch")
.header("Content-Type", "application/json")
.body("{\n \"orders\": [\n {\n \"outcomeId\": \"<string>\",\n \"side\": \"<string>\",\n \"type\": \"<string>\",\n \"amount\": 123,\n \"currency\": \"<string>\",\n \"price\": 123,\n \"timeInForce\": \"<string>\",\n \"postOnly\": true,\n \"maxSlippage\": 123,\n \"expiresAt\": \"<string>\",\n \"stpMode\": \"<string>\",\n \"clientOrderId\": \"<string>\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://relay.bayse.markets/v1/pm/orders/batch")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"orders\": [\n {\n \"outcomeId\": \"<string>\",\n \"side\": \"<string>\",\n \"type\": \"<string>\",\n \"amount\": 123,\n \"currency\": \"<string>\",\n \"price\": 123,\n \"timeInForce\": \"<string>\",\n \"postOnly\": true,\n \"maxSlippage\": 123,\n \"expiresAt\": \"<string>\",\n \"stpMode\": \"<string>\",\n \"clientOrderId\": \"<string>\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"engine": "CLOB",
"results": [
{
"index": 0,
"clientOrderId": "mm-001",
"success": true,
"order": {
"id": "f6a7b8c9-d0e1-2345-fabc-678901234567",
"marketId": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"userId": "9a8b7c6d-5e4f-3210-abcd-ef1234567890",
"outcome": "YES",
"side": "BUY",
"orderType": "LIMIT",
"type": "GTC",
"status": "open",
"amount": 100,
"price": 0.70,
"size": 100,
"filledSize": 0,
"remainingSize": 100,
"avgFillPrice": 0,
"fee": 0,
"postOnly": false,
"stpMode": "SKIP",
"quantity": 0,
"createdAt": "2026-05-04T12:00:00Z",
"updatedAt": "2026-05-04T12:00:00Z"
}
},
{
"index": 1,
"clientOrderId": "mm-002",
"success": false,
"error": {
"code": "INSUFFICIENT_BALANCE",
"message": "Insufficient USD balance for this order"
}
}
],
"summary": { "total": 2, "succeeded": 1, "failed": 1 }
}
{
"error": "bad_request",
"message": "invalid request body: orders[] required (1..20 entries with outcomeId, side, type, amount)",
"statusCode": 400
}
{
"error": "conflict",
"message": "A request with this Idempotency-Key is already in flight; retry shortly.",
"statusCode": 409
}
{
"error": "unprocessable_entity",
"message": "Idempotency-Key reused with a different request body",
"statusCode": 422
}
{
"message": "Rate limit exceeded for batch payload size. Please reduce the batch or try again later.",
"retryAfter": 2
}
Trading
Batch place orders
Place up to 20 CLOB orders across one or more markets in a single round-trip
POST
/
v1
/
pm
/
orders
/
batch
Batch place orders
curl --request POST \
--url https://relay.bayse.markets/v1/pm/orders/batch \
--header 'Content-Type: application/json' \
--data '
{
"orders": [
{
"outcomeId": "<string>",
"side": "<string>",
"type": "<string>",
"amount": 123,
"currency": "<string>",
"price": 123,
"timeInForce": "<string>",
"postOnly": true,
"maxSlippage": 123,
"expiresAt": "<string>",
"stpMode": "<string>",
"clientOrderId": "<string>"
}
]
}
'import requests
url = "https://relay.bayse.markets/v1/pm/orders/batch"
payload = { "orders": [
{
"outcomeId": "<string>",
"side": "<string>",
"type": "<string>",
"amount": 123,
"currency": "<string>",
"price": 123,
"timeInForce": "<string>",
"postOnly": True,
"maxSlippage": 123,
"expiresAt": "<string>",
"stpMode": "<string>",
"clientOrderId": "<string>"
}
] }
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
orders: [
{
outcomeId: '<string>',
side: '<string>',
type: '<string>',
amount: 123,
currency: '<string>',
price: 123,
timeInForce: '<string>',
postOnly: true,
maxSlippage: 123,
expiresAt: '<string>',
stpMode: '<string>',
clientOrderId: '<string>'
}
]
})
};
fetch('https://relay.bayse.markets/v1/pm/orders/batch', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://relay.bayse.markets/v1/pm/orders/batch",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'orders' => [
[
'outcomeId' => '<string>',
'side' => '<string>',
'type' => '<string>',
'amount' => 123,
'currency' => '<string>',
'price' => 123,
'timeInForce' => '<string>',
'postOnly' => true,
'maxSlippage' => 123,
'expiresAt' => '<string>',
'stpMode' => '<string>',
'clientOrderId' => '<string>'
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://relay.bayse.markets/v1/pm/orders/batch"
payload := strings.NewReader("{\n \"orders\": [\n {\n \"outcomeId\": \"<string>\",\n \"side\": \"<string>\",\n \"type\": \"<string>\",\n \"amount\": 123,\n \"currency\": \"<string>\",\n \"price\": 123,\n \"timeInForce\": \"<string>\",\n \"postOnly\": true,\n \"maxSlippage\": 123,\n \"expiresAt\": \"<string>\",\n \"stpMode\": \"<string>\",\n \"clientOrderId\": \"<string>\"\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://relay.bayse.markets/v1/pm/orders/batch")
.header("Content-Type", "application/json")
.body("{\n \"orders\": [\n {\n \"outcomeId\": \"<string>\",\n \"side\": \"<string>\",\n \"type\": \"<string>\",\n \"amount\": 123,\n \"currency\": \"<string>\",\n \"price\": 123,\n \"timeInForce\": \"<string>\",\n \"postOnly\": true,\n \"maxSlippage\": 123,\n \"expiresAt\": \"<string>\",\n \"stpMode\": \"<string>\",\n \"clientOrderId\": \"<string>\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://relay.bayse.markets/v1/pm/orders/batch")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"orders\": [\n {\n \"outcomeId\": \"<string>\",\n \"side\": \"<string>\",\n \"type\": \"<string>\",\n \"amount\": 123,\n \"currency\": \"<string>\",\n \"price\": 123,\n \"timeInForce\": \"<string>\",\n \"postOnly\": true,\n \"maxSlippage\": 123,\n \"expiresAt\": \"<string>\",\n \"stpMode\": \"<string>\",\n \"clientOrderId\": \"<string>\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"engine": "CLOB",
"results": [
{
"index": 0,
"clientOrderId": "mm-001",
"success": true,
"order": {
"id": "f6a7b8c9-d0e1-2345-fabc-678901234567",
"marketId": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"userId": "9a8b7c6d-5e4f-3210-abcd-ef1234567890",
"outcome": "YES",
"side": "BUY",
"orderType": "LIMIT",
"type": "GTC",
"status": "open",
"amount": 100,
"price": 0.70,
"size": 100,
"filledSize": 0,
"remainingSize": 100,
"avgFillPrice": 0,
"fee": 0,
"postOnly": false,
"stpMode": "SKIP",
"quantity": 0,
"createdAt": "2026-05-04T12:00:00Z",
"updatedAt": "2026-05-04T12:00:00Z"
}
},
{
"index": 1,
"clientOrderId": "mm-002",
"success": false,
"error": {
"code": "INSUFFICIENT_BALANCE",
"message": "Insufficient USD balance for this order"
}
}
],
"summary": { "total": 2, "succeeded": 1, "failed": 1 }
}
{
"error": "bad_request",
"message": "invalid request body: orders[] required (1..20 entries with outcomeId, side, type, amount)",
"statusCode": 400
}
{
"error": "conflict",
"message": "A request with this Idempotency-Key is already in flight; retry shortly.",
"statusCode": 409
}
{
"error": "unprocessable_entity",
"message": "Idempotency-Key reused with a different request body",
"statusCode": 422
}
{
"message": "Rate limit exceeded for batch payload size. Please reduce the batch or try again later.",
"retryAfter": 2
}
Submit up to 20 CLOB orders in a single request. Orders may span multiple markets and events — each item carries only
outcomeId, and the server resolves the parent market and event. CLOB-only: AMM markets are rejected per-order with UNSUPPORTED_ENGINE.
See the Batch orders concept page for limits, semantics, and rate-limit behavior.
Authentication
Write authentication required —X-Public-Key, X-Timestamp, and X-Signature headers. See the Authentication guide.
Headers
string
Optional. 1–255 characters of
[A-Za-z0-9_-]. Retries within 24 hours that share the same key, body, and route replay the original response with Idempotent-Replayed: true. A retry with the same key but a different body is rejected with 422. A concurrent retry (sent while the first is still in flight) is rejected with 409 — back off briefly and retry once the first call has finished. Transient responses (5xx, 429, 408) are not cached, so you can recover by retrying.Request body
array
required
1–20 order items. Each item is processed independently — one bad item does not abort the others.
Show Order item fields
Show Order item fields
string
required
BUY or SELL.string
required
LIMIT or MARKET.number
required
Amount to spend (buy) or receive (sell). Must be greater than 0.
string
USD (default) or NGN.number
Limit price per share (0.01–0.99). Required for
LIMIT orders.string
GTC, GTD, FAK, or FOK. Defaults to GTC for limit, FAK for market.boolean
If
true, the order is rejected instead of crossing the spread. Limit orders only.number
Maximum acceptable slippage for market orders (0.00–1.00).
string
ISO 8601 expiration timestamp. Required for
GTD orders.string
Self-trade prevention mode:
SKIP (default), CANCEL_OLDEST, CANCEL_NEWEST, or CANCEL_BOTH. See Place order for full semantics.string
Optional client-supplied identifier. Echoed back in the matching result so you can correlate items with their source ticket without relying on array order.
Example request
PUBLIC_KEY="pk_live_abcdef123456"
SECRET_KEY="sk_live_secret789xyz"
TIMESTAMP=$(date +%s)
METHOD="POST"
URL_PATH="/v1/pm/orders/batch"
BODY='{"orders":[{"outcomeId":"c3d4e5f6-a7b8-9012-cdef-345678901234","side":"BUY","type":"LIMIT","amount":100,"price":0.70,"timeInForce":"GTC","clientOrderId":"mm-001"},{"outcomeId":"d4e5f6a7-b8c9-0123-defa-456789012345","side":"SELL","type":"LIMIT","amount":50,"price":0.32,"timeInForce":"GTC","clientOrderId":"mm-002"}]}'
BODY_HASH=$(printf '%s' "$BODY" | openssl dgst -sha256 -hex 2>/dev/null | sed 's/.*= //')
PAYLOAD="${TIMESTAMP}.${METHOD}.${URL_PATH}.${BODY_HASH}"
SIGNATURE=$(printf '%s' "$PAYLOAD" | openssl dgst -sha256 -hmac "$SECRET_KEY" -binary | base64)
curl -X POST "https://relay.bayse.markets${URL_PATH}" \
-H "X-Public-Key: ${PUBLIC_KEY}" \
-H "X-Timestamp: ${TIMESTAMP}" \
-H "X-Signature: ${SIGNATURE}" \
-H "Idempotency-Key: 9d3f2c0e-7b1a-4e5d-9f80-3a8b1c2d4e5f" \
-H "Content-Type: application/json" \
-d "$BODY"
import crypto from 'crypto';
const publicKey = 'pk_live_abcdef123456';
const secretKey = 'sk_live_secret789xyz';
const timestamp = Math.floor(Date.now() / 1000);
const method = 'POST';
const path = '/v1/pm/orders/batch';
const body = JSON.stringify({
orders: [
{
outcomeId: 'c3d4e5f6-a7b8-9012-cdef-345678901234',
side: 'BUY',
type: 'LIMIT',
amount: 100,
price: 0.70,
timeInForce: 'GTC',
clientOrderId: 'mm-001',
},
{
outcomeId: 'd4e5f6a7-b8c9-0123-defa-456789012345',
side: 'SELL',
type: 'LIMIT',
amount: 50,
price: 0.32,
timeInForce: 'GTC',
clientOrderId: 'mm-002',
},
],
});
const bodyHash = crypto.createHash('sha256').update(body).digest('hex');
const payload = `${timestamp}.${method}.${path}.${bodyHash}`;
const signature = crypto
.createHmac('sha256', secretKey)
.update(payload)
.digest('base64');
const response = await fetch(`https://relay.bayse.markets${path}`, {
method,
headers: {
'X-Public-Key': publicKey,
'X-Timestamp': timestamp.toString(),
'X-Signature': signature,
'Idempotency-Key': crypto.randomUUID(),
'Content-Type': 'application/json',
},
body,
});
const result = await response.json();
import hmac, hashlib, base64, json, time, uuid, requests
public_key = 'pk_live_abcdef123456'
secret_key = 'sk_live_secret789xyz'
timestamp = int(time.time())
method = 'POST'
path = '/v1/pm/orders/batch'
body = json.dumps({
'orders': [
{
'outcomeId': 'c3d4e5f6-a7b8-9012-cdef-345678901234',
'side': 'BUY',
'type': 'LIMIT',
'amount': 100,
'price': 0.70,
'timeInForce': 'GTC',
'clientOrderId': 'mm-001',
},
{
'outcomeId': 'd4e5f6a7-b8c9-0123-defa-456789012345',
'side': 'SELL',
'type': 'LIMIT',
'amount': 50,
'price': 0.32,
'timeInForce': 'GTC',
'clientOrderId': 'mm-002',
},
],
})
body_hash = hashlib.sha256(body.encode()).hexdigest()
payload = f'{timestamp}.{method}.{path}.{body_hash}'
signature = base64.b64encode(
hmac.new(secret_key.encode(), payload.encode(), hashlib.sha256).digest()
).decode()
resp = requests.post(
f'https://relay.bayse.markets{path}',
headers={
'X-Public-Key': public_key,
'X-Timestamp': str(timestamp),
'X-Signature': signature,
'Idempotency-Key': str(uuid.uuid4()),
'Content-Type': 'application/json',
},
data=body,
)
result = resp.json()
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"fmt"
"strconv"
"strings"
"time"
)
timestamp := time.Now().Unix()
method := "POST"
urlPath := "/v1/pm/orders/batch"
body := []byte(`{"orders":[{"outcomeId":"c3d4e5f6-a7b8-9012-cdef-345678901234","side":"BUY","type":"LIMIT","amount":100,"price":0.70,"timeInForce":"GTC","clientOrderId":"mm-001"},{"outcomeId":"d4e5f6a7-b8c9-0123-defa-456789012345","side":"SELL","type":"LIMIT","amount":50,"price":0.32,"timeInForce":"GTC","clientOrderId":"mm-002"}]}`)
bodySum := sha256.Sum256(body)
bodyHash := hex.EncodeToString(bodySum[:])
payload := fmt.Sprintf("%d.%s.%s.%s", timestamp, method, urlPath, bodyHash)
mac := hmac.New(sha256.New, []byte("sk_live_secret789xyz"))
mac.Write([]byte(payload))
signature := base64.StdEncoding.EncodeToString(mac.Sum(nil))
req, _ := http.NewRequest("POST", "https://relay.bayse.markets"+urlPath, strings.NewReader(string(body)))
req.Header.Set("X-Public-Key", "pk_live_abcdef123456")
req.Header.Set("X-Timestamp", strconv.FormatInt(timestamp, 10))
req.Header.Set("X-Signature", signature)
req.Header.Set("Idempotency-Key", "9d3f2c0e-7b1a-4e5d-9f80-3a8b1c2d4e5f")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
Response
string
Always
CLOB for batch endpoints today.array
Per-order outcomes, in the same order as the request.
Show Result fields
Show Result fields
integer
Position of this item in the request
orders array (zero-based).string
Echoed from the request, if provided.
boolean
true if the order was accepted upstream, false if it failed.object
The placed CLOB order. Present when
success is true. See the CLOB order fields on Place order for the full schema.object
{
"engine": "CLOB",
"results": [
{
"index": 0,
"clientOrderId": "mm-001",
"success": true,
"order": {
"id": "f6a7b8c9-d0e1-2345-fabc-678901234567",
"marketId": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"userId": "9a8b7c6d-5e4f-3210-abcd-ef1234567890",
"outcome": "YES",
"side": "BUY",
"orderType": "LIMIT",
"type": "GTC",
"status": "open",
"amount": 100,
"price": 0.70,
"size": 100,
"filledSize": 0,
"remainingSize": 100,
"avgFillPrice": 0,
"fee": 0,
"postOnly": false,
"stpMode": "SKIP",
"quantity": 0,
"createdAt": "2026-05-04T12:00:00Z",
"updatedAt": "2026-05-04T12:00:00Z"
}
},
{
"index": 1,
"clientOrderId": "mm-002",
"success": false,
"error": {
"code": "INSUFFICIENT_BALANCE",
"message": "Insufficient USD balance for this order"
}
}
],
"summary": { "total": 2, "succeeded": 1, "failed": 1 }
}
{
"error": "bad_request",
"message": "invalid request body: orders[] required (1..20 entries with outcomeId, side, type, amount)",
"statusCode": 400
}
{
"error": "conflict",
"message": "A request with this Idempotency-Key is already in flight; retry shortly.",
"statusCode": 409
}
{
"error": "unprocessable_entity",
"message": "Idempotency-Key reused with a different request body",
"statusCode": 422
}
{
"message": "Rate limit exceeded for batch payload size. Please reduce the batch or try again later.",
"retryAfter": 2
}
Batch calls are charged per item against your write rate-limit bucket — a 20-order batch costs 20 tokens. Over-budget batches are rejected with
429 before any orders reach the matching engine. See Rate limits.⌘I