Skip to content

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-sdk

Requirements

  • 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 info

Error 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", 200

Type 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

Licensed under the Apache License 2.0