Metadata-Version: 2.4
Name: paperclip-sdk
Version: 0.4.0
Summary: Public Python SDK for calling remote functions, with sync and async clients.
Keywords: leasekey,sdk,rpc,paperclip
Requires-Python: >=3.10,<4.0
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Dist: httpx (>=0.27,<1.0)
Project-URL: Homepage, https://leasekey.org
Description-Content-Type: text/markdown

# paperclip-sdk

Python SDK for calling server-hosted Paperclip tools from scripts, workers, web apps, and async services.

Use it when you want to keep business logic, pricing rules, private workflows, or customer-specific functionality on the server while calling it from Python through a small client.

## Install

poetry add paperclip-sdk

or

pip install paperclip-sdk


## Configure authentication

export LEASEKEY_API_KEY="your-api-key"


## Quickstart

### Sync

from paperclip_sdk import Paperclip

with Paperclip() as paperclip:
    result = paperclip.tools.core.hello_world(name="Ada")
    print(result)


### Async

import asyncio
from paperclip_sdk import AsyncPaperclip


async def main() -> None:
    async with AsyncPaperclip() as paperclip:
        result = await paperclip.tools.core.hello_world(name="Ada")
        print(result)


asyncio.run(main())


## Real-world examples

The tool names below are illustrative. Replace them with the tools your Paperclip server exposes.

### Keep pricing logic on the server

from decimal import Decimal
from paperclip_sdk import Paperclip


def quote_total(customer_id: str, sku: str, quantity: int) -> Decimal:
    with Paperclip() as paperclip:
        result = paperclip.tools.pricing.compute_quote(
            customer_id=customer_id,
            sku=sku,
            quantity=quantity,
        )

    return Decimal(result["total"])


### Use it inside an async API

from fastapi import FastAPI
from paperclip_sdk import AsyncPaperclip

app = FastAPI()


@app.post("/tickets/{ticket_id}/summarize")
async def summarize_ticket(ticket_id: str) -> dict:
    async with AsyncPaperclip() as paperclip:
        return await paperclip.tools.support.summarize_ticket(
            ticket_id=ticket_id,
        )


### Build a remote plugin system

from paperclip_sdk import Paperclip

with Paperclip() as paperclip:
    result = paperclip.tools.plugins.transform_payload(
        payload={
            "source": "stripe",
            "event": "invoice.paid",
        }
    )
    print(result)


### Reuse a tool handle

from paperclip_sdk import Paperclip

with Paperclip() as paperclip:
    enrich_contact = paperclip.tools.crm.enrich_contact

    print(enrich_contact(email="ada@example.com"))
    print(enrich_contact(email="grace@example.com"))


### Reuse an async tool handle

import asyncio
from paperclip_sdk import AsyncPaperclip


async def main() -> None:
    async with AsyncPaperclip() as paperclip:
        summarize = paperclip.tools.support.summarize_ticket

        print(await summarize(ticket_id="T-100"))
        print(await summarize(ticket_id="T-101"))


asyncio.run(main())


## Notes

- Tools are available under `paperclip.tools.<namespace>.<name>(...)`
- The default base URL is `https://leasekey.org`, so passing `base_url` is optional
- The SDK automatically sends `User-Agent: paperclip-sdk/<version>`
- The SDK also sends `X-Leasekey-SDK-Version: <version>`
- Built-in retry behavior covers retryable transport failures and these HTTP statuses:
  408, 425, 429, 502, 503, 504

