Skip to content
Cirrus home
Sign in

Reference

Protection (classic triggers)

The first trigger API: protect one position with a stop-loss, target and trail.

Read the guide first

List triggers #

GET /v1/triggers scope read

Every trigger of the caller, with its live levels and status: server-side triggers and the mirrors of broker-held protection (bracket / cover legs, GTTs) armed from placed orders.

More about this

Ended protections (fired, exited, cancelled or deleted in the last 7 days, newest 500) follow the live ones, with status and ended_reason set.

Parameters

  • status query · string

    active: live triggers only; ended: ended ones only; absent: both.

Errors

HTTPCodeWhen
400invalid_query

The query string does not fit the route's parameters.

401unauthorized

No credential, or the credential is invalid, expired or revoked.

403forbidden

The credential may not use this route (missing scope, app-session-only route, IP not allowed).

429rate_limited

Too many requests for this credential (or too many failed attempts); retry after the Retry-After header (seconds; error.retry_after_ms has the exact wait).

503service_unavailable

A dependency is temporarily unavailable, or the feature is off on this server; retry later.

All fields (request and response schema)

Loading fields…

GET
curl "https://cirrus.pocketful.in/v1/triggers" \
  -H "Authorization: token $CIRRUS_API_KEY"
Response · 200
{
  "status": "success",
  "data": [
    {
      "trigger_id": "430cbd1c-3335-4d62-9938-411acd28860d",
      "account": "P1",
      "name": "SL + TGT + TSL",
      "side": "BUY",
      "product": "MIS",
      "quantity": 5,
      "price": 2500,
      "order_id": null,
      "broker_order_id": null,
      "kind": "platform",
      "paired_trigger_id": null,
      "rules": {
        "target": {
          "enabled": true,
          "type": "percentage",
          "value": 2
        },
        "stop_loss": {
          "enabled": true,
          "type": "points",
          "value": 25
        },
        "trail": {
          "enabled": true,
          "type": "points",
          "value": 5
        }
      },
      "stop_loss_price": 2475,
      "initial_stop_loss_price": 2475,
      "target_price": 2550,
      "live": true,
      "status": null,
      "ended_reason": null,
      "created_at": "2026-10-01 10:21:38",
      "updated_at": "2026-10-01 10:21:38",
      "instrument_token": "CT:TEST:RELIANCE",
      "exits": true
    },
    {
      "trigger_id": "31e804b4-68fb-40a2-8504-2e38f8f42476",
      "account": "PF1",
      "name": "SL + TGT",
      "side": "BUY",
      "product": "DELIVERY",
      "quantity": 5,
      "price": 2500,
      "order_id": "250929000002",
      "broker_order_id": "gtt-held",
      "kind": "gtt_oco",
      "paired_trigger_id": null,
      "rules": {
        "target": {
          "enabled": true,
          "type": "points",
          "value": 100
        },
        "stop_loss": {
          "enabled": true,
          "type": "points",
          "value": 25
        },
        "trail": {
          "enabled": false,
          "type": "percentage",
          "value": 0
        }
      },
      "stop_loss_price": 2475,
      "initial_stop_loss_price": 2475,
      "target_price": 2600,
      "live": true,
      "status": null,
      "ended_reason": null,
      "created_at": "2026-10-01 10:21:38",
      "updated_at": "2026-10-01 10:21:38",
      "instrument_token": "CT:TEST:RELIANCE",
      "exits": false
    }
  ],
  "error": null
}

Protect a position #

POST /v1/triggers scope triggers

Protects an open position with a stop-loss / target (and trailing stop-loss), broker-native first.

More about this

Levels are measured from price (LTP when absent); a level already crossed at LTP is refused.

