Skip to main content

Python SDK for the Rangler API.

Project description

ranglerpy

ranglerpy is a Python SDK for the Rangler API.

It is designed around the actual Rangler product shape:

  • polling-first event consumption
  • optional webhook verification helpers

The goal is to make Rangler easy to integrate whether you want to:

  • poll event feeds with a cursor
  • consume companies and filings directly
  • create Connect link tokens and read customer portfolio data
  • verify Rangler webhook signatures in a receiver

It is designed to give you one integration surface across:

  • polling feeds
  • Connect data-plane workflows
  • webhook receivers

Installation

With uv:

uv add ranglerpy

With pip:

pip install ranglerpy

For local development:

pip install -e .[dev]

For release builds:

python scripts/update_version.py 0.1.5
python -m unittest discover -s tests -v
uv build --no-sources
export UV_PUBLISH_TOKEN=pypi-your-project-token
uv publish --token "$UV_PUBLISH_TOKEN" dist/*

For local checks with the PyPA tools:

pip install -e .[build]
python -m build
python -m twine check dist/*

Quick start

Data plane: polling events

from ranglerpy import InMemoryCursorStore, PollingConsumer, RanglerClient

client = RanglerClient(
    api_key="rgl_test_your_api_key",
    environment="sandbox",
)

consumer = PollingConsumer(
    client.v1.events,
    cursor_store=InMemoryCursorStore(),
    stream="market-wide-filings",
)

for event in consumer.poll(event_types=["filing.new"], limit=100):
    print(event.id, event.type, event.occurred_at.isoformat())

Async polling

from ranglerpy import AsyncPollingConsumer, AsyncRanglerClient, FileCursorStore

async with AsyncRanglerClient(
    api_key="rgl_test_your_api_key",
    environment="sandbox",
) as client:
    consumer = AsyncPollingConsumer(
        client.v1.events,
        cursor_store=FileCursorStore(".rangler-cursors.json"),
        stream="issuer-monitoring",
    )

    for event in await consumer.poll(
        limit=100,
        event_types=["filing.new"],
    ):
        print(event.id, event.type)

Data plane: Connect

from ranglerpy import RanglerClient

client = RanglerClient(
    api_key="rgl_test_your_api_key",
    environment="sandbox",
)

link_token = client.connect.create_link_token(
    client_user_id="customer_123",
    allowed_origins=["https://app.example.com"],
    products=["accounts", "positions", "transactions"],
    idempotency_key="customer_123-connect-link",
)

connections = client.connect.list_connections(client_user_id="customer_123")
portfolio = client.connect.get_portfolio(client_user_id="customer_123")

print(link_token["link_token"], len(connections["data"]), portfolio["totals"])

Webhook verification

from ranglerpy import InMemoryIdempotencyStore, Webhook

idempotency_store = InMemoryIdempotencyStore()

event = Webhook.construct_event(
    headers=headers,
    raw_body=raw_body,
    secret=webhook_secret,
    idempotency_store=idempotency_store,
)

print(event.type, event.display.title, event.data.object.id)

FastAPI webhook handler

from fastapi import FastAPI, HTTPException, Request

from ranglerpy import DuplicateEventError, InMemoryIdempotencyStore, InvalidSignatureError, Webhook

app = FastAPI()
store = InMemoryIdempotencyStore()


@app.post("/rangler/webhooks")
async def rangler_webhook(request: Request):
    raw_body = await request.body()

    try:
        event = Webhook.construct_event(
            headers=request.headers,
            raw_body=raw_body,
            secret="whsec_your_secret",
            idempotency_store=store,
        )
    except InvalidSignatureError as exc:
        raise HTTPException(status_code=400, detail=str(exc)) from exc
    except DuplicateEventError:
        return {"duplicate": True}

    return {"received": event.id}

Flask webhook handler

from flask import Flask, jsonify, request

from ranglerpy import DuplicateEventError, InMemoryIdempotencyStore, InvalidSignatureError, Webhook

app = Flask(__name__)
store = InMemoryIdempotencyStore()


@app.post("/rangler/webhooks")
def rangler_webhook():
    raw_body = request.get_data()

    try:
        event = Webhook.construct_event(
            headers=request.headers,
            raw_body=raw_body,
            secret="whsec_your_secret",
            idempotency_store=store,
        )
    except InvalidSignatureError as exc:
        return jsonify({"error": str(exc)}), 400
    except DuplicateEventError:
        return jsonify({"duplicate": True}), 200

    return jsonify({"received": event.id})

Authentication

ranglerpy uses X-API-Key authentication for public API operations.

Current SDK scope

Data plane

  • companies
  • Connect accounts, positions, transactions, portfolio, and link tokens
  • filings
  • funds
  • event feeds

Helpers

  • cursor-based event iteration
  • Stripe-style client.v1.* namespace
  • list responses with data
  • dynamic object access for webhook/API payloads, e.g. event.data.object.id
  • polling consumer with checkpoint persistence
  • Rangler webhook signature verification
  • Webhook.construct_event(...) for webhook receivers
  • in-memory idempotency helper for duplicate webhook handling
  • async client support

Example scripts

The repo includes runnable examples in examples/:

These are intentionally small. They are meant to be copied into a real worker, cron job, or receiver and then adapted to your own storage and job queue.

Notes

This first version is intentionally thin. It aims to give Rangler customers one integration surface across polling and webhooks instead of pushing everyone straight into raw HTTP and receiver boilerplate.

You can override base_url explicitly if you need to point the SDK at a different Rangler environment.

The package version is tracked in VERSION, pyproject.toml, and src/ranglerpy/_version.py. The API contract version is tracked separately in src/ranglerpy/_api_version.py.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ranglerpy-0.1.5.tar.gz (19.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ranglerpy-0.1.5-py3-none-any.whl (21.5 kB view details)

Uploaded Python 3

File details

Details for the file ranglerpy-0.1.5.tar.gz.

File metadata

  • Download URL: ranglerpy-0.1.5.tar.gz
  • Upload date:
  • Size: 19.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.17

File hashes

Hashes for ranglerpy-0.1.5.tar.gz
Algorithm Hash digest
SHA256 5823fda46a6e9dac0d81433dde335cabf3c88528ba6b4b499fe5b37805d9b819
MD5 cdaa7ea1fefdd94652559df743c0f0bc
BLAKE2b-256 09201ef471a573d2716ffcd499c6223287fc598a10c74b9a0a19d3f72fdc22be

See more details on using hashes here.

File details

Details for the file ranglerpy-0.1.5-py3-none-any.whl.

File metadata

  • Download URL: ranglerpy-0.1.5-py3-none-any.whl
  • Upload date:
  • Size: 21.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.17

File hashes

Hashes for ranglerpy-0.1.5-py3-none-any.whl
Algorithm Hash digest
SHA256 4447417afbe2fcaf741fe08d58f592e7b3fb8106f6b9c95e15ecf1a3c7267dd5
MD5 438fe95a181182bae61e5df8970727b8
BLAKE2b-256 95b4881898bf763a3c99275e7e3f0d25fd6e62e1644b36efdddde201475c7901

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page