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
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
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
BUY or SELL.LIMIT or MARKET.Amount to spend (buy) or receive (sell). Must be greater than 0.
USD (default) or NGN.Limit price per share (0.01–0.99). Required for
LIMIT orders.GTC, GTD, FAK, or FOK. Defaults to GTC for limit, FAK for market.If
true, the order is rejected instead of crossing the spread. Limit orders only.Maximum acceptable slippage for market orders (0.00–1.00).
ISO 8601 expiration timestamp. Required for
GTD orders.Self-trade prevention mode:
SKIP (default), CANCEL_OLDEST, CANCEL_NEWEST, or CANCEL_BOTH. See Place order for full semantics.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
Always
CLOB for batch endpoints today.Per-order outcomes, in the same order as the request.
Show Result fields
Show Result fields
Position of this item in the request
orders array (zero-based).Echoed from the request, if provided.
true if the order was accepted upstream, false if it failed.The placed CLOB order. Present when
success is true. See the CLOB order fields on Place order for the full schema.{
"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