PentPort
v1 available Package: pentport Base URL: https://pentport.com JSON over HTTPS

Use PentPort with one clean Python package.

Install pentport, create a PentPort client, choose an account, then request stock quotes, options chains, prediction markets, sports odds, and place supported orders through your existing API key.

Installation

Install the PentPort Python SDK.

The SDK wraps the existing V1 API so hand-rolling request helpers for common actions is not necessary.

Install

PowerShell / Terminal
python -m pip install pentport

If the distribution name changes later, for example to pentport-sdk, the import can still stay from pentport import PentPort.

Authenticate

Environment variable
$env:PENTPORT_API_KEY = "pp_live_REPLACE_ME"

In macOS/Linux shells, use export PENTPORT_API_KEY="pp_live_REPLACE_ME".

Do not expose API keys in public frontend JavaScript. Use the Python package from a backend, private script, local automation job, notebook, or another secure environment.
Quickstart

Choose an account and make your first request.

Most requests need an account_hash. The SDK can choose the first active account that supports a product, or you can list accounts and pick one manually.

Python quickstart
from pentport import PentPort

pp = PentPort()  # reads PENTPORT_API_KEY

account = pp.choose_account("stocks")
account_hash = account["account_hash"]

print(pp.account_balance(account_hash=account_hash))
print(pp.quotes(["AAPL", "TSLA", "SPY"], account_hash=account_hash))

order = pp.buy("AAPL", 1, account_hash=account_hash)
print(order)
1

Install
Run pip install pentport.

2

Authenticate
Set PENTPORT_API_KEY or pass api_key=....

3

Use account_hash
Call choose_account() or accounts().

API flow

The whole API starts with an API key and an account_hash.

Most V1 requests target exactly one account. Get that value from accounts() or GET /api/v1/accounts, then pass it to quotes, balances, positions, orders, trades, predictions, and sports requests.

Create an API key

Go to Account Settings → API. Copy the key once and store it securely.

List accounts

Call pp.accounts(). Each account includes product flags like stocks, options, predictions, and sports.

Pick the right account

Use pp.choose_account("stocks"), pp.choose_account("options"), pp.choose_account("predictions"), or pp.choose_account("sports").

Make requests

Use the convenience methods below or the low-level request() helper for endpoints not yet wrapped by a convenience method.

Manual client setup

Python
from pentport import PentPort

pp = PentPort(
    api_key="pp_live_REPLACE_ME",      # optional if env var is set
    base_url="https://pentport.com",   # optional default
    timeout=30.0,                      # optional default is 20.0
)
Current usage limits

Unlimited requests, rate limited to 60 requests per minute.

Everyone currently has unlimited total and monthly API requests. To keep the API stable, rate limits are set to 60 requests per minute.

Unlimited

Total requests
No current lifetime cap.

Unlimited

Monthly requests
No current monthly cap.

60/min

Rate limit
Requests above the minute window return 429.

Watch the response headers: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, and X-API-Monthly-Remaining. When rate limited, wait for Retry-After before trying again.
Python package reference

Client setup and low-level helpers.

These methods are useful everywhere. Use convenience methods first, then drop down to request(), get(), or post() for custom V1 calls.

PentPort(...)

PentPort(api_key=None, *, base_url=None, timeout=20.0, session=None)

Creates a client. Reads PENTPORT_API_KEY automatically when api_key is omitted. Reads PENTPORT_BASE_URL when base_url is omitted.

choose_account()

choose_account(product="stocks")

Returns the first active account whose product flag is enabled. Valid product values include stocks, options, predictions, and sports.

request()

request(method, path, *, params=None, json=None, timeout=None)

Low-level V1 caller. Paths can be "/accounts" or "/api/v1/accounts".

get() and post()

get(path, **params) post(path, **payload)

Small shortcuts around request(). They remove None values before sending.

Client helper usage
from pentport import PentPort

pp = PentPort()

# Same endpoint, three valid styles:
usage_1 = pp.usage()
usage_2 = pp.get("/usage")
usage_3 = pp.request("GET", "/api/v1/usage")

print(usage_1)
Accounts & usage

