Metadata-Version: 2.4
Name: resultsza-sdk
Version: 0.1.0
Summary: Thin Python client and webhook-receiver toolkit for the ResultsZA API (lottery & horse racing results). Unofficial.
Project-URL: Homepage, https://resultsza.co.za
Project-URL: Documentation, https://resultsza.co.za/api_docs
Project-URL: API Keys, https://resultsza.co.za/generate_api_key
Project-URL: Webhook Docs, https://resultsza.co.za/webhook-docs
Author: Stefan
License: MIT
License-File: LICENSE
Keywords: api,euromillions,horse-racing,lottery,lotto,powerball,resultsza,sdk,south-africa,uk49s,webhook
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.9
Requires-Dist: httpx>=0.24
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: respx>=0.20; extra == 'dev'
Description-Content-Type: text/markdown

# resultsza-sdk (Python)

Thin Python client for the [ResultsZA API](https://resultsza.co.za/api_docs) - lottery and horse racing results, number tools, and result checkers. It builds the request, handles errors, and hands you back the parsed JSON. Nothing more.

> Unofficial tooling for the ResultsZA API. Not affiliated with the South African National Lottery, UK 49's, or any national lottery or racing operator. Always verify results on the official operator's site before claiming a prize.

## Install

```bash
pip install resultsza-sdk
```

Or from source while it's in development:

```bash
pip install -e "python/[dev]"
```

## Quickstart

Get an API key at **[resultsza.co.za/generate_api_key](https://resultsza.co.za/generate_api_key)**, then:

```python
import os
from resultsza import ResultsZA

client = ResultsZA(api_key=os.environ["RESULTSZA_API_KEY"])

client.get_lotto_results()                          # latest draw
client.get_lotto_results(date="2026-07-08")         # a specific draw
client.get_hot_cold_numbers(product="Powerball")
client.generate_random_numbers(game="Lotto", lines=5)
client.check_balance()                              # free - no calls used
```

The API key is read from an argument or your own environment variable - it is never hardcoded. If a key ever appears in a URL or error, the client redacts it.

## Supported endpoints

| Method | Endpoint |
|---|---|
| `get_daily_lotto_results(date=None)` | Daily Lotto |
| `get_lotto_results(date=None)` | Lotto |
| `get_lotto_plus_1_results(date=None)` | Lotto Plus 1 |
| `get_lotto_5_max_results(date=None)` | Lotto 5 Max |
| `get_sa_powerball_results(date=None)` | SA Powerball |
| `get_powerball_xtra_results(date=None)` | Powerball Xtra |
| `get_kenya_lotto_results(date=None, draw_type=None)` | Kenya Lotto (`draw_type`: `daily`/`jackpot`) |
| `get_nigeria_lotto_results(game=None, date=None)` | Nigeria (Premier Lotto) |
| `get_ghana_lotto_results(game=None, date=None)` | Ghana Lotto |
| `get_uk49s_results(game, date=None)` | UK 49's (`game` required) |
| `get_euromillions_results(date=None)` | EuroMillions |
| `get_irish_lotto_results(date=None)` | Irish Lotto |
| `get_us_powerball_results(date=None)` | US Powerball |
| `get_megamillions_results(date=None)` | US Mega Millions |
| `get_horse_racing_meetings(from_date=None, to_date=None)` | Race meetings (max 7-day span) |
| `get_horse_racing_results(date, venue)` | Full race card |
| `get_horse_racing_race(date, venue, race_no)` | Single-race runner table |
| `generate_random_numbers(game, lines=None)` | Random line generator |
| `text_to_lucky_numbers(game, text)` | Deterministic text to numbers |
| `get_hot_cold_numbers(product)` | Hot & cold numbers |
| `get_number_frequencies(product)` | Per-number frequencies |
| `get_number_pairs(product)` | Top number pairs |
| `check_played_numbers(game, date, played_numbers)` | Checker - up to 10 lines |
| `bulk_check_numbers(game, date, played_numbers)` | Bulk checker - up to 500 lines |
| `check_balance()` | Remaining calls & subscription status (free) |

See the [full API docs](https://resultsza.co.za/api_docs) for response shapes. Parameters that accept only specific values (`game`, `product`, `venue`, `draw_type`) are listed under [Games and parameter values](#games-and-parameter-values) below.

## Games and parameter values

Some parameters only accept specific values. Here they are in full.

**South African games** - used by the SA result endpoints, both checkers, and the generators:
`Daily Lotto`, `Lotto`, `Lotto Plus 1`, `Lotto 5 Max`, `Powerball`, `Powerball Xtra`

**UK 49's** - `get_uk49s_results(game=...)`, required:
`UK49s Brunchtime`, `UK49s Lunchtime`, `UK49s Drivetime`, `UK49s Teatime`

**Kenya draw type** - `get_kenya_lotto_results(draw_type=...)`:
`daily` (hourly draws) or `jackpot` (Wed/Sat). Omit for both.

**Horse racing venues** - `get_horse_racing_results` / `get_horse_racing_race` `venue`:
`Greyville`, `Kenilworth`, `Fairview`, `Vaal`

**Ghana Lotto games** - `get_ghana_lotto_results(game=...)`, optional (omit to return every game drawn on that date):
`Ghana Monday Special`, `Ghana Lucky Tuesday`, `Ghana Mid-Week`, `Ghana Fortune Thursday`, `Ghana Friday Bonanza`, `Ghana National Weekly`, `Ghana Sunday Aseda`, `Ghana VAG Lotto`, `Ghana Noon Rush`, `Ghana Daywa 5/39`

**Nigeria (Premier Lotto) games** - `get_nigeria_lotto_results(game=...)`, optional (omit to return every game drawn on that date; Nigeria draws 6 of these per day):

<details><summary>25 game names</summary>

`PREMIER 06`, `PREMIER ASEDA`, `PREMIER BINGO`, `PREMIER BONANZA`, `PREMIER CLUB MASTER`, `PREMIER DIAMOND`, `PREMIER ENUGU`, `PREMIER FAIRCHANCE`, `PREMIER FORTUNE`, `PREMIER GOLD`, `PREMIER INTERNATIONAL`, `PREMIER JACKPOT`, `PREMIER KING`, `PREMIER LUCKY`, `PREMIER LUCKY G`, `PREMIER MARK II`, `PREMIER METRO`, `PREMIER MIDWEEK`, `PREMIER MSP`, `PREMIER NATIONAL`, `PREMIER PEOPLES`, `PREMIER ROYAL`, `PREMIER SUPER`, `PREMIER TOTA`, `PREMIER VAG`
</details>

**Number generator / text-to-lucky games** - `generate_random_numbers` / `text_to_lucky_numbers` `game`:
the SA games above, the four UK 49's variants above, plus `EuroMillions`, `Irish Lotto`, `US Powerball`, `Mega Millions`, `Kenya Lotto`, `Nigeria Lotto`, `Ghana Lotto`.

**Hot/cold, frequencies, pairs** - `product`: the SA games are the primary set; `UK49s`, `EuroMillions`, `Irish Lotto`, `US Powerball`, `Mega Millions`, `Kenya Lotto`, `Nigeria Lotto`, and `Ghana Lotto` are also supported.

Dates are always `YYYY-MM-DD`.

## Errors

Failures raise typed exceptions so you can handle them predictably:

```python
from resultsza.exceptions import (
    ResultsZAError,          # base class
    BadRequestError,         # invalid parameters
    AuthError,               # missing/invalid key
    RateLimitError,          # rate limit / cooldown
    SubscriptionExpiredError,
    SubscriptionPendingError,
)

try:
    client.get_lotto_results(date="not-a-date")
except BadRequestError as exc:
    print(exc.status_code, exc.response)
```

## Webhooks

ResultsZA can push results to your endpoint the moment they're published. Register your endpoint URL and get your signing secret in the **[subscriber portal](https://resultsza.co.za/portal/login)** under **Push Settings** (there is no webhook API) - this SDK helps you *receive* those deliveries safely.

```python
from resultsza.webhook import verify_and_parse, SIGNATURE_HEADER
from resultsza.exceptions import InvalidSignatureError

# raw = the exact request BYTES (not re-serialized JSON)
# signature = request header "X-ResultsZA-Signature"
try:
    event = verify_and_parse(raw, signature, secret)
except InvalidSignatureError:
    ...  # reject: return 401

if event.is_test:        # portal test sends (result.test)
    ...
event.game, event.data, event.dedupe_key()
```

Three rules a correct receiver must follow, all shown in [`examples/webhook_receiver_flask.py`](examples/webhook_receiver_flask.py):

1. **Verify against the raw request bytes**, not a re-serialized copy of the JSON.
2. **Return a 2xx within 10 seconds**, then do slow work afterwards.
3. **Deduplicate** - delivery is at-least-once and unordered (`event.dedupe_key()` helps).

Endpoints must be **HTTPS**. See the [webhook docs](https://resultsza.co.za/webhook-docs).

## Rate limits

The Unlimited tier is capped at 60 requests/minute; exceeding it triggers a 5-minute cooldown. Other tiers are bounded by a monthly quota. Check your usage any time with `client.check_balance()` - it doesn't consume a call. See [pricing](https://resultsza.co.za) for tiers.

## Testing

The test suite mocks the HTTP layer, so it needs no API key and never calls the production API:

```bash
pip install -e "python/[dev]"
cd python && pytest
```

## Links

- **Get an API key:** https://resultsza.co.za/generate_api_key
- **Set up webhooks (portal Push Settings):** https://resultsza.co.za/portal/login
- API docs: https://resultsza.co.za/api_docs
- Webhook docs: https://resultsza.co.za/webhook-docs
- Pricing & plans: https://resultsza.co.za

MIT licensed.