Where it lives (rules.route): auto (default) places a broker GTT when the account's broker has GTTs, the product is positional (CARRYFORWARD, DELIVERY, MTF) and nothing trails; for an intraday (MIS) position with a stop-loss and no trailing it places a broker stop-loss order (SL) where the broker's stop-loss orders are proven, sized to the position the broker holds (kind stop_order); otherwise a server-side trigger watches every tick and exits at market. gtt / stop_order ask for that route (refused with 422 before the broker where auto would not take it); trigger asks for the server-side trigger; bracket and cover are refused (they come only with an entry order). A broker whose GTT takes one leg, or a stop order, holds the stop-loss at the broker and a server-side trigger holds the target; the two name each other (paired_trigger_id) and whichever exits first ends the other. Any exit the server places for a position held by a stop order cancels the stop first (one that already went off is left to finish, and the exit waits for it). A stop order the broker refuses is replaced by a server-side trigger at once.

A broker-held GTT is answered as its display trigger (kind gtt_oco / gtt_single, exits: false, the GTT id in broker_order_id). If the broker refuses the GTT, rules.fallback decides: trigger (default) creates the server-side trigger instead, reject creates nothing (422 gtt_refused). A server-side trigger needs a running trigger exit worker: without one nothing is created (503 trigger_worker_down).

Body fields

  • account string required

    Account id (see /v1/accounts).

  • instrument_token string required

    Instrument id (see /v1/instruments).

  • side string required

    Side of the position's entry (BUY = long, protected by a SELL exit).

    One of: BUY, SELL

  • product string required

    MIS (intraday), CARRYFORWARD (overnight derivatives, NRML), DELIVERY (equity delivery, CNC) or MTF (margin trading facility).

    One of: MIS, CARRYFORWARD, DELIVERY, MTF

  • quantity integer (int64) required

    Units to exit when a level is hit.

  • rules object required

    Stop-loss, target and trailing stop-loss. Enable a stop-loss, a target or both; a trail needs a stop-loss and is percentage or points.

  • price number (double) | null

    Entry / average price the levels are measured from; LTP if absent.

Errors

HTTPCodeWhen
400malformed_json

The body is not JSON, or does not fit the request shape (unknown or missing fields, wrong types).

401unauthorized

No credential, or the credential is invalid, expired or revoked.

403forbidden

The credential may not use this route (missing scope, app-session-only route, IP not allowed).

404account_not_found

No linked broker account with this id for the caller.

422invalid_request

The request is well-formed but not valid; field names the input.

422gtt_refused

The broker refused the GTT protecting a position and rules.fallback is reject: nothing was created.

429rate_limited

Too many requests for this credential (or too many failed attempts); retry after the Retry-After header (seconds; error.retry_after_ms has the exact wait).

503trigger_worker_down

No trigger exit worker is running; nothing was created.

503service_unavailable

A dependency is temporarily unavailable, or the feature is off on this server; retry later.

504broker_outcome_unknown

The broker did not answer in time: it may or may not have applied the change. Check before retrying.

All fields (request and response schema)

Loading fields…

POST
curl -X POST "https://cirrus.pocketful.in/v1/triggers" \
  -H "Authorization: token $CIRRUS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "account": "P1",
    "instrument_token": "CT:TEST:RELIANCE",
    "side": "BUY",
    "product": "MIS",
    "quantity": 5,
    "price": 2500,
    "rules": {
      "stop_loss": {
        "enabled": true,
        "type": "points",
        "value": 25
      },
      "target": {
        "enabled": true,
        "type": "percentage",
        "value": 2
      },
      "trail": {
        "enabled": true,
        "type": "points",
        "value": 5
      }
    }
  }'
