Sample Python client

import asyncio
import logging
import os
import random

import httpx

logger = logging.getLogger(__name__)

API_KEY = os.environ["ANDUIN_API_KEY"]
BASE_URL = "https://api.anduintransact.com"
MAX_RETRIES = 3
BASE_DELAY_MS = 500
REQUEST_TIMEOUT_S = 25.0


_semaphore = asyncio.Semaphore(5)


async def call_api(
    client: httpx.AsyncClient, method: str, path: str, **kwargs
) -> httpx.Response:
    async with _semaphore:
        for attempt in range(MAX_RETRIES + 1):
            response = await client.request(method, path, **kwargs)

            if response.status_code != 429:
                return response
            if attempt == MAX_RETRIES:
                break

            delay_ms = BASE_DELAY_MS * (2**attempt) + random.uniform(
                0, BASE_DELAY_MS * 0.5
            )
            logger.warning(
                "%s returned 429 — attempt %d/%d, retrying in %dms",
                path,
                attempt + 1,
                MAX_RETRIES,
                round(delay_ms),
            )
            await asyncio.sleep(delay_ms / 1000)

        raise httpx.HTTPStatusError(
            f"{path}: still receiving 429 after {MAX_RETRIES + 1} attempts",
            request=response.request,
            response=response,
        )


async def call_api_concurrently(client, items, fn):
    return await asyncio.gather(
        *[fn(client, item) for item in items],
        return_exceptions=True,
    )


# --- Usage ---


async def main():
    deal_ids = ["deal_1", "deal_2", "deal_3", "deal_4", "deal_5", "deal_6"]

    async with httpx.AsyncClient(
        base_url=BASE_URL,
        headers={
            "Authorization": f"Bearer {API_KEY}",
            "Content-Type": "application/json",
        },
        timeout=httpx.Timeout(REQUEST_TIMEOUT_S),
    ) as client:
        # Option 1: Sequential — safest for heavy endpoints (order creation, bulk operations)
        for deal_id in deal_ids:
            await call_api(client, "GET", f"/v2/deals/{deal_id}")

        # Option 2: Concurrent — semaphore in call_api caps in-flight requests
        results = await call_api_concurrently(
            client,
            deal_ids,
            lambda c, deal_id: call_api(c, "GET", f"/v2/deals/{deal_id}"),
        )

Did this page help you?