Stockbit Research research Playground @hansputera

Trading Operations

Overview

Stockbit's trading backend is at carina.stockbit.com, a separate service from the main API. It uses its own JWT token (obtained via PIN-authenticated login) and manages equity orders through Sinarmas Sekuritas.

See Carina REST API for the complete endpoint reference. This document covers the operational flow, lifecycle, and constraints.

Order Flow

1. Check Balance ─── GET /balance/cash
2. Check Portfolio  GET /portfolio/v2/summary
3. Check Price ───── GET /orderbook/companies/{code} (via Exodus API)
4. Place Order ───── POST /order/v2/buy|sell
5. Monitor ───────── GET /order/v2/list + WebSocket (order_queue, liveprice)
6. Amend/Cancel ──── POST /order/v2/amend|cancel
7. Settlement ────── GET /order/history/v4

Balance & Portfolio

Get Cash Balance

GET /balance/cash
Authorization: Bearer <trading_token>

Response:
{ "data": { "available_cash_on_hand": 99750.80 } }

Get Portfolio Summary

GET /portfolio/v2/summary

Response:
{
  "data": {
    "aggregated_portfolio_summary": {
      "trading": { "balance": 99750.8 },
      "amount": { "invested": 4063286.306, "allocated": 0, "credit_limit": 99750.8 },
      "profit_loss": { "net": -1877769.306, "unrealised": -1877769.306, "realised": 0 },
      "gain": -0.451, "equity": 2285267.8,
      "debt": { "ratio": 0, "total": 0, "market_value": 0 }
    }
  }
}

Placing Orders

Buy/Sell Order (v2)

POST /order/v2/buy
{
  "symbol": "BUMI",
  "price": 148,
  "shares": 100,
  "board_type": "RG"
}
Field Type Required Values
symbol String Yes Stock code
price Integer Yes Price in Rupiah per share
shares Integer Yes Number of shares (100 = 1 lot)
board_type String Yes "RG" (Reguler), "NG" (Negosiasi), "TN" (Tunai)
is_gtc Boolean No Good-Till-Cancelled
time_in_force String No "0" (GoodForDay)
split_order Boolean No Auto-split across sub-accounts
platform_order_type String No "PLATFORM_ORDER_TYPE_LIMIT_DAY"

ui_ref is auto-generated by the client (W<timestamp><13 random chars>).

Amend Order

POST /order/v2/amend
{
  "order_id": "XL2778867...",
  "symbol": "BUMI",
  "price": 150,
  "shares": 100,
  "board_type": "RG"
}

Cancel Order

POST /order/v2/cancel
{ "order_id": "XL2778867..." }

Order Status Lifecycle

         ┌──────────┐
           SUBMIT  
         └────┬─────┘
              
         ┌────▼─────┐
            OPEN   │◄──── AMEND
         └────┬─────┘
              
       ┌──────┴──────┐
                     
  ┌──────────┐  ┌───────────┐
   PARTIAL     WITHDRAWN 
    MATCH      (CANCEL)  
  └────┬─────┘  └───────────┘
       
  ┌────▼─────┐
    FULL    
    MATCH   
  └──────────┘

Status values: READY, PENDING, OPEN, PARTIAL, MATCH, AMENDED, WITHDRAWN, REJECTED, EXPIRED

Real-time Order Monitoring (WebSocket)

Subscribe to the order_queue channel to monitor orders in real-time:

message OrderQueueWebsocketRequest {
    string stock_code = 1;
    double price = 2;
    BoardType board_type = 3;
    ActionType action_type = 4;
}

Sends updates on: OPEN, PARTIAL_MATCH, FULL_MATCH, WITHDRAWN, AMEND.

Trading PIN

The 6-digit trading PIN is required for: - Login: POST /auth/v2/login { login_token, pin } - Change PIN: POST /auth/pin/change - Validate PIN: POST /auth/pin/validate - Reset PIN: Multi-step OTP flow via /auth/v2/pin/reset/*

Fee Structure

Fee Type Percentage Description
Broker Buy Fee ~0.15% - 0.30% Broker commission on buy
Broker Sell Fee ~0.25% - 0.40% Broker commission on sell
VAT 11% VAT on broker fee
IDX Levy 0.01% Exchange transaction levy
KPEI Levy 0.01% Clearing guarantee

Limits & Restrictions

Example

# 1. Get trading token
sekuritas_token = requests.get(
    "https://exodus.stockbit.com/sekuritas/auth/token",
    headers={"Authorization": f"Bearer {main_token}"}
).json()["data"]["token"]

resp = requests.post("https://carina.stockbit.com/auth/v2/login",
    json={"login_token": sekuritas_token, "pin": "YOUR_TRADING_PIN"})
trading_token = resp.json()["data"]["access_token"]

headers = {"Authorization": f"Bearer {trading_token}"}

# 2. Check balance
r = requests.get("https://carina.stockbit.com/balance/cash", headers=headers)
print(f"Cash: Rp {r.json()['data']['available_cash_on_hand']:,}")

# 3. Place buy order (1 lot at Rp 148)
r = requests.post("https://carina.stockbit.com/order/v2/buy",
    json={"symbol": "BUMI", "price": 148, "shares": 100, "board_type": "RG"},
    headers={**headers, "Content-Type": "application/json"})
order_id = r.json()["data"]["order_id"]
print(f"Order placed: {order_id}")

# 4. Cancel the order
requests.post("https://carina.stockbit.com/order/v2/cancel",
    json={"order_id": order_id},
    headers={**headers, "Content-Type": "application/json"})