List available accounts and read balances, positions, and orders.

FunctionUse it for
accounts()List accounts, product flags, competition info, and account_hash values.
usage()Read API tier, totals, and current rate-limit window.
account_balance(account_hash=None, competition_id=None)Read balance and account details.
positions(account_hash=None, competition_id=None)Read stock and options positions.
orders(account_hash=None, competition_id=None)Read stock and options orders.
Accounts and account state
from pentport import PentPort

pp = PentPort()

usage = pp.usage()
accounts = pp.accounts()

account = pp.choose_account("stocks")
account_hash = account["account_hash"]

balance = pp.account_balance(account_hash=account_hash)
positions = pp.positions(account_hash=account_hash)
orders = pp.orders(account_hash=account_hash)

print(usage)
print(accounts)
print(balance)
print(positions)
print(orders)
Stocks

Get equity quotes and place stock or ETF orders.

FunctionSignatureUse it for
quotes()quotes(symbols, account_hash=None, competition_id=None)Get one or more equity quotes. Pass a string like "AAPL,TSLA" or a list like ["AAPL", "TSLA"].
trade_stock()trade_stock(symbol, quantity, action, order_type="MARKET", ...)Place the full stock order payload with optional price, stop price, duration, session, and strategy fields.
buy()buy(symbol, quantity, account_hash=None, competition_id=None, order_type="MARKET", price=None)Convenience wrapper for a stock buy.
sell()sell(symbol, quantity, account_hash=None, competition_id=None, order_type="MARKET", price=None)Convenience wrapper for a stock sell.
Quotes
from pentport import PentPort

pp = PentPort()
account_hash = pp.choose_account("stocks")["account_hash"]

quotes = pp.quotes(["AAPL", "TSLA", "SPY"], account_hash=account_hash)
print(quotes)
Buy, sell, and custom order
from pentport import PentPort

pp = PentPort()
account_hash = pp.choose_account("stocks")["account_hash"]

market_buy = pp.buy("AAPL", 1, account_hash=account_hash)

limit_buy = pp.trade_stock(
    symbol="AAPL",
    quantity=5,
    action="BUY",
    order_type="LIMIT",
    price=190.00,
    duration="DAY",
    session_type="NORMAL",
    account_hash=account_hash,
)

sell_order = pp.sell("AAPL", 1, account_hash=account_hash)

print(market_buy)
print(limit_buy)
print(sell_order)
Options

Get option chains and place single-leg or multi-leg option orders.

FunctionSignatureUse it for
options_chain()options_chain(symbol, expiry=None, account_hash=None, competition_id=None)Get the options chain for an underlying symbol and optional expiration date.
trade_options()trade_options(legs, order_type="MARKET", price=None, ...)Place single-leg or multi-leg option orders.
Options chain
from pentport import PentPort

pp = PentPort()
account_hash = pp.choose_account("options")["account_hash"]

chain = pp.options_chain("AAPL", account_hash=account_hash)
chain_for_expiry = pp.options_chain(
    "AAPL",
    expiry="2026-05-15",
    account_hash=account_hash,
)

print(chain)
print(chain_for_expiry)
Option orders
from pentport import PentPort

pp = PentPort()
account_hash = pp.choose_account("options")["account_hash"]

single_leg = pp.trade_options(
    account_hash=account_hash,
    order_type="MARKET",
    duration="DAY",
    legs=[{
        "symbol": "AAPL260515C00200000",
        "instruction": "BUY_TO_OPEN",
        "quantity": 1,
        "estimatedPrice": 4.25,
    }],
)

vertical_spread = pp.trade_options(
    account_hash=account_hash,
    order_type="LIMIT",
    price=1.35,
    complex_order_strategy_type="VERTICAL",
    legs=[
        {"symbol": "AAPL260515C00195000", "instruction": "BUY_TO_OPEN", "quantity": 1, "price": 4.10},
        {"symbol": "AAPL260515C00200000", "instruction": "SELL_TO_OPEN", "quantity": 1, "price": 2.75},
    ],
)

print(single_leg)
print(vertical_spread)
Prediction markets

