Skip to main content

Referalli Python SDK

The official Python client for the Referalli API: attribution-first affiliate and referral programs.

  • One typed method per API operation, with TypedDict models for every request and response.
  • Sync (Referalli, standard library only) and async (AsyncReferalli, on httpx) clients with the same methods.
  • Retries with backoff, idempotency keys, timeouts, auto-paging iterators and one exception class per error code.
  • Webhook signature verification and typed webhook events.

Python 3.11+. Docs: https://referalli.com/docs.

Install

pip install referalli            # sync client, no dependencies
pip install "referalli[async]"   # adds httpx for AsyncReferalli

Quickstart

Keep the rk_ API key on your server.

import os

from referalli import Referalli

client = Referalli(api_key=os.environ["REFERALLI_API_KEY"])

# 1. Create a referral link for a partner
link = client.post_links({
    "programId": "prg_123",
    "partnerId": "ptr_123",
    "destinationUrl": "https://example.com/pricing",
})
print(link.get("shortUrl"))

# 2. Attribute a signup to the partner who referred it
client.post_referrals_associate({"programId": "prg_123", "customerRef": "user_42", "anonId": "anon_from_cookie"})

# 3. Track a conversion: a purchase your server has validated
client.post_mobile_purchases({"eventId": "order_1001", "customerRef": "user_42", "amountMinor": 4900, "currency": "usd"})

Verify a webhook delivery (Flask shown; any framework works, as long as you pass the raw body):

import os

from flask import Flask, request

from referalli import WebhookVerificationError, webhooks

app = Flask(__name__)


@app.post("/webhooks/referalli")
def referalli_webhook():
    try:
        event = webhooks.construct_event(request.get_data(), request.headers, os.environ["REFERALLI_WEBHOOK_SECRET"])
    except WebhookVerificationError:
        return "", 400
    if event["topic"] == "commission.earned":
        print("commission", event["data"])
    return "", 204

Configuration

from referalli import Referalli

client = Referalli(
    api_key="rk_live_...",
    base_url="https://referalli.com",  # the default
    timeout=30.0,                      # seconds per attempt
    max_retries=3,                     # retries for idempotent requests
    mode="live",                       # optional: assert the key's mode ("test" or "live")
)

fast = client.with_options(timeout=5, max_retries=0)  # a copy with some settings changed

Every request is pinned to the API version this SDK was generated against (referalli.API_VERSION); pass api_version= to pin another.

Async

import asyncio

from referalli import AsyncReferalli


async def main() -> None:
    async with AsyncReferalli(api_key="rk_live_...") as client:
        programs = await client.get_programs()
        async for partner in client.get_partners_iter(status="active"):
            print(partner["email"])


asyncio.run(main())

Test mode

Use a test-mode key (rk_test_...) to work against your organization's test data. Pass mode="test" to make every request assert it: the API rejects a request whose key is in the other mode with ModeMismatchError, so test code can never write live data. Webhook events carry livemode.

Errors

Every API error raises a subclass of ApiError named after its code, with status, code, message, request_id, docs_url, details and retry_after. Network failures and timeouts raise ApiConnectionError after the retries run out. All of them derive from ReferalliError.

from referalli import ApiError, NotFoundError, RateLimitedError, Referalli

client = Referalli(api_key="rk_live_...")
try:
    client.get_partners_id("ptr_missing")
except NotFoundError as e:
    print(e.code, e.status, e.request_id, e.docs_url)
except RateLimitedError as e:
    print("retry after", e.retry_after)
except ApiError as e:
    print(e.code, e.message)

Retries: GET, PUT and DELETE requests, and writes carrying an Idempotency-Key, are retried on 429, 5xx and network errors with exponential backoff and jitter, honoring Retry-After. POST and PATCH requests always carry a key (generated unless you pass idempotency_key=), and the same key is reused across retries, so a retried write is applied once.

Pagination

List methods return one page ({"object": "list", "data": [...], "has_more": ..., "next_cursor": ...}); their _iter twin follows the cursor for you.

from referalli import Referalli

client = Referalli(api_key="rk_live_...")
page = client.get_partners(status="active", limit=50)
next_page = client.get_partners(status="active", limit=50, starting_after=page["next_cursor"])

for referral in client.get_referrals_iter():
    print(referral["id"])

Webhooks

webhooks.construct_event(raw_body, headers, secrets) checks the Standard Webhooks signature (webhook-id, webhook-timestamp, webhook-signature) in constant time, rejects deliveries more than 5 minutes old or ahead (tolerance_sec=), and returns the event typed by topic (referalli.WebhookEvent, one TypedDict per topic in referalli.TOPICS). Pass a list of secrets while you rotate one. webhooks.verify(...) returns a bool instead of raising.

from referalli import webhooks

secrets = ["whsec_current", "whsec_previous"]


def handle(raw_body: bytes, headers: dict) -> None:
    if not webhooks.verify(raw_body, headers, secrets):
        raise PermissionError("bad signature")

Any operation by id

from referalli import Referalli

client = Referalli(api_key="rk_live_...")
partner = client.call("getPartnersId", path={"id": "ptr_123"})
for item in client.list_all("getPartners", query={"status": "active"}):
    print(item["id"])

Versioning

This SDK follows semantic versioning; see CHANGELOG.md. The API version it pins is referalli.API_VERSION.

License

MIT. See LICENSE.

Metadata

Release files for referalli 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for referalli 0.1.0
File Size Uploaded Provenance
referalli-0.1.0.tar.gz 145.9 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for referalli 0.1.0
File Interpreter ABI Platform
referalli-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 297.4 kB

Release files / referalli-0.1.0.tar.gz

Download URL referalli-0.1.0.tar.gz
Size 145.9 kB
Tags Source
SHA-256 checksum
How to use checksums
9465ef658ffa17fb6157ff0f59735110ba989fed9e1dbe27dd34ca0705f7b0f1
BLAKE2b-256 checksum
How to use checksums
b5cc11c683e8fd47b03f3892526a2627f99cb813cfee6967c78a39a46c2d80cb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / referalli-0.1.0-py3-none-any.whl

Download URL referalli-0.1.0-py3-none-any.whl
Size 151.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d617a6a2d35066409cb9514d2d87dd0ebc6a1d30cc3138b3256ae7941f4dfe56
BLAKE2b-256 checksum
How to use checksums
9c610c0d540b465611c5a79512a9b1367bdf3c00587c1d96f8be1635d9861260
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Security for referalli 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page