Files
portfolio-hub/docs/api-examples.md
T

5.7 KiB

PortfolioHub API Examples

1. Purpose

This document contains example requests and responses for PortfolioHub HTTP APIs.

  • Sync rule: when files under app/api/ or app/schemas/ change, this document must be updated in the same commit/PR.
  • Companion spec: docs/portfoliohub-spec.md

2. Conventions

  • Base URL example: http://localhost:8000
  • Auth header format: Authorization: Bearer <TOKEN>
  • JSON examples are representative and may omit some optional fields.

3. Health

3.1 GET /health

Request:

curl -X GET "http://localhost:8000/health"

Response 200:

{
  "status": "ok"
}

4. Portfolios

4.1 GET /portfolios

Request:

curl -X GET "http://localhost:8000/portfolios?broker=upbit&status_filter=enabled" \
  -H "Authorization: Bearer <READ_TOKEN>"

Response 200:

[
  {
    "portfolio_id": "krw-btc",
    "broker": "upbit",
    "status": "enabled",
    "symbol": "KRW-BTC",
    "cash_balance": 1000000.0,
    "asset_quantity": 0.1,
    "price": 100000000.0,
    "profit_buffer": 0.0,
    "active_strategy_id": "stv-001",
    "avabile_strategies": ["stv-001"],
    "created_at": "2026-04-03T00:00:00Z",
    "updated_at": "2026-04-03T00:00:00Z",
    "last_trade_at": "2026-04-03T00:00:00Z",
    "total_value": 11000000.0
  }
]

4.2 GET /portfolios/{portfolio_id}

Request:

curl -X GET "http://localhost:8000/portfolios/krw-btc?recent_trades=5" \
  -H "Authorization: Bearer <READ_TOKEN>"

Response 200:

{
  "portfolio": {
    "portfolio_id": "krw-btc",
    "broker": "upbit",
    "status": "enabled",
    "symbol": "KRW-BTC",
    "cash_balance": 1000000.0,
    "asset_quantity": 0.1,
    "price": 100000000.0,
    "profit_buffer": 0.0,
    "active_strategy_id": "stv-001",
    "avabile_strategies": ["stv-001"],
    "created_at": "2026-04-03T00:00:00Z",
    "updated_at": "2026-04-03T00:00:00Z",
    "last_trade_at": "2026-04-03T00:00:00Z"
  },
  "recent_entries": [
    {
      "portfolio_id": "krw-btc",
      "recorded_at": "2026-04-03T00:00:00Z",
      "action": "buy",
      "price": 100000000.0,
      "quantity": 0.1,
      "fee_amount": 0.0,
      "tax_amount": 0.0,
      "cash_balance_after": 1000000.0,
      "asset_quantity_after": 0.1,
      "total_value_after": 11000000.0,
      "profit_buffer_after": 0.0,
      "strategy_set_id": "stv-001",
      "note": ""
    }
  ],
  "strategy_set": {
    "id": "stv-001",
    "name": "target_value",
    "config": "{}",
    "nick": "target_value:99914b932bd3",
    "created_at": "2026-04-03T00:00:00Z"
  },
  "live_quantity": null
}

4.3 POST /portfolios

Request:

curl -X POST "http://localhost:8000/portfolios" \
  -H "Authorization: Bearer <TRADE_WRITE_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "portfolio_id": "krw-btc",
    "broker": "upbit",
    "status": "enabled",
    "symbol": "KRW-BTC",
    "strategy_name": "target_value",
    "strategy_params": {},
    "active_strategy_id": null,
    "avabile_strategies": null,
    "cash_balance": 1000000,
    "asset_quantity": 0,
    "asset_price": 0,
    "profit_buffer": 0
  }'

Response 201:

  • Response body shape is PortfolioDetailResponse (same as 4.2).

4.4 PATCH /portfolios/{portfolio_id}

Request:

curl -X PATCH "http://localhost:8000/portfolios/krw-btc" \
  -H "Authorization: Bearer <TRADE_WRITE_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "broker": "upbit",
    "symbol": "KRW-BTC"
  }'

Response 200:

  • Response body shape is PortfolioDetailResponse.

4.5 POST /portfolios/{portfolio_id}/buy

Request:

curl -X POST "http://localhost:8000/portfolios/krw-btc/buy" \
  -H "Authorization: Bearer <TRADE_WRITE_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"quantity": 0.01, "price": 100000000, "fee": 0, "tax": 0, "note": ""}'

Response 200:

  • Response body shape is PortfolioDetailResponse.

4.6 POST /portfolios/{portfolio_id}/sell

Request:

curl -X POST "http://localhost:8000/portfolios/krw-btc/sell" \
  -H "Authorization: Bearer <TRADE_WRITE_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"quantity": 0.01, "price": 100000000, "fee": 0, "tax": 0, "note": ""}'

Response 200:

  • Response body shape is PortfolioDetailResponse.

4.7 POST /portfolios/{portfolio_id}/invest

Request:

curl -X POST "http://localhost:8000/portfolios/krw-btc/invest" \
  -H "Authorization: Bearer <TRADE_WRITE_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"movement_type": "deposit", "amount": 50000, "note": ""}'

Response 200:

  • Response body shape is PortfolioDetailResponse.

4.8 POST /portfolios/{portfolio_id}/transfer

Request:

curl -X POST "http://localhost:8000/portfolios/krw-btc/transfer" \
  -H "Authorization: Bearer <TRADE_WRITE_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"direction": "to-buffer", "amount": 10000, "note": ""}'

Response 200:

  • Response body shape is PortfolioDetailResponse.

4.9 POST /portfolios/{portfolio_id}/reset

Request:

curl -X POST "http://localhost:8000/portfolios/krw-btc/reset" \
  -H "Authorization: Bearer <TRADE_WRITE_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"infer_symbol": "KRW-BTC"}'

Response 200:

  • Response body shape is PortfolioDetailResponse.

4.10 DELETE /portfolios/{portfolio_id}

Request:

curl -X DELETE "http://localhost:8000/portfolios/krw-btc?keep_ledger=false" \
  -H "Authorization: Bearer <ADMIN_TOKEN>"

Response 204:

  • No content.

5. Common Error Examples

5.1 Missing token

Response 401:

{
  "detail": "Missing bearer token"
}

5.2 Invalid token

Response 401:

{
  "detail": "Invalid token"
}

5.3 Insufficient permission

Response 403:

{
  "detail": "Insufficient permission"
}