Discover markets, load market details, and place prediction orders.

The SDK includes convenience methods for featured/search/market/order. Use request() for additional prediction endpoints such as browse, quotes, price history, close, positions, orders, and parlays.

FunctionSignatureUse it for
predictions_featured()predictions_featured(account_hash=None, competition_id=None)Get featured or hot prediction markets.
predictions_search()predictions_search(**params)Search markets. Pass account_hash, q, and any filters as keyword arguments.
predictions_market()predictions_market(**params)Load one market by market_id or supported identifier.
prediction_order()prediction_order(**payload)Place market or limit prediction orders.
Discover and load markets
from pentport import PentPort

pp = PentPort()
account_hash = pp.choose_account("predictions")["account_hash"]

featured = pp.predictions_featured(account_hash=account_hash)
search = pp.predictions_search(account_hash=account_hash, q="election")
market = pp.predictions_market(account_hash=account_hash, market_id="MARKET_ID")

print(featured)
print(search)
print(market)
Place prediction orders
from pentport import PentPort

pp = PentPort()
account_hash = pp.choose_account("predictions")["account_hash"]

market_order = pp.prediction_order(
    account_hash=account_hash,
    provider="polymarket",
    market_id="MARKET_ID",
    slug="market-slug",
    question="Will example event happen?",
    outcome="YES",
    side="BUY",
    order_type="MARKET",
    token_id="YES_TOKEN_ID",
    stake_usd=25,
)

limit_order = pp.prediction_order(
    account_hash=account_hash,
    provider="polymarket",
    market_id="MARKET_ID",
    slug="market-slug",
    question="Will example event happen?",
    outcome="NO",
    side="BUY",
    order_type="LIMIT",
    token_id="NO_TOKEN_ID",
    stake_usd=10,
    limit_price=0.42,
)

print(market_order)
print(limit_order)
Additional prediction endpoints through request()
from pentport import PentPort

pp = PentPort()
account_hash = pp.choose_account("predictions")["account_hash"]

browse = pp.request("GET", "/predictions/browse", params={
    "account_hash": account_hash,
    "sort": "trending",
    "min_volume": 5000,
})

quotes = pp.request("GET", "/predictions/quotes", params={
    "account_hash": account_hash,
    "token_ids": "YES_TOKEN_ID,NO_TOKEN_ID",
})

history = pp.request("GET", "/predictions/price_history", params={
    "account_hash": account_hash,
    "market_id": "MARKET_ID",
    "interval": "1w",
})

positions = pp.request("GET", "/predictions/positions", params={
    "account_hash": account_hash,
})

orders = pp.request("GET", "/predictions/orders", params={
    "account_hash": account_hash,
    "status": "FILLED",
    "limit": 100,
})

close_position = pp.request("POST", "/predictions/close", json={
    "account_hash": account_hash,
    "position_id": 123,
    "qty": 5,
})

parlay = pp.request("POST", "/predictions/parlay", json={
    "account_hash": account_hash,
    "stake": 10,
    "legs": [
        {"market_id": "MARKET_ID_1", "slug": "market-one", "question": "Will event one happen?", "token_id": "YES_TOKEN_ID_1", "outcome": "YES", "odds": 0.56, "event_id": "EVENT_GROUP_1"},
        {"market_id": "MARKET_ID_2", "slug": "market-two", "question": "Will event two happen?", "token_id": "NO_TOKEN_ID_2", "outcome": "NO", "odds": 0.33, "event_id": "EVENT_GROUP_2"},
    ],
})

parlays = pp.request("GET", "/predictions/parlays", params={
    "account_hash": account_hash,
    "status": "OPEN",
})
Sports

Get sports, odds, and place supported bets.

The SDK includes convenience methods for sports discovery, odds, and single bets. Use request() for sports parlays, listing bets/parlays, and cancel endpoints.

FunctionSignatureUse it for
sports()sports(account_hash=None, competition_id=None)List available sports for the account.
sports_odds()sports_odds(sport, account_hash=None, competition_id=None)Get odds for one sport key such as nba or basketball_nba.
sports_bet()sports_bet(**payload)Place moneyline, spread, or total bets.
Sports and odds
from pentport import PentPort

