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.
Install the PentPort Python SDK.
The SDK wraps the existing V1 API so hand-rolling request helpers for common actions is not necessary.
Install
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
$env:PENTPORT_API_KEY = "pp_live_REPLACE_ME"
In macOS/Linux shells, use export PENTPORT_API_KEY="pp_live_REPLACE_ME".
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.
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)
Install
Run pip install pentport.
Authenticate
Set PENTPORT_API_KEY or pass api_key=....
Use account_hash
Call choose_account() or accounts().
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
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
)
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.
Total requests
No current lifetime cap.
Monthly requests
No current monthly cap.
Rate limit
Requests above the minute window return 429.
X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, and X-API-Monthly-Remaining. When rate limited, wait for Retry-After before trying again.
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.
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)
List available accounts and read balances, positions, and orders.
| Function | Use 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. |
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)
Get equity quotes and place stock or ETF orders.
| Function | Signature | Use 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. |
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)
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)
Get option chains and place single-leg or multi-leg option orders.
| Function | Signature | Use 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. |
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)
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)
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.
| Function | Signature | Use 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. |
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)
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)
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",
})
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.
| Function | Signature | Use 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. |
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)
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)
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,
})
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.
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")
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",
)
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.
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)
The V1 endpoints shown on this page.
These raw endpoints are still available. The Python package uses these routes under the hood.
| Method | Endpoint | Scope | Use it for |
|---|---|---|---|
| GET | /api/v1/accounts | No | List accounts, product flags, competition info, and account_hash values. |
| GET | /api/v1/usage | No | Read aggregate usage totals and the current rate-limit window. |
| GET | /api/v1/account/balance | Yes | Read balance and account details. |
| GET | /api/v1/positions | Yes | Read stock and options positions. |
| GET | /api/v1/orders | Yes | Read stock and options orders. |
| GET/POST | /api/v1/quotes | Yes, stocks | Get equity quotes. |
| GET | /api/v1/options/chain | Yes, options | Get an options chain. |
| POST | /api/v1/trades/stocks | Yes, stocks | Place stock or ETF orders. |
| POST | /api/v1/trades/options | Yes, options | Place single-leg or multi-leg option orders. |
| GET | /api/v1/predictions/featured | Yes, predictions | Featured or hot prediction markets. |
| GET | /api/v1/predictions/search | Yes, predictions | Search prediction markets. |
| GET | /api/v1/predictions/browse | Yes, predictions | Browse markets by sort/category filters. |
| GET | /api/v1/predictions/market | Yes, predictions | Get one prediction market. |
| GET/POST | /api/v1/predictions/quotes | Yes, predictions | Quote prediction token IDs. |
| GET | /api/v1/predictions/price_history | Yes, predictions | Get prediction token price history. |
| POST | /api/v1/predictions/order | Yes, predictions | Place market or limit prediction orders. |
| POST | /api/v1/predictions/close | Yes, predictions | Close prediction positions. |
| POST | /api/v1/predictions/parlay | Yes, predictions | Place prediction parlays. |
| GET | /api/v1/predictions/positions | Yes, predictions | List prediction positions. |
| GET | /api/v1/predictions/orders | Yes, predictions | List prediction orders. |
| GET | /api/v1/predictions/parlays | Yes, predictions | List prediction parlays. |
| GET | /api/v1/sports | Yes, sports | List available sports. |
| GET | /api/v1/sports/odds/<sport> | Yes, sports | Get odds for one sport. |
| POST | /api/v1/sports/bet | Yes, sports | Place moneyline, spread, or total bets. |
| POST | /api/v1/sports/parlay | Yes, sports | Place sports parlays. |
| GET | /api/v1/sports/bets | Yes, sports | List sports bets. |
| GET | /api/v1/sports/parlays | Yes, sports | List sports parlays. |
| POST | /api/v1/sports/cancel | Yes, sports | Cancel an open pre-game sports bet. |
| POST | /api/v1/sports/parlay/cancel | Yes, sports | Cancel an open pre-game sports parlay. |
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.
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()
from pentport import PentPort
pp = PentPort()
accounts = pp.accounts()
