curl --request POST \
--url https://core.api.dev.predictstreet.sde.adifoundation.ai/api/orders/cancel \
--header 'Content-Type: application/json' \
--header 'X-Api-Key: <api-key>' \
--data '
{
"orderId": "<string>"
}
'import requests
url = "https://core.api.dev.predictstreet.sde.adifoundation.ai/api/orders/cancel"
payload = { "orderId": "<string>" }
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({orderId: '<string>'})
};
fetch('https://core.api.dev.predictstreet.sde.adifoundation.ai/api/orders/cancel', 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/cancel",
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([
'orderId' => '<string>'
]),
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/cancel"
payload := strings.NewReader("{\n \"orderId\": \"<string>\"\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/cancel")
.header("X-Api-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"orderId\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://core.api.dev.predictstreet.sde.adifoundation.ai/api/orders/cancel")
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 \"orderId\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"orderId": "<string>",
"status": "CANCELLED",
"remainingQty": "<string>",
"code": "cancel_pending",
"message": "<string>",
"retryAfterSec": 123
}{
"orderId": "<string>",
"status": "CANCELLED",
"remainingQty": "<string>",
"code": "cancel_pending",
"message": "<string>",
"retryAfterSec": 123
}{
"status": 400,
"error": {
"code": "bad_request",
"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": 400,
"error": {
"code": "bad_request",
"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": 400,
"error": {
"code": "bad_request",
"message": "<string>",
"trace_id": "<string>",
"retryAfterSec": 123,
"retryable": true,
"details": {}
}
}Cancel a single order
Idempotent — an id this wallet does not hold returns 200 with status=not_found, and one it holds already ended returns 200 with status=already_terminal; neither is a 404. Authentication scope is checked against the order owner, not the JWT wallet alone. A cancel that is recorded but has no recorded answer yet returns 202 with status=cancel_pending and Retry-After: 5; send the same cancel again after Retry-After until it ends.
curl --request POST \
--url https://core.api.dev.predictstreet.sde.adifoundation.ai/api/orders/cancel \
--header 'Content-Type: application/json' \
--header 'X-Api-Key: <api-key>' \
--data '
{
"orderId": "<string>"
}
'import requests
url = "https://core.api.dev.predictstreet.sde.adifoundation.ai/api/orders/cancel"
payload = { "orderId": "<string>" }
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({orderId: '<string>'})
};
fetch('https://core.api.dev.predictstreet.sde.adifoundation.ai/api/orders/cancel', 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/cancel",
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([
'orderId' => '<string>'
]),
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/cancel"
payload := strings.NewReader("{\n \"orderId\": \"<string>\"\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/cancel")
.header("X-Api-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"orderId\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://core.api.dev.predictstreet.sde.adifoundation.ai/api/orders/cancel")
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 \"orderId\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"orderId": "<string>",
"status": "CANCELLED",
"remainingQty": "<string>",
"code": "cancel_pending",
"message": "<string>",
"retryAfterSec": 123
}{
"orderId": "<string>",
"status": "CANCELLED",
"remainingQty": "<string>",
"code": "cancel_pending",
"message": "<string>",
"retryAfterSec": 123
}{
"status": 400,
"error": {
"code": "bad_request",
"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": 400,
"error": {
"code": "bad_request",
"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": 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
Response
Server-side order id (echoes the request).
Cancel outcome. CANCELLED matches the OrderStatus enum every other endpoint returns. already_terminal — this wallet holds the order and it had already ended (cancelled, filled, expired, rejected, settlement failed). not_found — this wallet holds no such order (an unknown id, or another wallet's). Both are 200, NOT 404: the cancel call is idempotent, and a foreign id reads the same as an unknown one. cancel_pending — answered with HTTP 202 and Retry-After: 5 (also retryAfterSec): the cancel is recorded, but no answer to it is recorded yet (for example the matching engine is restarting and has not answered it). The order may still be open with its collateral held, and can still fill. Send the same cancel again after Retry-After: retrying with the same order id is safe, cannot cancel twice, and is what completes it soonest. The platform may also complete it on its own. Its final status (CANCELLED, or FILLED if it filled first) arrives on the user_orders WebSocket channel and on GET /api/orders/{id}. A retry answered 409 order_cancel_not_taken means the engine refused this cancel and the order is still open.
CANCELLED, not_found, already_terminal, cancel_pending Quantity that was still unfilled at cancel time — the same meaning as remainingQty on /api/orders/place and /api/orders/{id}. Only set when status is CANCELLED.
Only with status=cancel_pending (HTTP 202): the same value, as a code to switch on.
cancel_pending Only with status=cancel_pending (HTTP 202): what the code means, in words.
Only with status=cancel_pending (HTTP 202): seconds to wait before sending the same cancel again; the same value as the Retry-After header.