A safety layer for AI agents that trade
For people who already use an AI agent for trading or stocks. AgentRaaS doesn't recommend trading, pick trades or trade for anyone; it keeps your agent in bounds. An agent whose order request times out will often send it again, and buy twice. AgentRaaS sits between your agent and your broker: each order runs once, limits and allowed symbols are checked before the broker sees the order, large orders wait for a person, and every order is in the audit trail.
Set up the guardrailsSelf-host itWhat it stops
| What goes wrong | What AgentRaaS does |
|---|---|
| A retried order fills twice | The same order runs once; a repeat gets the first answer back. |
| The agent sizes an order wrong | An action policy caps qty and notional, and blocks the order before it is sent. |
| It trades something it shouldn't | A policy lists the symbols and order types it may use. |
| A large order needs a second look | Above a limit, the order waits for a person to approve it in Slack, Teams, Telegram or email (Team plan). |
| It loops, or trades too much in a day | A spend cap limits orders per day and the total notional per day. |
| It trades when the market is closed | A policy's hours allow orders only during market hours, in the market's own time zone. |
| It closes everything at once | A policy denies positions.close_all for that agent. |
| You need to know what happened | Every order, sent or refused, is in the audit trail with the reason. |
Connect Alpaca
In the dashboard, Connect a service, pick Alpaca (paper trading) and paste the paper account's API key ID and secret. Your agent then sends orders to AgentRaaS instead of to Alpaca:
curl -X POST https://agentraas.io/v1/webhook/org_acme/trader \
-H "Authorization: Bearer ar_live_..." \
-H "Content-Type: application/json" \
-d '{
"service": "alpaca_paper",
"action": "order.create",
"payload": { "symbol": "AAPL", "qty": "1", "side": "buy", "type": "market",
"time_in_force": "day", "client_order_id": "run-42-buy-aapl" }
}'
| Action | Alpaca call |
|---|---|
order.create | POST /v2/orders |
order.replace | PATCH /v2/orders/{order_id} |
order.cancel | DELETE /v2/orders/{order_id} |
orders.cancel_all | DELETE /v2/orders |
position.close | DELETE /v2/positions/{symbol} |
positions.close_all | DELETE /v2/positions |
Use alpaca instead of alpaca_paper for the live account. Send a client_order_id that stays the same when your agent retries: Alpaca refuses a second order with the same one, which covers a retry that reaches Alpaca some other way. Undo (dashboard, Monitor) cancels an order that has not filled yet; a filled order needs an opposite order.
Guardrails as code
Apply these with agentraas apply -f trading.yaml (see Rules as code), then change the numbers to yours:
# trading.yaml
apiVersion: agentraas.io/v1alpha1
kind: DedupRule
metadata: {name: same-order-once, org: org_acme}
spec: {service: alpaca_paper, action: order.create, fields: [symbol, side, qty, notional], ttlSeconds: 60}
---
apiVersion: agentraas.io/v1alpha1
kind: ActionPolicy
metadata: {name: hard-limits, org: org_acme}
spec: {agentId: trader, service: alpaca_paper, action: order.create, effect: require,
fields: {symbol: {enum: [AAPL, MSFT, SPY]}, type: {enum: [market, limit]}, qty: {max: 10}, notional: {max: 5000}},
hours: {tz: America/New_York, days: [mon, tue, wed, thu, fri], from: "09:30", to: "16:00"}}
---
apiVersion: agentraas.io/v1alpha1
kind: ActionPolicy
metadata: {name: never-liquidate-all, org: org_acme}
spec: {agentId: trader, service: alpaca_paper, action: positions.close_all, effect: deny}
---
apiVersion: agentraas.io/v1alpha1
kind: SpendCap
metadata: {name: daily-limits, org: org_acme}
spec: {agentId: trader, service: alpaca_paper, action: order.create, window: day, timezone: America/New_York,
maxCalls: 20, amountField: notional, maxAmount: 10000, onExceed: block}
Then add the approval step (Team plan) in the dashboard under Rules → Approval rules: service alpaca_paper, action order.create, field notional greater than 1000.
Together: the same order inside a minute runs once; orders above $5,000, more than 10 shares, or off the list are blocked; orders outside 09:30 to 16:00 New York time on weekdays are blocked; orders above $1,000 that pass those wait for approval; after 20 orders or $10,000 in a New York day, the rest are blocked. Limits hold whether the agent sends "notional": 500 or "notional": "500". The daily total needs notional on every order: an order by qty alone is refused by that cap, so have your agent size orders in dollars.
India (NSE/BSE)
Two Indian brokers are built in: upstox (Upstox API, order endpoints v3) and dhan (DhanHQ API v2). Each has order.place, order.modify and order.cancel, and undo on order.place cancels the order if it has not filled yet.
| Action | Upstox call | Dhan call |
|---|---|---|
order.place | POST /v3/order/place | POST /v2/orders |
order.modify | PUT /v3/order/modify | PUT /v2/orders/{order_id} |
order.cancel | DELETE /v3/order/cancel?order_id=... | DELETE /v2/orders/{order_id} |
Field names are the broker's own: Upstox takes instrument_token (for example NSE_EQ|INE002A01018), transaction_type, product (D is delivery), order_type, validity, quantity, price and a tag of up to 40 characters. Dhan takes dhanClientId, transactionType, exchangeSegment, productType (CNC is delivery), orderType, validity, securityId, quantity, price and a correlationId of up to 30 characters. Dhan's order.modify takes the order id twice: order_id for the URL and orderId for the body. Undo on an Upstox order cancels the first order id it returns, so don't use Upstox's slice with undo.
SEBI's framework for retail algo trading (in effect since April 1, 2026, per the brokers' notices) changes how an API order reaches the exchange:
- Orders must come from a static IP that you have registered with the broker.
- You log in every trading day: the access token is good for one day (Upstox: until 3:30 AM the next day; Dhan: 24 hours).
- Exchange algo IDs are handled by the broker, not by AgentRaaS.
So live Indian orders need self-hosted AgentRaaS on a server with a static IP, registered with your broker. AgentRaaS Cloud has no fixed outbound IP, so the broker would refuse its orders.
Save the new token every morning
Get the day's token from your broker (Dhan can issue one from your client ID, PIN and TOTP; Upstox through its login flow), then save it to AgentRaaS. Saving a credential for a service replaces the one stored before it, so a scheduled script like this before 09:15 is enough:
# AGENTRAAS_URL is your self-hosted AgentRaaS, BROKER_TOKEN the day's token
curl -s -c /tmp/ar.jar -X POST "$AGENTRAAS_URL/api/v1/auth/login" \
-H "Content-Type: application/json" \
-d "{\"email\": \"$AGENTRAAS_EMAIL\", \"password\": \"$AGENTRAAS_PASSWORD\"}"
curl -s -b /tmp/ar.jar -X POST "$AGENTRAAS_URL/api/v1/credentials" \
-H "Content-Type: application/json" \
-d "{\"org_id\": \"org_acme\", \"service\": \"dhan\", \"credentials\": {\"api_key\": \"$BROKER_TOKEN\"}}"
Guardrails for NSE cash equity
# india.yaml
apiVersion: agentraas.io/v1alpha1
kind: ActionPolicy
metadata: {name: nse-delivery-only, org: org_acme}
spec: {agentId: trader, service: dhan, action: order.place, effect: require,
fields: {exchangeSegment: {enum: [NSE_EQ]}, productType: {enum: [CNC]}, orderType: {enum: [LIMIT]},
securityId: {enum: ["11536"]}, price: {required: true, max: 5000}},
hours: {tz: Asia/Kolkata, days: [mon, tue, wed, thu, fri], from: "09:15", to: "15:30"}}
---
apiVersion: agentraas.io/v1alpha1
kind: SpendCap
metadata: {name: daily-size, org: org_acme}
spec: {agentId: trader, service: dhan, action: order.place, window: day, timezone: Asia/Kolkata,
maxCalls: 20, amountField: quantity, maxAmount: 40, onExceed: block}
Together: only delivery (CNC) limit orders in NSE cash for the listed securities, so F&O segments (NSE_FNO, BSE_FNO) and intraday are blocked; only from 09:15 to 15:30 India time on weekdays (exchange holidays are not known to AgentRaaS); at most 20 orders and 40 shares a day, India time. An Indian order has no order-value field, so the daily rupee limit comes from the two: 40 shares at a price of at most ₹5,000 is at most ₹2,00,000 a day. For Upstox the same rules use instrument_token (list the NSE_EQ|... keys you allow, which also keeps out F&O), product: {enum: [D]} and order_type: {enum: [LIMIT]}.
This is not investment or legal advice. SEBI's and your broker's rules change: check the current ones before you trade live.
Before you go live
- Run on paper first, with the same rules you plan to use live.
- For live keys, self-host: your broker keys then never leave your servers.
- AgentRaaS does not give trading advice and does not trade for you; your agent places orders with your own broker account. Automated trading can have its own rules where you live and at your broker: check them before going live.
Using another broker?
Any broker with an HTTP API works today as a Custom Action, with the same dedup, policies and approvals. Tell us which one you want built in.
Ask in the communityCustom actions