Response · 201
{
  "status": "success",
  "data": {
    "trigger_id": "b6ad3114-7fd9-414b-af5c-bcd933758e2c",
    "account": "P1",
    "name": "SL + TGT + TSL",
    "side": "BUY",
    "product": "MIS",
    "quantity": 5,
    "price": 2500,
    "order_id": null,
    "broker_order_id": null,
    "kind": "platform",
    "paired_trigger_id": null,
    "rules": {
      "target": {
        "enabled": true,
        "type": "percentage",
        "value": 2
      },
      "stop_loss": {
        "enabled": true,
        "type": "points",
        "value": 25
      },
      "trail": {
        "enabled": true,
        "type": "points",
        "value": 5
      }
    },
    "stop_loss_price": 2475,
    "initial_stop_loss_price": 2475,
    "target_price": 2550,
    "live": true,
    "status": null,
    "ended_reason": null,
    "created_at": "2026-10-01 10:21:38",
    "updated_at": "2026-10-01 10:21:38",
    "instrument_token": "CT:TEST:RELIANCE",
    "exits": true
  },
  "error": null
}

One trigger #

GET /v1/triggers/{trigger_id} scope read

One trigger of the caller, with its live levels and status (the same shape as a GET /v1/triggers item).

More about this

Another user's id is not found.

Parameters

  • trigger_id path · string required

    The trigger's id.

Errors

HTTPCodeWhen
401unauthorized

No credential, or the credential is invalid, expired or revoked.

403forbidden

The credential may not use this route (missing scope, app-session-only route, IP not allowed).

404trigger_not_found

No trigger with this id for the caller.

429rate_limited

Too many requests for this credential (or too many failed attempts); retry after the Retry-After header (seconds; error.retry_after_ms has the exact wait).

503service_unavailable

A dependency is temporarily unavailable, or the feature is off on this server; retry later.

All fields (request and response schema)

Loading fields…

GET
curl "https://cirrus.pocketful.in/v1/triggers/<trigger_id>" \
  -H "Authorization: token $CIRRUS_API_KEY"
Response · 200
{
  "status": "success",
  "data": {
    "trigger_id": "428f23a8-7607-4a7d-9257-5bbdb49eb9b3",
    "account": "P1",
    "name": "SL + TGT + TSL",
    "side": "BUY",
    "product": "MIS",
    "quantity": 5,
    "price": 2500,
    "order_id": null,
    "broker_order_id": null,
    "kind": "platform",
    "paired_trigger_id": null,
    "rules": {
      "target": {
        "enabled": true,
        "type": "percentage",
        "value": 2
      },
      "stop_loss": {
        "enabled": true,
        "type": "points",
        "value": 25
      },
      "trail": {
        "enabled": true,
        "type": "points",
        "value": 5
      }
    },
    "stop_loss_price": 2475,
    "initial_stop_loss_price": 2475,
    "target_price": 2550,
    "live": true,
    "status": null,
    "ended_reason": null,
    "created_at": "2026-10-01 10:21:38",
    "updated_at": "2026-10-01 10:21:38",
    "instrument_token": "CT:TEST:RELIANCE",
    "exits": true
  },
  "error": null
}

Change a trigger #

PATCH /v1/triggers/{trigger_id} scope triggers

Changes the rules, quantity or entry price of a trigger.

More about this

Levels are recomputed only for the legs whose inputs changed, so trailing progress on an untouched stop-loss is kept. Broker-held protection (exits: false: a bracket / cover order's legs, a GTT or a stop order) is changed at the broker first and answered with its new levels once the broker agreed; its trailing stop-loss and entry price stay as placed, a bracket keeps both legs, a cover or a stop order keeps a stop-loss only (a stop order's target is its paired trigger), and only a GTT's quantity can change (a stop order follows the position's quantity on its own).

Parameters

  • trigger_id path · string required

    The trigger's id.

Body fields

  • rules object | null

    New rules (all three legs).

  • quantity integer (int64) | null

    New quantity, in units.

  • price number (double) | null

    New entry price the levels are measured from.

Errors

HTTPCodeWhen
400malformed_json

The body is not JSON, or does not fit the request shape (unknown or missing fields, wrong types).

401unauthorized

No credential, or the credential is invalid, expired or revoked.

403forbidden

The credential may not use this route (missing scope, app-session-only route, IP not allowed).

404trigger_not_found

No trigger with this id for the caller.

