Close one position on an account
Closes one open position at market, wholly or in part, with the organization API key. The account keeps its status and is not locked out.
- Whole position (no
quantity, or the full open size): the contract’s working orders on the account are cancelled, the position is closed at market, and its take-profit and stop-loss orders are cancelled after the fill. This is whatPOST .../flattendoes, for this one contract. Orders on other contracts are untouched. - Part of it (
quantitybelow the open size): a reduce-only market order forquantity. Working orders stay; take-profit and stop-loss orders keep protecting what remains.
The close is an ordinary market order: it fills at the market price with the usual commissions, updates balance and rules like any close, and appears on the real-time stream (OrderUpdate, Fill, PositionUpdate, AccountUpdate) and in order history with reason Admin flatten: <who> — <your reason> (trigger admin_flatten). An ACCOUNT_UPDATED event (trigger admin_position_close) lands on the account’s event log and goes to account.updated webhooks.
It is refused with 409 MARKET_CLOSED while the contract’s market is closed (for example during the daily break, at the weekend or on a holiday); nothing is closed.
Retries: send an Idempotency-Key header to make retries safe; a retry with the same key returns the first answer and never closes twice. A whole-position close repeated without a key answers 404 NO_POSITION once the position is gone. On 504 CLOSE_OUTCOME_UNKNOWN read the positions before retrying a partial close.
Requires manage permission on traders.
curl -X POST "https://api.hyperprop.com/platform/v1/organization/trading-accounts/7c9e6679-7425-40de-944b-e07fc1f90ae7/positions/MNQZ6/close" \
-H "X-API-Key: hp_live_your_key_here" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: close-7c9e6679-mnqz6-001" \
-d '{"reason": "Risk review", "quantity": 1}'
curl --request POST \
--url https://api.hyperprop.com/platform/v1/organization/trading-accounts/{accountId}/positions/{contract}/close \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"reason": "Risk review",
"quantity": 1
}
'import requests
url = "https://api.hyperprop.com/platform/v1/organization/trading-accounts/{accountId}/positions/{contract}/close"
payload = {
"reason": "Risk review",
"quantity": 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({reason: 'Risk review', quantity: 1})
};
fetch('https://api.hyperprop.com/platform/v1/organization/trading-accounts/{accountId}/positions/{contract}/close', 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://api.hyperprop.com/platform/v1/organization/trading-accounts/{accountId}/positions/{contract}/close",
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([
'reason' => 'Risk review',
'quantity' => 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://api.hyperprop.com/platform/v1/organization/trading-accounts/{accountId}/positions/{contract}/close"
payload := strings.NewReader("{\n \"reason\": \"Risk review\",\n \"quantity\": 1\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://api.hyperprop.com/platform/v1/organization/trading-accounts/{accountId}/positions/{contract}/close")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"reason\": \"Risk review\",\n \"quantity\": 1\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.hyperprop.com/platform/v1/organization/trading-accounts/{accountId}/positions/{contract}/close")
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 \"reason\": \"Risk review\",\n \"quantity\": 1\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"accountId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"accountNumber": "ACC-50K-000123",
"contract": "MNQZ6",
"side": "long",
"requestedQuantity": 1,
"remainingQuantity": 1,
"closed": false,
"ordersCancelled": 0,
"orders": [
{
"orderId": "<string>",
"contract": "MNQZ6",
"side": "sell",
"type": "market",
"quantity": 1,
"filledQuantity": 1,
"status": "filled",
"avgFillPrice": 20010.5,
"filledAt": "2026-10-30T14:41:07.312Z",
"rejectReason": null,
"reason": "Admin flatten: API key — Risk review"
}
],
"reason": "Admin flatten: API key — Risk review"
}
}{
"success": false,
"statusCode": 400,
"error": "Bad Request",
"message": "Cannot close 3 of MNQZ6: only 2 is open",
"code": "QUANTITY_EXCEEDS_POSITION"
}{
"success": false,
"statusCode": 401,
"error": "Unauthorized",
"message": "Authentication required",
"code": "UNAUTHORIZED"
}{
"statusCode": 403,
"error": "Forbidden",
"message": "Your role does not have write access to \"Traders & accounts\"",
"code": "INSUFFICIENT_PERMISSIONS"
}{
"success": false,
"statusCode": 404,
"error": "Not Found",
"message": "No open position in MNQZ6",
"code": "NO_POSITION"
}{
"success": false,
"statusCode": 409,
"error": "Conflict",
"message": "Market is closed. Trading resumes at session open.",
"code": "MARKET_CLOSED"
}{
"success": false,
"statusCode": 500,
"error": "Internal Server Error",
"message": "An unexpected error occurred",
"code": "INTERNAL_ERROR"
}{
"success": false,
"statusCode": 502,
"error": "Error",
"message": "The trading engine could not be reached; nothing was closed",
"code": "ENGINE_UNAVAILABLE"
}{
"success": false,
"statusCode": 504,
"error": "Error",
"message": "The trading engine did not answer in time; the position may or may not have been closed. Read the account's positions before retrying.",
"code": "CLOSE_OUTCOME_UNKNOWN"
}Authorizations
Organization API key. Format: "hp_live_{key}". Organization admins manage the key in the dashboard.
Path Parameters
Trading account ID
Contract symbol of the open position, as on the positions read and the real-time stream
^[A-Za-z0-9._-]{1,40}$Body
Why the position is being closed. Recorded on the resulting orders and on the account's event log.
3 - 200"Risk review"
How much to close, in the position's units (futures: contracts; perpetuals: units of the contract's quantityStep, as quantity on the positions read). Omit to close the whole position.
1 <= x <= 42949672951
curl --request POST \
--url https://api.hyperprop.com/platform/v1/organization/trading-accounts/{accountId}/positions/{contract}/close \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"reason": "Risk review",
"quantity": 1
}
'import requests
url = "https://api.hyperprop.com/platform/v1/organization/trading-accounts/{accountId}/positions/{contract}/close"
payload = {
"reason": "Risk review",
"quantity": 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({reason: 'Risk review', quantity: 1})
};
fetch('https://api.hyperprop.com/platform/v1/organization/trading-accounts/{accountId}/positions/{contract}/close', 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://api.hyperprop.com/platform/v1/organization/trading-accounts/{accountId}/positions/{contract}/close",
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([
'reason' => 'Risk review',
'quantity' => 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://api.hyperprop.com/platform/v1/organization/trading-accounts/{accountId}/positions/{contract}/close"
payload := strings.NewReader("{\n \"reason\": \"Risk review\",\n \"quantity\": 1\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://api.hyperprop.com/platform/v1/organization/trading-accounts/{accountId}/positions/{contract}/close")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"reason\": \"Risk review\",\n \"quantity\": 1\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.hyperprop.com/platform/v1/organization/trading-accounts/{accountId}/positions/{contract}/close")
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 \"reason\": \"Risk review\",\n \"quantity\": 1\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"accountId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"accountNumber": "ACC-50K-000123",
"contract": "MNQZ6",
"side": "long",
"requestedQuantity": 1,
"remainingQuantity": 1,
"closed": false,
"ordersCancelled": 0,
"orders": [
{
"orderId": "<string>",
"contract": "MNQZ6",
"side": "sell",
"type": "market",
"quantity": 1,
"filledQuantity": 1,
"status": "filled",
"avgFillPrice": 20010.5,
"filledAt": "2026-10-30T14:41:07.312Z",
"rejectReason": null,
"reason": "Admin flatten: API key — Risk review"
}
],
"reason": "Admin flatten: API key — Risk review"
}
}{
"success": false,
"statusCode": 400,
"error": "Bad Request",
"message": "Cannot close 3 of MNQZ6: only 2 is open",
"code": "QUANTITY_EXCEEDS_POSITION"
}{
"success": false,
"statusCode": 401,
"error": "Unauthorized",
"message": "Authentication required",
"code": "UNAUTHORIZED"
}{
"statusCode": 403,
"error": "Forbidden",
"message": "Your role does not have write access to \"Traders & accounts\"",
"code": "INSUFFICIENT_PERMISSIONS"
}{
"success": false,
"statusCode": 404,
"error": "Not Found",
"message": "No open position in MNQZ6",
"code": "NO_POSITION"
}{
"success": false,
"statusCode": 409,
"error": "Conflict",
"message": "Market is closed. Trading resumes at session open.",
"code": "MARKET_CLOSED"
}{
"success": false,
"statusCode": 500,
"error": "Internal Server Error",
"message": "An unexpected error occurred",
"code": "INTERNAL_ERROR"
}{
"success": false,
"statusCode": 502,
"error": "Error",
"message": "The trading engine could not be reached; nothing was closed",
"code": "ENGINE_UNAVAILABLE"
}{
"success": false,
"statusCode": 504,
"error": "Error",
"message": "The trading engine did not answer in time; the position may or may not have been closed. Read the account's positions before retrying.",
"code": "CLOSE_OUTCOME_UNKNOWN"
}