Python SDK
The official Islamic Open Finance™ Python SDK provides async support and type hints.
Installation
bash
pip install iof-sdk
# or with poetry
poetry add iof-sdkRequirements
- Python 3.9 or later
- httpx (installed automatically)
Quick Start
python
import os
from iof import IOFClient
client = IOFClient(
api_key=os.environ["IOF_API_KEY"],
environment="sandbox" # or 'production'
)
# Create a contract
contract = client.contracts.create(
type="murabaha",
jurisdiction="SA",
parties={
"financier": {"entity_id": "ent_123"},
"customer": {"entity_id": "ent_456"},
},
asset={
"description": "Vehicle financing",
"cost_price": {"amount": 100000, "currency": "SAR"},
"profit_margin": 0.08,
},
terms={
"payment_schedule": "monthly",
"number_of_installments": 48,
}
)Async Support
The SDK supports both sync and async operations:
python
import asyncio
from iof import AsyncIOFClient
async def main():
client = AsyncIOFClient(
api_key=os.environ["IOF_API_KEY"],
environment="sandbox"
)
# Async operations
contract = await client.contracts.create(...)
contracts = await client.contracts.list()
# Async iteration
async for contract in client.contracts.list():
print(contract.id)
asyncio.run(main())Configuration
python
from iof import IOFClient
client = IOFClient(
# Required
api_key="sk_live_...",
# Optional
environment="production", # 'sandbox' | 'production'
timeout=30.0, # Request timeout in seconds
max_retries=3, # Retry failed requests
base_url="https://api.islamicopenfinance.com", # Custom base URL
)Available Resources
Contracts
python
# Create
contract = client.contracts.create(...)
# Get
contract = client.contracts.get("con_123")
# List
contracts = client.contracts.list(
status="active",
type="murabaha",
page=1,
per_page=20
)
# Update (draft only)
updated = client.contracts.update("con_123", ...)
# Submit for review
client.contracts.submit("con_123")
# Activate
client.contracts.activate("con_123")
# Terminate
client.contracts.terminate("con_123", reason="early_settlement")Entities
python
# Create individual
individual = client.entities.create(
type="individual",
name="Ahmed Al-Rashid",
jurisdiction="SA",
national_id="1234567890"
)
# Create institution
institution = client.entities.create(
type="institution",
name="Al Rajhi Bank",
jurisdiction="SA",
registration_number="123456"
)
# KYC verification
kyc = client.kyc.verify(
"ent_123",
document_type="national_id",
document_number="1234567890"
)Webhooks
python
# Create subscription
webhook = client.webhooks.create(
url="https://example.com/webhooks",
events=["contract.created", "payment.received"],
secret="whsec_..."
)
# List subscriptions
webhooks = client.webhooks.list()
# Update subscription
client.webhooks.update("wh_123", events=["contract.created"])
# Delete subscription
client.webhooks.delete("wh_123")Pagination
python
# Iterate through all pages automatically
for contract in client.contracts.list():
print(contract.id)
# Or get a single page
page = client.contracts.list(page=1, per_page=50)
print(page.data) # List of contracts
print(page.pagination) # Pagination infoError Handling
python
from iof.errors import (
IOFError,
ValidationError,
AuthenticationError,
RateLimitError,
NotFoundError,
)
try:
client.contracts.create(...)
except ValidationError as e:
print(f"Validation errors: {e.details}")
for detail in e.details:
print(f"{detail['field']}: {detail['message']}")
except AuthenticationError:
print("Invalid API key")
except RateLimitError as e:
print(f"Rate limited, retry after: {e.retry_after} seconds")
except NotFoundError:
print("Resource not found")
except IOFError as e:
print(f"API error: {e.code} - {e.message}")Webhook Signature Verification
python
from flask import Flask, request
from iof.webhooks import verify_signature
app = Flask(__name__)
@app.route("/webhooks", methods=["POST"])
def handle_webhook():
signature = request.headers.get("X-IOF-Signature")
payload = request.get_json()
is_valid = verify_signature(
payload=payload,
signature=signature,
secret=os.environ["WEBHOOK_SECRET"]
)
if not is_valid:
return "Invalid signature", 401
# Process webhook
event_type = payload["type"]
if event_type == "contract.created":
print(f"Contract created: {payload['data']['id']}")
elif event_type == "payment.received":
print(f"Payment received: {payload['data']['amount']}")
return "OK", 200Type Hints
The SDK includes full type annotations:
python
from iof import IOFClient
from iof.types import Contract, Entity, ContractType, ContractStatus
def process_contract(contract: Contract) -> None:
if contract.status == ContractStatus.ACTIVE:
print(contract.payment.monthly_amount)
client = IOFClient(api_key="sk_...")
contract: Contract = client.contracts.get("con_123")
process_contract(contract)Django Integration
python
# settings.py
IOF_API_KEY = env("IOF_API_KEY")
IOF_ENVIRONMENT = env("IOF_ENVIRONMENT", default="sandbox")
# services.py
from django.conf import settings
from iof import IOFClient
def get_iof_client() -> IOFClient:
return IOFClient(
api_key=settings.IOF_API_KEY,
environment=settings.IOF_ENVIRONMENT
)
# views.py
from django.http import JsonResponse
from .services import get_iof_client
def create_contract(request):
client = get_iof_client()
contract = client.contracts.create(...)
return JsonResponse({"id": contract.id})FastAPI Integration
python
from fastapi import FastAPI, Depends
from iof import AsyncIOFClient
app = FastAPI()
async def get_client() -> AsyncIOFClient:
return AsyncIOFClient(
api_key=os.environ["IOF_API_KEY"],
environment="sandbox"
)
@app.post("/contracts")
async def create_contract(
data: ContractCreateRequest,
client: AsyncIOFClient = Depends(get_client)
):
contract = await client.contracts.create(**data.dict())
return {"id": contract.id}Next Steps
- API Reference - Complete API documentation
- Error Handling - Detailed error handling guide
- Webhooks - Webhook integration guide