Orders
Place, modify and cancel orders in one or many accounts, and estimate margin first.
Place orders #
/v1/orders scope ordersPlaces each order in every account it names (sized per account; split above the exchange freeze quantity).
More about this
Once placement starts the answer is 200 with one result per slice, even when some accounts refuse: check each status. Request-level problems (bad JSON, validation, unknown instrument or account list, missing Idempotency-Key) are 4xx and place nothing.
Repeat a request with the same Idempotency-Key to get the first answer back (Idempotent-Replayed: true) instead of placing again.
Parameters
- Idempotency-Key header · string required
A new UUID per order request (1-128 printable characters).
Body fields
- orders object[] required
- use_multiplier boolean
Scale quantity by each account's
Multiplier.
Errors
| HTTP | Code | When |
|---|---|---|
| 400 | malformed_json | The body is not JSON, or does not fit the request shape (unknown or missing fields, wrong types). |
| 400 | idempotency_key_required | The |
| 400 | invalid_idempotency_key | The |
| 401 | unauthorized | No credential, or the credential is invalid, expired or revoked. |
| 403 | forbidden | The credential may not use this route (missing scope, app-session-only route, IP not allowed). |
| 409 | request_in_progress | A request with this |
| 422 | invalid_request | The request is well-formed but not valid; |
| 422 | idempotency_key_reused | This |
| 429 | rate_limited | Too many requests for this credential (or too many failed attempts); retry after the |
| 503 | service_unavailable | A dependency is temporarily unavailable, or the feature is off on this server; retry later. |
All fields (request and response schema)
Loading fields…
curl -X POST "https://cirrus.pocketful.in/v1/orders" \
-H "Authorization: token $CIRRUS_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"orders": [
{
"instrument_token": "CT:TEST:RELIANCE",
"side": "BUY",
"order_type": "LIMIT",
"product": "DELIVERY",
"quantity": 1,
"price": 2500,
"accounts": [
"P1"
]
}
]
}'import os
import uuid
import requests
response = requests.post(
"https://cirrus.pocketful.in/v1/orders",
headers={
"Authorization": f"token {os.environ['CIRRUS_API_KEY']}",
"Idempotency-Key": str(uuid.uuid4()),
},
json={
"orders": [
{
"instrument_token": "CT:TEST:RELIANCE",
"side": "BUY",
"order_type": "LIMIT",
"product": "DELIVERY",
"quantity": 1,
"price": 2500,
"accounts": [
"P1",
],
},
],
},
timeout=10,
)
print(response.status_code, response.json())const response = await fetch('https://cirrus.pocketful.in/v1/orders', {
method: 'POST',
headers: {
Authorization: `token ${process.env.CIRRUS_API_KEY}`,
'Idempotency-Key': crypto.randomUUID(),
'Content-Type': 'application/json',
},
body: JSON.stringify({
"orders": [
{
"instrument_token": "CT:TEST:RELIANCE",
"side": "BUY",
"order_type": "LIMIT",
"product": "DELIVERY",
"quantity": 1,
"price": 2500,
"accounts": [
"P1"
]
}
]
}),
});
const body = await response.json();
console.log(response.status, body);{
"status": "success",
"data": {
"results": [
{
"order_index": 0,
"account": "P1",
"quantity": 1,
"status": "accepted",
"order_id": "PAPER-1",
"message": null,
"order_type": "LIMIT",
"price": 2500,
"instrument_token": "CT:TEST:RELIANCE",
"order_tag": "01M3PGPRZFZXEQM0KEC0DB653H"
}
],
"accepted": 1,
"rejected": 0,
"unknown": 0
},
"error": null
}One order #
/v1/orders/{order_id} scope readOne order from today's order book, in the same shape as a GET /v1/portfolio/orders row (OrderData, with instrument details and live prices when known).
More about this
order_id is the broker's order id (as PATCH / DELETE on this path take it) or the order's order_tag (known before the broker acknowledges), or the client_tag it was placed with. Searches every linked account, or only account.
An id that names more than one order (a client_tag given to several orders or accounts, or the same broker order id in two accounts) is answered with 409 ambiguous_order listing the accounts; send account to pick one.
A cover / bracket entry placed through POST /v1/orders may be accepted with a null order_id (the broker's reply did not name the entry); look it up by its order_tag here once the order book has it.
Parameters
- order_id path · string required
Broker order id,
order_tagorclient_tag(1-64 letters, digits,-,_,.or:). - account query · string
Only this account's book; every linked account when absent.
Errors
| HTTP | Code | When |
|---|---|---|
| 400 | invalid_query | The query string does not fit the route's parameters. |
| 401 | unauthorized | No credential, or the credential is invalid, expired or revoked. |
| 403 | forbidden | The credential may not use this route (missing scope, app-session-only route, IP not allowed). |
| 404 | order_not_found | No order with this id (broker order id or |
| 404 | account_not_found | No linked broker account with this id for the caller. |
| 409 | ambiguous_order | The id names orders in more than one account (or several orders); |
| 422 | invalid_request | The request is well-formed but not valid; |
| 429 | rate_limited | Too many requests for this credential (or too many failed attempts); retry after the |
| 503 | service_unavailable | A dependency is temporarily unavailable, or the feature is off on this server; retry later. |
All fields (request and response schema)
Loading fields…
curl "https://cirrus.pocketful.in/v1/orders/<order_id>" \
-H "Authorization: token $CIRRUS_API_KEY"import os
import requests
response = requests.get(
"https://cirrus.pocketful.in/v1/orders/<order_id>",
headers={
"Authorization": f"token {os.environ['CIRRUS_API_KEY']}",
},
timeout=10,
)
print(response.status_code, response.json())const response = await fetch('https://cirrus.pocketful.in/v1/orders/<order_id>', {
method: 'GET',
headers: {
Authorization: `token ${process.env.CIRRUS_API_KEY}`,
},
});
const body = await response.json();
console.log(response.status, body);{
"status": "success",
"data": {
"broker_tag": null,
"order_id": "250929000101",
"parent_tag": null,
"username": "user-01M3PGPRXSNM34C3C6AM1B721X",
"account": "P1",
"broker": "paper",
"tradingsymbol": "RELIANCE-EQ",
"side": "BUY",
"order_type": "LIMIT",
"product": "MIS",
"quantity": 5,
"price": 2500,
"trigger_price": null,
"state": "OPEN",
"filled_qty": 0,
"average_price": null,
"status_message": null,
"broker_updated_at": null,
"created_at": "2026-09-29T12:02:21.780809Z",
"status_history": [],
"client_tag": "strat-7:entry",
"lot_size": 1,
"exchange": "NSE",
"instrument_type": "EQUITY",
"symbol": "RELIANCE",
"expiry": "",
"strike": 0,
"option_type": "",
"ltp": 2500,
"prev_close": 2490,
"instrument_token": "CT:TEST:RELIANCE",
"order_tag": "01M3PGPRYMRRAPV8MCBEA19MS1"
},
"error": null
}Modify an order #
/v1/orders/{order_id} scope ordersChanges an open order in one account: send the order as it should be now (same validation and market protection as placement).
More about this
Once the request is valid the answer is 200 with the broker's verdict in status; request-level problems are 4xx and change nothing. quantity must be greater than what has already filled.
Send an Idempotency-Key to make retries safe: a repeat with the same key gets the first answer back (Idempotent-Replayed: true) instead of modifying again.
Parameters
- order_id path · string required
Broker order id,
order_tagorclient_tag, asGET /v1/orders/{order_id}takes it (1-64 letters, digits,-,_,.or:). A tag is sent to the broker as the order's broker id. - Idempotency-Key header · string
Optional: a new UUID per modify request (1-128 printable characters).
Body fields
- account string required
Account id the order is in (see
/v1/accounts). - instrument_token string required
Instrument id of the order.
- side string required
Order side.
One of: BUY, SELL
- order_type string required
MARKET,LIMIT,SL(stop-loss limit) orSL_M(stop-loss market;SL-MandSLMare accepted in requests).One of: MARKET, LIMIT, SL, SL_M
- product string required
MIS(intraday),CARRYFORWARD(overnight derivatives, NRML),DELIVERY(equity delivery, CNC) orMTF(margin trading facility).One of: MIS, CARRYFORWARD, DELIVERY, MTF
- quantity integer (int64) required
Units, or lots when
qty_is_in_lot. Units round down to whole lots; under one lot is refused. - qty_is_in_lot boolean
quantitycounts lots, not units. - price number (double)
Limit price (
LIMIT,SL); 0 or absent for market orders. - trigger_price number (double) | null
Trigger price for
SL/SL_M.
Errors
| HTTP | Code | When |
|---|---|---|
| 400 | malformed_json | The body is not JSON, or does not fit the request shape (unknown or missing fields, wrong types). |
| 400 | invalid_idempotency_key | The |
| 401 | unauthorized | No credential, or the credential is invalid, expired or revoked. |
| 403 | forbidden | The credential may not use this route (missing scope, app-session-only route, IP not allowed). |
| 404 | account_not_found | No linked broker account with this id for the caller. |
| 409 | order_not_open | The order is already finished (filled, cancelled or rejected), so there is nothing to modify or cancel. Nothing was sent to the broker. |
| 409 | request_in_progress | A request with this |
| 422 | invalid_request | The request is well-formed but not valid; |
| 422 | idempotency_key_reused | This |
| 429 | rate_limited | Too many requests for this credential (or too many failed attempts); retry after the |
| 503 | service_unavailable | A dependency is temporarily unavailable, or the feature is off on this server; retry later. |
All fields (request and response schema)
Loading fields…
curl -X PATCH "https://cirrus.pocketful.in/v1/orders/<order_id>" \
-H "Authorization: token $CIRRUS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"account": "P1",
"instrument_token": "CT:TEST:RELIANCE",
"side": "BUY",
"order_type": "SL",
"product": "MIS",
"quantity": 5,
"price": 2500,
"trigger_price": 2499
}'import os
import requests
response = requests.patch(
"https://cirrus.pocketful.in/v1/orders/<order_id>",
headers={
"Authorization": f"token {os.environ['CIRRUS_API_KEY']}",
},
json={
"account": "P1",
"instrument_token": "CT:TEST:RELIANCE",
"side": "BUY",
"order_type": "SL",
"product": "MIS",
"quantity": 5,
"price": 2500,
"trigger_price": 2499,
},
timeout=10,
)
print(response.status_code, response.json())const response = await fetch('https://cirrus.pocketful.in/v1/orders/<order_id>', {
method: 'PATCH',
headers: {
Authorization: `token ${process.env.CIRRUS_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"account": "P1",
"instrument_token": "CT:TEST:RELIANCE",
"side": "BUY",
"order_type": "SL",
"product": "MIS",
"quantity": 5,
"price": 2500,
"trigger_price": 2499
}),
});
const body = await response.json();
console.log(response.status, body);{
"status": "success",
"data": {
"account": "P1",
"order_id": "PAPER-9",
"status": "accepted",
"message": null
},
"error": null
}Cancel an order #
/v1/orders/{order_id} scope ordersCancels an open order in one account.
More about this
Once the request is valid the answer is 200 with the broker's verdict in status.
A bracket / cover entry is cancelled together with its legs. Once the entry has (partly) filled, its legs are the position's live stop-loss / target, so such a cancel is refused with 409 position_protected unless legs=true is sent; then the legs are cancelled, the answer carries a warning (the position is unprotected) and the activity log records the protection as removed. An entry that has not filled is cancelled as before.
Parameters
- order_id path · string required
Broker order id,
order_tagorclient_tag, asGET /v1/orders/{order_id}takes it (1-64 letters, digits,-,_,.or:). A tag is sent to the broker as the order's broker id. - account query · string required
Account id the order is in.
- instrument_token query · string required
Instrument id of the order.
- quantity query · integer (int64)
Units still open (some brokers need it to cancel); 0 or absent otherwise.
- legs query · boolean
For a bracket / cover entry that has (partly) filled:
truealso cancels its live stop-loss / target legs, leaving the position unprotected. Without it such a cancel is refused (409position_protected).
Errors
| HTTP | Code | When |
|---|---|---|
| 400 | invalid_query | The query string does not fit the route's parameters. |
| 401 | unauthorized | No credential, or the credential is invalid, expired or revoked. |
| 403 | forbidden | The credential may not use this route (missing scope, app-session-only route, IP not allowed). |
| 404 | account_not_found | No linked broker account with this id for the caller. |
| 409 | position_protected | The order is a (partly) filled bracket / cover entry: cancelling it would cancel the live stop-loss / target legs of its position. Send |
| 409 | order_not_open | The order is already finished (filled, cancelled or rejected), so there is nothing to modify or cancel. Nothing was sent to the broker. |
| 422 | invalid_request | The request is well-formed but not valid; |
| 429 | rate_limited | Too many requests for this credential (or too many failed attempts); retry after the |
| 503 | service_unavailable | A dependency is temporarily unavailable, or the feature is off on this server; retry later. |
All fields (request and response schema)
Loading fields…
curl -X DELETE "https://cirrus.pocketful.in/v1/orders/<order_id>?account=<account>&instrument_token=<instrument_token>" \
-H "Authorization: token $CIRRUS_API_KEY"import os
import requests
response = requests.delete(
"https://cirrus.pocketful.in/v1/orders/<order_id>",
headers={
"Authorization": f"token {os.environ['CIRRUS_API_KEY']}",
},
params={
"account": "<account>",
"instrument_token": "<instrument_token>",
},
timeout=10,
)
print(response.status_code, response.json())const response = await fetch('https://cirrus.pocketful.in/v1/orders/<order_id>?account=<account>&instrument_token=<instrument_token>', {
method: 'DELETE',
headers: {
Authorization: `token ${process.env.CIRRUS_API_KEY}`,
},
});
const body = await response.json();
console.log(response.status, body);{
"status": "success",
"data": {
"account": "P1",
"order_id": "PAPER-8",
"status": "accepted",
"message": null
},
"error": null
}An order's protection #
/v1/orders/{order_id}/protection scope readThe stop-loss / target an order placed with protection on POST /v1/orders is protected by: status (none, waiting_for_fill, armed), where it lives (route), the rules asked for and the triggers holding it, each with the path to open it (version v2: /v2/triggers/{trigger_id}, v1: /v1/triggers/{trigger_id}).
More about this
The order is found as GET /v1/orders/{order_id} finds it (broker id, order_tag or client_tag, today's book). Protection records are kept 36 hours after the order; an older or unprotected order answers none.
Parameters
- order_id path · string required
Broker order id,
order_tagorclient_tag. - account query · string
Only this account's book; every linked account when absent.
Errors
| HTTP | Code | When |
|---|---|---|
| 400 | invalid_query | The query string does not fit the route's parameters. |
| 401 | unauthorized | No credential, or the credential is invalid, expired or revoked. |
| 403 | forbidden | The credential may not use this route (missing scope, app-session-only route, IP not allowed). |
| 404 | order_not_found | No order with this id (broker order id or |
| 404 | account_not_found | No linked broker account with this id for the caller. |
| 409 | ambiguous_order | The id names orders in more than one account (or several orders); |
| 422 | invalid_request | The request is well-formed but not valid; |
| 429 | rate_limited | Too many requests for this credential (or too many failed attempts); retry after the |
| 503 | service_unavailable | A dependency is temporarily unavailable, or the feature is off on this server; retry later. |
All fields (request and response schema)
Loading fields…
curl "https://cirrus.pocketful.in/v1/orders/<order_id>/protection" \
-H "Authorization: token $CIRRUS_API_KEY"import os
import requests
response = requests.get(
"https://cirrus.pocketful.in/v1/orders/<order_id>/protection",
headers={
"Authorization": f"token {os.environ['CIRRUS_API_KEY']}",
},
timeout=10,
)
print(response.status_code, response.json())const response = await fetch('https://cirrus.pocketful.in/v1/orders/<order_id>/protection', {
method: 'GET',
headers: {
Authorization: `token ${process.env.CIRRUS_API_KEY}`,
},
});
const body = await response.json();
console.log(response.status, body);{
"status": "success",
"data": {
"account": "P1",
"status": "armed",
"route": "trigger",
"rules": {
"stop_loss": {
"type": "points",
"value": 20
},
"target": {
"type": "points",
"value": 40
},
"trail": null
},
"broker_id": null,
"triggers": [
{
"trigger_id": "01JAC9X2K7QF0000000000TRG1",
"version": "v2",
"quantity": 5,
"entry_price": 2499.5
}
],
"order_tag": "01JAC9X2K7QF0000000000PR01"
},
"error": null
}Calculate order margins #
/v1/margins/orders scope readThe margin each order would need in each account, for the same body as POST /v1/orders (sized and priced as it would be placed).
More about this
Nothing is placed and no Idempotency-Key is needed. Accounts without a figure carry a message instead; the other accounts still get theirs.
Broker limits: Pocketful, 5paisa, Motilal Oswal, Tradejini, XTS and ODIN accounts have no margin calculation; their results have no figure and error_code not_supported_by_broker.
Body fields
- orders object[] required
- use_multiplier boolean
Scale quantity by each account's
Multiplier.
Errors
| HTTP | Code | When |
|---|---|---|
| 400 | malformed_json | The body is not JSON, or does not fit the request shape (unknown or missing fields, wrong types). |
| 401 | unauthorized | No credential, or the credential is invalid, expired or revoked. |
| 403 | forbidden | The credential may not use this route (missing scope, app-session-only route, IP not allowed). |
| 422 | invalid_request | The request is well-formed but not valid; |
| 429 | rate_limited | Too many requests for this credential (or too many failed attempts); retry after the |
| 503 | service_unavailable | A dependency is temporarily unavailable, or the feature is off on this server; retry later. |
All fields (request and response schema)
Loading fields…
curl -X POST "https://cirrus.pocketful.in/v1/margins/orders" \
-H "Authorization: token $CIRRUS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"orders": [
{
"instrument_token": "CT:TEST:RELIANCE",
"side": "BUY",
"order_type": "LIMIT",
"product": "MIS",
"quantity": 10,
"price": 2500,
"accounts": [
"P2",
"PF1"
]
}
],
"use_multiplier": true
}'import os
import requests
response = requests.post(
"https://cirrus.pocketful.in/v1/margins/orders",
headers={
"Authorization": f"token {os.environ['CIRRUS_API_KEY']}",
},
json={
"orders": [
{
"instrument_token": "CT:TEST:RELIANCE",
"side": "BUY",
"order_type": "LIMIT",
"product": "MIS",
"quantity": 10,
"price": 2500,
"accounts": [
"P2",
"PF1",
],
},
],
"use_multiplier": True,
},
timeout=10,
)
print(response.status_code, response.json())const response = await fetch('https://cirrus.pocketful.in/v1/margins/orders', {
method: 'POST',
headers: {
Authorization: `token ${process.env.CIRRUS_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"orders": [
{
"instrument_token": "CT:TEST:RELIANCE",
"side": "BUY",
"order_type": "LIMIT",
"product": "MIS",
"quantity": 10,
"price": 2500,
"accounts": [
"P2",
"PF1"
]
}
],
"use_multiplier": true
}),
});
const body = await response.json();
console.log(response.status, body);{
"status": "success",
"data": {
"results": [
{
"order_index": 0,
"account": "PF1",
"quantity": 10,
"total_required": null,
"message": "Margin calculation is not available for pocketful accounts.",
"error_code": "not_supported_by_broker",
"instrument_token": "CT:TEST:RELIANCE"
},
{
"order_index": 0,
"account": "P2",
"quantity": 20,
"total_required": 50000,
"message": null,
"error_code": null,
"instrument_token": "CT:TEST:RELIANCE"
}
],
"total_required": 50000
},
"error": null
}