curl --request POST \
--url https://core.api.dev.predictstreet.sde.adifoundation.ai/api/orders/place-batch \
--header 'Content-Type: application/json' \
--header 'X-Api-Key: <api-key>' \
--data '
{
"orders": [
{
"marketId": "NC26-BIN-83479265",
"price": "0.42",
"quantity": "2",
"nonce": "<string>",
"expiry": 0,
"maker": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb3",
"signature": "<string>",
"clientOrderId": "<string>",
"type": "limit",
"timeInForce": "gtc",
"postOnly": false,
"feeRateBps": 1
}
]
}
'import requests
url = "https://core.api.dev.predictstreet.sde.adifoundation.ai/api/orders/place-batch"
payload = { "orders": [
{
"marketId": "NC26-BIN-83479265",
"price": "0.42",
"quantity": "2",
"nonce": "<string>",
"expiry": 0,
"maker": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb3",
"signature": "<string>",
"clientOrderId": "<string>",
"type": "limit",
"timeInForce": "gtc",
"postOnly": False,
"feeRateBps": 1
}
] }
headers = {
"X-Api-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-Api-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
orders: [
{
marketId: 'NC26-BIN-83479265',
price: '0.42',
quantity: '2',
nonce: '<string>',
expiry: 0,
maker: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb3',
signature: '<string>',
clientOrderId: '<string>',
type: 'limit',
timeInForce: 'gtc',
postOnly: false,
feeRateBps: 1
}
]
})
};
fetch('https://core.api.dev.predictstreet.sde.adifoundation.ai/api/orders/place-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://core.api.dev.predictstreet.sde.adifoundation.ai/api/orders/place-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' => [
[
'marketId' => 'NC26-BIN-83479265',
'price' => '0.42',
'quantity' => '2',
'nonce' => '<string>',
'expiry' => 0,
'maker' => '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb3',
'signature' => '<string>',
'clientOrderId' => '<string>',
'type' => 'limit',
'timeInForce' => 'gtc',
'postOnly' => false,
'feeRateBps' => 1
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-Api-Key: <api-key>"
],
]);
$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://core.api.dev.predictstreet.sde.adifoundation.ai/api/orders/place-batch"
payload := strings.NewReader("{\n \"orders\": [\n {\n \"marketId\": \"NC26-BIN-83479265\",\n \"price\": \"0.42\",\n \"quantity\": \"2\",\n \"nonce\": \"<string>\",\n \"expiry\": 0,\n \"maker\": \"0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb3\",\n \"signature\": \"<string>\",\n \"clientOrderId\": \"<string>\",\n \"type\": \"limit\",\n \"timeInForce\": \"gtc\",\n \"postOnly\": false,\n \"feeRateBps\": 1\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Api-Key", "<api-key>")
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://core.api.dev.predictstreet.sde.adifoundation.ai/api/orders/place-batch")
.header("X-Api-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"orders\": [\n {\n \"marketId\": \"NC26-BIN-83479265\",\n \"price\": \"0.42\",\n \"quantity\": \"2\",\n \"nonce\": \"<string>\",\n \"expiry\": 0,\n \"maker\": \"0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb3\",\n \"signature\": \"<string>\",\n \"clientOrderId\": \"<string>\",\n \"type\": \"limit\",\n \"timeInForce\": \"gtc\",\n \"postOnly\": false,\n \"feeRateBps\": 1\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://core.api.dev.predictstreet.sde.adifoundation.ai/api/orders/place-batch")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Api-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"orders\": [\n {\n \"marketId\": \"NC26-BIN-83479265\",\n \"price\": \"0.42\",\n \"quantity\": \"2\",\n \"nonce\": \"<string>\",\n \"expiry\": 0,\n \"maker\": \"0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb3\",\n \"signature\": \"<string>\",\n \"clientOrderId\": \"<string>\",\n \"type\": \"limit\",\n \"timeInForce\": \"gtc\",\n \"postOnly\": false,\n \"feeRateBps\": 1\n }\n ]\n}"
response = http.request(request)
puts response.read_body[
{
"orderId": "<string>",
"status": "PENDING",
"filledQty": "<string>",
"remainingQty": "<string>",
"trades": [
{
"id": "<string>",
"orderId": "<string>",
"userWallet": "<string>",
"marketId": "<string>",
"price": "<string>",
"quantity": "<string>",
"fee": "<string>",
"side": "buy",
"createdAt": "<string>"
}
],
"success": true,
"code": "<string>",
"message": "<string>",
"traceId": "<string>",
"details": {},
"clientOrderId": "<string>"
}
]{
"status": 400,
"error": {
"code": "bad_request",
"message": "<string>",
"trace_id": "<string>",
"retryAfterSec": 123,
"retryable": true,
"details": {}
}
}{
"status": 404,
"error": {
"code": "<string>",
"message": "<string>",
"trace_id": "<string>",
"retryAfterSec": 123,
"retryable": true,
"details": {}
}
}{
"status": 400,
"error": {
"code": "bad_request",
"message": "<string>",
"trace_id": "<string>",
"retryAfterSec": 123,
"retryable": true,
"details": {}
}
}{
"status": 404,
"error": {
"code": "<string>",
"message": "<string>",
"trace_id": "<string>",
"retryAfterSec": 123,
"retryable": true,
"details": {}
}
}{
"status": 400,
"error": {
"code": "bad_request",
"message": "<string>",
"trace_id": "<string>",
"retryAfterSec": 123,
"retryable": true,
"details": {}
}
}Place a batch of signed orders (max 10)
Submit up to 10 EIP-712-signed orders in one request. Orders are processed sequentially in array order with independent per-order outcomes — one rejected order never aborts the rest, and there is no all-or-nothing atomicity. The exception is request validation: a malformed entry, or an array of 0 or more than 10 entries, fails the whole request with 400 invalid_request and no entry is processed. Each entry is validated, balance-locked, and matched exactly as a single POST /api/orders/place. For users trading through a partner sign-in, the partner trade cap is charged against the running total of the entries accepted earlier in the batch, so a batch can never admit more exposure than the same orders sent one at a time. Rate limited at 8 req/sec per wallet (token bucket, up to 80 orders/sec). KYC deposit-tier gating applies, same as single place. Business rejects (bad signature, insufficient funds, …) come back as per-entry REJECTED results with HTTP 201; infrastructure failures (matcher / verifier / DB unavailable) fail the whole request with a 5xx. Entries processed before a 5xx may already be placed. Set your own clientOrderId on every entry: resending the same batch with the same keys returns the original result for entries already placed and processes the rest normally. Keys the server generates for entries sent without one are not returned; resending identical signed orders still cannot place them twice, but an already-placed entry then comes back as order_already_placed instead of its original result.
curl --request POST \
--url https://core.api.dev.predictstreet.sde.adifoundation.ai/api/orders/place-batch \
--header 'Content-Type: application/json' \
--header 'X-Api-Key: <api-key>' \
--data '
{
"orders": [
{
"marketId": "NC26-BIN-83479265",
"price": "0.42",
"quantity": "2",
"nonce": "<string>",
"expiry": 0,
"maker": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb3",
"signature": "<string>",
"clientOrderId": "<string>",
"type": "limit",
"timeInForce": "gtc",
"postOnly": false,
"feeRateBps": 1
}
]
}
'import requests
url = "https://core.api.dev.predictstreet.sde.adifoundation.ai/api/orders/place-batch"
payload = { "orders": [
{
"marketId": "NC26-BIN-83479265",
"price": "0.42",
"quantity": "2",
"nonce": "<string>",
"expiry": 0,
"maker": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb3",
"signature": "<string>",
"clientOrderId": "<string>",
"type": "limit",
"timeInForce": "gtc",
"postOnly": False,
"feeRateBps": 1
}
] }
headers = {
"X-Api-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-Api-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
orders: [
{
marketId: 'NC26-BIN-83479265',
price: '0.42',
quantity: '2',
nonce: '<string>',
expiry: 0,
maker: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb3',
signature: '<string>',
clientOrderId: '<string>',
type: 'limit',
timeInForce: 'gtc',
postOnly: false,
feeRateBps: 1
}
]
})
};
fetch('https://core.api.dev.predictstreet.sde.adifoundation.ai/api/orders/place-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://core.api.dev.predictstreet.sde.adifoundation.ai/api/orders/place-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' => [
[
'marketId' => 'NC26-BIN-83479265',
'price' => '0.42',
'quantity' => '2',
'nonce' => '<string>',
'expiry' => 0,
'maker' => '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb3',
'signature' => '<string>',
'clientOrderId' => '<string>',
'type' => 'limit',
'timeInForce' => 'gtc',
'postOnly' => false,
'feeRateBps' => 1
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-Api-Key: <api-key>"
],
]);
$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://core.api.dev.predictstreet.sde.adifoundation.ai/api/orders/place-batch"
payload := strings.NewReader("{\n \"orders\": [\n {\n \"marketId\": \"NC26-BIN-83479265\",\n \"price\": \"0.42\",\n \"quantity\": \"2\",\n \"nonce\": \"<string>\",\n \"expiry\": 0,\n \"maker\": \"0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb3\",\n \"signature\": \"<string>\",\n \"clientOrderId\": \"<string>\",\n \"type\": \"limit\",\n \"timeInForce\": \"gtc\",\n \"postOnly\": false,\n \"feeRateBps\": 1\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Api-Key", "<api-key>")
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://core.api.dev.predictstreet.sde.adifoundation.ai/api/orders/place-batch")
.header("X-Api-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"orders\": [\n {\n \"marketId\": \"NC26-BIN-83479265\",\n \"price\": \"0.42\",\n \"quantity\": \"2\",\n \"nonce\": \"<string>\",\n \"expiry\": 0,\n \"maker\": \"0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb3\",\n \"signature\": \"<string>\",\n \"clientOrderId\": \"<string>\",\n \"type\": \"limit\",\n \"timeInForce\": \"gtc\",\n \"postOnly\": false,\n \"feeRateBps\": 1\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://core.api.dev.predictstreet.sde.adifoundation.ai/api/orders/place-batch")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Api-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"orders\": [\n {\n \"marketId\": \"NC26-BIN-83479265\",\n \"price\": \"0.42\",\n \"quantity\": \"2\",\n \"nonce\": \"<string>\",\n \"expiry\": 0,\n \"maker\": \"0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb3\",\n \"signature\": \"<string>\",\n \"clientOrderId\": \"<string>\",\n \"type\": \"limit\",\n \"timeInForce\": \"gtc\",\n \"postOnly\": false,\n \"feeRateBps\": 1\n }\n ]\n}"
response = http.request(request)
puts response.read_body[
{
"orderId": "<string>",
"status": "PENDING",
"filledQty": "<string>",
"remainingQty": "<string>",
"trades": [
{
"id": "<string>",
"orderId": "<string>",
"userWallet": "<string>",
"marketId": "<string>",
"price": "<string>",
"quantity": "<string>",
"fee": "<string>",
"side": "buy",
"createdAt": "<string>"
}
],
"success": true,
"code": "<string>",
"message": "<string>",
"traceId": "<string>",
"details": {},
"clientOrderId": "<string>"
}
]{
"status": 400,
"error": {
"code": "bad_request",
"message": "<string>",
"trace_id": "<string>",
"retryAfterSec": 123,
"retryable": true,
"details": {}
}
}{
"status": 404,
"error": {
"code": "<string>",
"message": "<string>",
"trace_id": "<string>",
"retryAfterSec": 123,
"retryable": true,
"details": {}
}
}{
"status": 400,
"error": {
"code": "bad_request",
"message": "<string>",
"trace_id": "<string>",
"retryAfterSec": 123,
"retryable": true,
"details": {}
}
}{
"status": 404,
"error": {
"code": "<string>",
"message": "<string>",
"trace_id": "<string>",
"retryAfterSec": 123,
"retryable": true,
"details": {}
}
}{
"status": 400,
"error": {
"code": "bad_request",
"message": "<string>",
"trace_id": "<string>",
"retryAfterSec": 123,
"retryable": true,
"details": {}
}
}Authorizations
Partner / integrator key — format ps_live_<keyId>_<secret>. Partner keys are issued by PredictStreet; a user can also create keys bound to their own wallet from their account settings in the web app. Never ship to a browser. multi_wallet partners must additionally send X-User-Wallet: 0x<40-hex> on every authenticated request to declare the acting wallet. See the API keys guide for scope taxonomy, partner kinds, rate limits, and rotation procedure.
Headers
Required for multi_wallet partners on every authenticated request; ignored for single_wallet. Declares the acting end-user wallet for this request — drives KYC checks, balances/positions/orders attribution, rate-limit buckets, and audit. Lower-cased server-side. Missing on a multi_wallet key → 401 api_key_user_wallet_required; malformed → 401 api_key_user_wallet_invalid. The on-chain CTFExchange/Vault contracts still verify EIP-712 signer ↔ vault binding, so loosening API-layer attribution is safe by construction.
^0x[a-fA-F0-9]{40}$"0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb3"
Body
1–10 orders, each identical in shape to the single POST /api/orders/place body. Processed sequentially in array order.
1 - 10 elementsShow child attributes
Show child attributes
Response
Per-order results, aligned to the request orders[] by index. Inspect each entry's success flag and status — a 201 batch can still contain REJECTED entries (e.g. bad_signature, maker_mismatch). An entry the exchange was too busy to take comes back REJECTED with code: journal_intent_not_durable and details.retryable: true: nothing was admitted for it, so resend that same signed order unchanged, under the same clientOrderId, shortly. The other entries keep their own results.
Server-side order id (UUID). Empty string when the order was rejected before it was recorded (validation, signature, fee or funds checks); an order the matching engine rejects after it was recorded comes back as REJECTED with its real id.
Lifecycle state at the moment of response. Note: a 201 response may carry status=REJECTED together with a populated code / message — partner SDKs MUST inspect the body, not just the HTTP code.
PENDING, OPEN, FILLED, CANCELLED, REJECTED, EXPIRED, SETTLEMENT_FAILED Cumulative quantity filled at response time (decimal string).
quantity - filledQty (decimal string).
Synchronous fills produced by IOC/FOK or aggressive LIMIT orders.
Show child attributes
Show child attributes
true when the order was accepted (status ≠ REJECTED); false for a per-order business reject. Convenience flag over status.
Reject reason code (insufficient_funds, invalid_amounts, market_not_open, bad_signature, order_signed_with_floor_notional, insufficient_position, …). Present when status=REJECTED. For order_signed_with_floor_notional the response body also carries a details object with signedMakerAmountWei + expectedCeilMakerAmountWei so the SDK can re-sign without recomputing the CEIL formula — see /errors/codes#order_signed_with_floor_notional-diagnostic-hints.
Human-readable explanation; pairs with code.
Correlation id for this request — quote it in support reports. On place-batch every entry carries the same value. Omitted (never null) when no trace is active. Error envelopes carry the same id as error.trace_id.
Structured rejection context; the shape depends on code. bad_signature carries recovered (the address your signature recovers to, null if it does not decode), expected_signer (the authenticated wallet) and platform_canonical_struct (the exact Order struct the platform hashed and verified) — diff it field by field against the struct you signed. order_signed_with_floor_notional carries signedMakerAmountWei + expectedCeilMakerAmountWei. Never rely on details being present — check before reading.
Echo of the request clientOrderId (when supplied). Lets MM partners correlate the server-issued orderId to their own client-side handle without a follow-up GET /api/orders/{id}. Present on every shape (success, REJECTED, idempotent replay) when the request carried one. Also echoed on the order_placed and order_cancelled frames of the user_orders WebSocket channel.