Installation

pip install rulebook-sdk
Requires Python 3.11+. The SDK depends on httpx and pydantic.

Initialize the Client

from rulebook import Rulebook

client = Rulebook(api_key="your-api-key")
Or set the RULEBOOK_API_KEY environment variable and omit the parameter:
export RULEBOOK_API_KEY="your-api-key"
from rulebook import Rulebook

client = Rulebook()  # reads from RULEBOOK_API_KEY
You can also override the base URL via the RULEBOOK_BASE_URL environment variable:
export RULEBOOK_BASE_URL="https://your-custom-endpoint/api/v1"

List Exchanges

response = client.exchanges.list()

for ex in response.data:
    print(f"{ex.name} ({ex.display_name})")
    print(f"  Fee types: {ex.fee_types}")
    print(f"  Records: {ex.record_count}")

print(f"Total exchanges: {response.meta.record_count}")
Response type: ExchangeListResponse
FieldTypeDescription
datalist[Exchange]Array of exchange objects
metaMetaResponse metadata

Get Exchange Details

response = client.exchanges.retrieve("nasdaq")

detail = response.data
print(f"Date range: {detail.date_range.earliest} to {detail.date_range.latest}")
print(f"Actions: {detail.actions}")
print(f"Participants: {detail.participants}")
print(f"Fee categories: {detail.fee_categories}")
print(f"Query time: {response.meta.query_time_ms}ms")
Response type: ExchangeDetailResponse
FieldTypeDescription
dataExchangeDetailExchange detail object
metaMetaResponse metadata

List Fee Schedule Results

page = client.fee_schedule_results.list(
    exchange_name=["nasdaq"],
    fee_type=["option"],
    fee_participant=["market_maker"],
    latest_only=True,
    page_size=10,
)

print(f"Total results: {page.meta.record_count}")
for result in page.data:
    print(f"  {result.fee_action}: {result.fee_amount} ({result.fee_symbol_type})")
Response type: PaginatedResponse[FeeScheduleResult]
FieldTypeDescription
datalist[FeeScheduleResult]Array of result objects
metaMetaPagination metadata
Filter parameters:
ParameterTypeDescription
exchange_namelist[str]Filter by exchange name(s)
fee_typelist[str]Filter by fee type(s)
fee_categorylist[str]Filter by fee category(s)
fee_actionlist[str]Filter by trading action(s)
fee_participantlist[str]Filter by participant type(s)
fee_symbol_classificationlist[str]Filter by symbol classification(s)
fee_symbol_typelist[str]Filter by symbol type(s)
fee_trade_typelist[str]Filter by trade type(s)
start_datestrFilter by scraped date (YYYY-MM-DD)
end_datestrFilter by scraped date (YYYY-MM-DD)
latest_onlyboolOnly latest version per exchange
include_footnotesboolInclude footnotes in relationships
include_definitionsboolInclude definitions in relationships
include_sourceboolInclude source_document, source_link, page_number
order_bystrSort field (default: created_on)
order_dirstrSort direction: asc or desc
page_sizeintRecords per page (1–100)
page_numberintPage number (0-indexed)

Get a Single Fee Schedule Result

response = client.fee_schedule_results.retrieve(
    "a3d76e96-0cad-4ece-9db1-7ad3c743bdf8",
    include_footnotes=True,
    include_definitions=True,
    include_source=True,
)

result = response.data
print(f"{result.exchange_name}{result.fee_type}{result.fee_category}")
print(f"  Action: {result.fee_action}")
print(f"  Amount: {result.fee_amount}")
print(f"  Participant: {result.fee_participant}")
print(f"  Source: {result.source_document} (p.{result.page_number})")
print(f"Query time: {response.meta.query_time_ms}ms")

if result.relationships:
    for fn in result.relationships.footnotes:
        print(f"  Footnote: {fn.text}")
    for defn in result.relationships.definitions:
        print(f"  Definition: {defn.term}{defn.text}")
ParameterTypeDefaultDescription
include_footnotesboolFalseInclude footnotes in relationships
include_definitionsboolFalseInclude definitions in relationships
include_sourceboolFalseInclude source_document, source_link, page_number
Response type: FeeScheduleResultResponse
FieldTypeDescription
dataFeeScheduleResultFee schedule result object
metaMetaResponse metadata

Get Available Filters

Discover valid filter values before querying results:
response = client.fee_schedule_results.get_filters()

filters = response.data
print(f"Exchanges: {filters.exchange_names}")
print(f"Fee types: {filters.fee_types}")
print(f"Categories: {filters.fee_categories}")
print(f"Actions: {filters.fee_actions}")
print(f"Participants: {filters.fee_participants}")
print(f"Total records: {response.meta.record_count}")
Optionally narrow filter values to specific exchanges:
response = client.fee_schedule_results.get_filters(
    exchange_name=["nasdaq", "nasdaq_phlx"]
)
Response type: FeeScheduleResultFiltersResponse
FieldTypeDescription
dataFeeScheduleResultFiltersFilter values object
metaMetaResponse metadata

Get Results by Version

Retrieve all fee schedule results from a specific extraction version:
page = client.fee_schedule_results.get_results_by_version(
    "b962c0b1-5d99-4ef6-b3f6-36cb18c08933",
    include_source=True,
    include_footnotes=True,
    page_size=50,
)

print(f"Version has {page.meta.record_count} results ({page.meta.total_pages} pages)")
for result in page.data:
    print(f"  {result.fee_action}: {result.fee_amount}")
    if result.source_document:
        print(f"    Source: {result.source_document} (p.{result.page_number})")
Response type: PaginatedResponse[FeeScheduleResult]
FieldTypeDescription
datalist[FeeScheduleResult]Array of result objects
metaMetaPagination metadata

Pagination

Fee schedule results are paginated. Use page_number and page_size to iterate:
page_number = 0
total_fetched = 0

while True:
    page = client.fee_schedule_results.list(
        latest_only=True,
        page_size=50,
        page_number=page_number,
    )
    total_fetched += len(page.data)
    print(f"Page {page_number + 1}/{page.meta.total_pages}: {len(page.data)} results")

    if page_number >= page.meta.total_pages - 1:
        break
    page_number += 1

print(f"Fetched {total_fetched} of {page.meta.record_count} total results")

Async Client

import asyncio
from rulebook import AsyncRulebook

async def main():
    async with AsyncRulebook(api_key="your-key") as client:
        exchanges = await client.exchanges.list()
        detail = await client.exchanges.retrieve("nasdaq")

        page = await client.fee_schedule_results.list(
            exchange_name=["nasdaq"],
            latest_only=True,
        )
        filters = await client.fee_schedule_results.get_filters()

asyncio.run(main())
The async client has an identical API surface — every method is await-able.

Context Manager

Both clients support context managers for automatic cleanup:
with Rulebook(api_key="your-key") as client:
    exchanges = client.exchanges.list()
# Connection pool is cleaned up here

Next Steps

Error Handling

Handle API errors with typed exceptions

Advanced Usage

Timeouts, retries, raw responses, and per-request overrides