409trigger_fired

The trigger already fired; its exit is being handled.

409broker_held

The protection is held by the broker; change the broker order instead.

409trigger_busy

The trigger changed while it was being updated; retry.

422invalid_request

The request is well-formed but not valid; field names the input.

429rate_limited

Too many requests for this credential (or too many failed attempts); retry after the Retry-After header (seconds; error.retry_after_ms has the exact wait).

502broker_refused

The broker refused the change.

503service_unavailable

A dependency is temporarily unavailable, or the feature is off on this server; retry later.

504broker_outcome_unknown

The broker did not answer in time: it may or may not have applied the change. Check before retrying.

All fields (request and response schema)

Loading fields…

PATCH
curl -X PATCH "https://cirrus.pocketful.in/v1/triggers/<trigger_id>" \
  -H "Authorization: token $CIRRUS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "price": 2510,
    "quantity": 3
  }'
Response · 200
{
  "status": "success",
  "data": {
    "trigger_id": "6b992f81-de42-4803-946d-cda864e0baaf",
    "account": "P1",
    "name": "SL + TGT + TSL",
    "side": "BUY",
    "product": "MIS",
    "quantity": 3,
    "price": 2510,
    "order_id": null,
    "broker_order_id": null,
    "kind": "platform",
    "paired_trigger_id": null,
    "rules": {
      "target": {
        "enabled": true,
        "type": "percentage",
        "value": 2
      },
      "stop_loss": {
        "enabled": true,
        "type": "points",
        "value": 25
      },
      "trail": {
        "enabled": true,
        "type": "points",
        "value": 5
      }
    },
    "stop_loss_price": 2485,
    "initial_stop_loss_price": 2485,
    "target_price": 2560.2,
    "live": true,
    "status": null,
    "ended_reason": null,
    "created_at": "2026-10-01 10:21:38",
    "updated_at": "2026-10-01 10:21:38",
    "instrument_token": "CT:TEST:RELIANCE",
    "exits": true
  },
  "error": null
}

Delete a trigger #

DELETE /v1/triggers/{trigger_id} scope triggers

Removes a trigger.

More about this

Broker-held protection is cancelled at the broker first (the bracket / cover order, the GTT or the stop order; a stop order that already went off is exiting at the broker and is not cancelled: 502, retry), and its state always copies the broker's. If the broker refuses the cancel, the protection is read back: shown cancelled or ended at the broker, the trigger is removed (broker_cancel cancelled, the broker's refusal in broker_message); shown fired, it ends as fired_at_broker (409 trigger_fired); otherwise it stays live with status cancel_pending (202, deleted false, broker_cancel pending, the broker's reason in broker_message) and is re-checked until the broker shows a final state, which it then copies. If the account is no longer linked the trigger is removed and broker_cancel is failed. If the broker does not answer or the session expired, the trigger is kept (502) so the delete can be retried.

Parameters

  • trigger_id path · string required

    The trigger's id.

Errors

HTTPCodeWhen
401unauthorized

No credential, or the credential is invalid, expired or revoked.

403forbidden

The credential may not use this route (missing scope, app-session-only route, IP not allowed).

404trigger_not_found

No trigger with this id for the caller.

409trigger_fired

The trigger already fired; its exit is being handled.

429rate_limited

Too many requests for this credential (or too many failed attempts); retry after the Retry-After header (seconds; error.retry_after_ms has the exact wait).

502broker_refused

The broker refused the change.

503service_unavailable

A dependency is temporarily unavailable, or the feature is off on this server; retry later.

All fields (request and response schema)

Loading fields…

DELETE
curl -X DELETE "https://cirrus.pocketful.in/v1/triggers/<trigger_id>" \
  -H "Authorization: token $CIRRUS_API_KEY"
Response · 200
{
  "status": "success",
  "data": {
    "trigger_id": "365acf45-6339-46bc-b364-a834de660866",
    "deleted": true
  },
  "error": null
}