Skip to main content

Installation

pip install keystoneos
Requires Python 3.10+. Dependencies: httpx (HTTP client) and pydantic (type validation).

Initialize the client

The SDK provides both async and sync clients:
from keystoneos import KeystoneClient

client = KeystoneClient(
    client_id="YOUR_CLIENT_ID",
    client_secret="YOUR_CLIENT_SECRET",
)

# Use as async context manager
async with client:
    settlements = await client.settlements.list()
The async client is recommended for production workloads. The sync client wraps the async client for scripts and notebooks.

Configuration options

OptionTypeDefaultDescription
client_idstrrequiredAuth0 M2M client ID
client_secretstrrequiredAuth0 M2M client secret
base_urlstrhttps://api.keystoneos.xyzAPI base URL
auth_domainstrauth.keystoneos.xyzAuth0 domain
audiencestrhttps://api.keystoneos.xyzAuth0 audience
timeoutfloat30.0Request timeout in seconds
retryRetryConfig3 retries, 0.5s baseRetry configuration

Resources

client.settlements    # Create, get, list, compliance decisions, events
client.instructions   # Submit, get, list, cancel bilateral instructions
client.templates      # List and get settlement templates (read-only)
client.webhooks       # CRUD + test, rotate secret, delivery logs
client.environments   # CRUD + deactivate
client.compliance     # approve() and reject() convenience methods

Submit a bilateral instruction

from keystoneos import KeystoneClient

async with KeystoneClient(
    client_id="YOUR_CLIENT_ID",
    client_secret="YOUR_CLIENT_SECRET",
) as client:
    instruction = await client.instructions.submit({
        "template_slug": "cross_platform_dvp",
        "role": "seller",
        "party": {
            "external_reference": "SELLER-001",
            "name": "BNY Mellon Fund A",
            "wallet_address": "0x1234567890abcdef1234567890abcdef12345678",
            "chain_id": 11155111,
        },
        "legs": [
            {
                "instrument_id": "BOND-2026-A",
                "quantity": "1000000",
                "direction": "deliver",
            },
        ],
        "timeout_at": "2026-04-01T00:00:00Z",
        "idempotency_key": client.generate_idempotency_key(),
    })

    print(instruction.trade_reference)  # Share with counterparty
    print(instruction.status)           # "pending_match" or "matched"

List settlements

result = await client.settlements.list(state="FINALIZED", limit=20)

for settlement in result.items:
    print(f"{settlement.id} - {settlement.state}")

print(f"Total: {result.total}")

Webhook signature verification

from keystoneos import KeystoneClient

# In your webhook handler (FastAPI, Flask, etc.)
@app.post("/webhooks/keystone")
async def handle_webhook(request: Request):
    payload = await request.body()
    signature = request.headers.get("x-keystone-signature", "")

    if not KeystoneClient.webhooks.verify_signature(
        payload=payload.decode(),
        signature=signature,
        secret="your-webhook-secret",
    ):
        raise HTTPException(status_code=401, detail="Invalid signature")

    event = await request.json()
    print(f"Settlement {event['data']['settlement_id']} -> {event['data']['to_state']}")

    return {"status": "ok"}

Error handling

from keystoneos.exceptions import (
    ApiError,
    AuthenticationError,
    NotFoundError,
    ConflictError,
    RetryExhaustedError,
)

try:
    settlement = await client.settlements.get("non-existent-id")
except NotFoundError:
    print("Settlement not found")
except ConflictError as e:
    print(f"State conflict: {e.message}")
except AuthenticationError:
    print("Check your credentials")
except RetryExhaustedError:
    print("Service unavailable after retries")
except ApiError as e:
    print(f"API error {e.status_code}: {e.message}")

Compliance decisions

The compliance resource provides convenience methods:
# Approve compliance for a settlement
settlement = await client.compliance.approve("settlement-id-here")

# Reject compliance
settlement = await client.compliance.reject("settlement-id-here")

Idempotency

key = client.generate_idempotency_key()           # UUIDv4
key = client.generate_idempotency_key("my-prefix") # "my-prefix-{uuid}"

# Safe to retry - same key returns existing resource
settlement = await client.settlements.create(
    idempotency_key=key,
    # ...
)

API Reference

See the full API reference for all available endpoints and parameters.