pp = PentPort()
account_hash = pp.choose_account("sports")["account_hash"]

sports = pp.sports(account_hash=account_hash)
nba_odds = pp.sports_odds("nba", account_hash=account_hash)
canonical_odds = pp.sports_odds("basketball_nba", account_hash=account_hash)

print(sports)
print(nba_odds)
print(canonical_odds)
Single sports bets
from pentport import PentPort

pp = PentPort()
account_hash = pp.choose_account("sports")["account_hash"]

moneyline_bet = pp.sports_bet(
    account_hash=account_hash,
    event_id="401705000",
    sport="basketball_nba",
    league="NBA",
    home_team="New York Knicks",
    away_team="Boston Celtics",
    event_start_time="2026-04-30T23:00:00Z",
    bet_type="moneyline",
    selection="home",
    team_name="New York Knicks",
    odds=120,
    stake=25,
)

spread_bet = pp.sports_bet(
    account_hash=account_hash,
    event_id="401705000",
    sport="basketball_nba",
    league="NBA",
    home_team="New York Knicks",
    away_team="Boston Celtics",
    event_start_time="2026-04-30T23:00:00Z",
    bet_type="spread",
    selection="away",
    team_name="Boston Celtics -3.5",
    odds=-110,
    stake=25,
    line=-3.5,
)

print(moneyline_bet)
print(spread_bet)
Sports parlays, lists, and cancels through request()
from pentport import PentPort

pp = PentPort()
account_hash = pp.choose_account("sports")["account_hash"]

sports_parlay = pp.request("POST", "/sports/parlay", json={
    "account_hash": account_hash,
    "stake": 10,
    "legs": [
        {"event_id": "401705000", "sport": "basketball_nba", "league": "NBA", "home_team": "New York Knicks", "away_team": "Boston Celtics", "event_start_time": "2026-04-30T23:00:00Z", "bet_type": "moneyline", "selection": "home", "team_name": "New York Knicks", "odds": 120},
        {"event_id": "401705001", "sport": "basketball_nba", "league": "NBA", "home_team": "Los Angeles Lakers", "away_team": "Denver Nuggets", "event_start_time": "2026-04-30T02:00:00Z", "bet_type": "spread", "selection": "away", "team_name": "Denver Nuggets -4.5", "line": -4.5, "odds": -110},
    ],
})

sports_bets = pp.request("GET", "/sports/bets", params={
    "account_hash": account_hash,
    "status": "OPEN",
    "sport": "basketball_nba",
})

sports_parlays = pp.request("GET", "/sports/parlays", params={
    "account_hash": account_hash,
    "status": "OPEN",
})

cancel_bet = pp.request("POST", "/sports/cancel", json={
    "account_hash": account_hash,
    "bet_id": 123,
})

cancel_parlay = pp.request("POST", "/sports/parlay/cancel", json={
    "account_hash": account_hash,
    "parlay_id": 456,
})
Raw V1 requests

Call any V1 endpoint through the package.

The package does not need a dedicated convenience method for every API route. Use request(), get(), or post() to call the V1 API directly with SDK auth and error handling.

GET endpoint
from pentport import PentPort

pp = PentPort()
account_hash = pp.choose_account("stocks")["account_hash"]

quotes = pp.request("GET", "/quotes", params={
    "account_hash": account_hash,
    "symbols": "AAPL,TSLA,SPY",
})

# Equivalent shortcut:
quotes_again = pp.get("/quotes", account_hash=account_hash, symbols="AAPL,TSLA,SPY")
POST endpoint
from pentport import PentPort

pp = PentPort()
account_hash = pp.choose_account("stocks")["account_hash"]

order = pp.request("POST", "/trades/stocks", json={
    "account_hash": account_hash,
    "symbol": "AAPL",
    "quantity": 1,
    "action": "BUY",
    "orderType": "MARKET",
    "assetType": "EQUITY",
    "duration": "DAY",
    "session": "NORMAL",
})

# Equivalent shortcut:
order_again = pp.post(
    "/trades/stocks",
    account_hash=account_hash,
    symbol="AAPL",
    quantity=1,
    action="BUY",
    orderType="MARKET",
)
Errors

Handle API errors and rate limits cleanly.

The SDK raises structured exceptions for non-2xx responses, ok=false payloads, and rate limits.

PentPortError

Base exception for SDK errors.

PentPortAPIError

Raised when the API returns an error response. Useful attributes: status_code, error, data, and headers.

PentPortRateLimitError

Raised for HTTP 429. Use retry_after_seconds to read the retry delay when provided.

Error handling
from pentport import PentPort
from pentport.exceptions import PentPortAPIError, PentPortRateLimitError

pp = PentPort()

try:
    account_hash = pp.choose_account("stocks")["account_hash"]
    print(pp.quotes(["AAPL", "TSLA"], account_hash=account_hash))
except PentPortRateLimitError as exc:
    print("Rate limited. Retry after:", exc.retry_after_seconds)
    print("Response data:", exc.data)
except PentPortAPIError as exc:
    print("API error:", exc.status_code, exc.error)
    print("Response data:", exc.data)
Endpoint reference

The V1 endpoints shown on this page.

These raw endpoints are still available. The Python package uses these routes under the hood.

MethodEndpointScopeUse it for
GET/api/v1/accountsNoList accounts, product flags, competition info, and account_hash values.
GET/api/v1/usageNoRead aggregate usage totals and the current rate-limit window.
GET/api/v1/account/balanceYesRead balance and account details.
GET/api/v1/positionsYesRead stock and options positions.
GET/api/v1/ordersYesRead stock and options orders.
GET/POST/api/v1/quotesYes, stocksGet equity quotes.
GET/api/v1/options/chainYes, optionsGet an options chain.
POST/api/v1/trades/stocksYes, stocksPlace stock or ETF orders.
POST/api/v1/trades/optionsYes, optionsPlace single-leg or multi-leg option orders.
GET/api/v1/predictions/featuredYes, predictionsFeatured or hot prediction markets.
GET/api/v1/predictions/searchYes, predictionsSearch prediction markets.
GET/api/v1/predictions/browseYes, predictionsBrowse markets by sort/category filters.
GET/api/v1/predictions/marketYes, predictionsGet one prediction market.
GET/POST/api/v1/predictions/quotesYes, predictionsQuote prediction token IDs.
GET/api/v1/predictions/price_historyYes, predictionsGet prediction token price history.
POST/api/v1/predictions/orderYes, predictionsPlace market or limit prediction orders.
POST/api/v1/predictions/closeYes, predictionsClose prediction positions.
POST/api/v1/predictions/parlayYes, predictionsPlace prediction parlays.
GET/api/v1/predictions/positionsYes, predictionsList prediction positions.
GET/api/v1/predictions/ordersYes, predictionsList prediction orders.
GET/api/v1/predictions/parlaysYes, predictionsList prediction parlays.
GET/api/v1/sportsYes, sportsList available sports.
GET/api/v1/sports/odds/<sport>Yes, sportsGet odds for one sport.
POST/api/v1/sports/betYes, sportsPlace moneyline, spread, or total bets.
POST/api/v1/sports/parlayYes, sportsPlace sports parlays.
GET/api/v1/sports/betsYes, sportsList sports bets.
GET/api/v1/sports/parlaysYes, sportsList sports parlays.
POST/api/v1/sports/cancelYes, sportsCancel an open pre-game sports bet.
POST/api/v1/sports/parlay/cancelYes, sportsCancel an open pre-game sports parlay.
Migration notes

Replace custom request helpers with SDK methods.

Old raw HTTP examples still work, but the package keeps auth, base URL handling, JSON parsing, and error handling in one place.

Before: raw requests
import os
import requests

response = requests.get(
    "https://pentport.com/api/v1/accounts",
    headers={"Authorization": f"Bearer {os.environ['PENTPORT_API_KEY']}"},
    timeout=20,
)
accounts = response.json()
After: pentport package
from pentport import PentPort

pp = PentPort()
accounts = pp.accounts()