Skip to content

Latest commit

 

History

History
422 lines (327 loc) · 15.5 KB

File metadata and controls

422 lines (327 loc) · 15.5 KB
SofizPay Logo

SofizPay SDK Python

The official Python SDK for secure digital payments, EDAHABIA / CIB transactions, utility bill payments, and telecom recharges in Algeria.

PyPI version Python Versions License: MIT


🚀 Quick Start

Installation

pip install sofizpay-sdk-python

Basic Usage

import asyncio
from sofizpay import SofizPayClient

async def main():
    # Production mode (default)
    client = SofizPayClient()
    
    # Or Sandbox mode for testing:
    # client = SofizPayClient(is_sandbox=True)
    
    # Send direct wallet payment (DZT)
    result = await client.send_payment(
        source_secret='YOUR_SECRET_KEY',
        destination_public_key='RECIPIENT_PUBLIC_KEY',
        amount='100',
        memo='Payment description'
    )
    print('Payment sent!' if result.get('successful') else result.get('error'))

asyncio.run(main())

✨ Features

  • 💳 CIB & EDAHABIA Gateway - Accept bank card and postal card payments with full 3D Secure, Webhooks, and Sandbox testing.
  • 🔍 CIB Transaction Status Check - Real-time verification of CIB/EDAHABIA payment status.
  • Send Secure Payments - Instant DZT wallet digital transactions on Stellar network.
  • 💰 Account Balance - Real-time balance checking for DZT.
  • 📜 Transaction History & Search - Complete transaction history and memo/hash searching.
  • 📡 Real-time Streaming - Live transaction monitoring with customizable intervals.
  • 🛍️ Products Catalog - Browse available products, gaming vouchers, and telecom packages.
  • 🧾 Utility Bill Payments - Pay Sonelgaz, ADE (water), and Algérie Télécom bills programmatically.
  • 📱 Mobile & Internet Top-ups - Flexy (Mobilis, Djezzy, Ooredoo) and IDOOM (ADSL / 4G LTE).
  • 🎮 Gaming Credits - Instant top-ups for PUBG UC, Free Fire Diamonds, and more.
  • 🔐 Digital Signature Verification - Verify cryptographic RSA SHA-256 signatures from SofizPay callbacks.
  • 🌐 Multi-platform - Fully asynchronous with async/await support across Linux, Windows, macOS.

📋 Core Methods Reference

Method Description Example
make_cib_transaction(data) Create CIB / EDAHABIA payment link await client.make_cib_transaction({...})
make_sandbox_cib_transaction(data) Create Sandbox CIB payment link await client.make_sandbox_cib_transaction({...})
check_cib_transaction(data) Check CIB transaction status await client.check_cib_transaction('order_id')
check_cib_status(cib_id) Production CIB status check await client.check_cib_status('2517039448')
check_sandbox_cib_status(cib_id) Sandbox CIB status check await client.check_sandbox_cib_status('40a11881...')
send_payment(secret, dest, amount, memo) Send DZT Stellar payment await client.send_payment(...)
get_balance(public_key) Get DZT account balance await client.get_balance('GXXX...')
get_transactions(public_key, limit) Get transaction history await client.get_transactions('GXXX...', 50)
search_transactions_by_memo(pk, memo, limit) Search transactions by memo await client.search_transactions_by_memo('GXXX...', 'Order #1')
get_transaction_by_hash(hash) Find transaction by hash await client.get_transaction_by_hash('abc123...')
setup_transaction_stream(pk, cb, from_now) Stream live transactions await client.setup_transaction_stream('GXXX...', cb)
stop_transaction_stream(stream_id) Stop live stream client.stop_transaction_stream(stream_id)
get_products(encrypted_sk, search) Browse products catalog await client.get_products('SXXX', search='PUBG')
get_operation_history(encrypted_sk, limit) View service operations history await client.get_operation_history('SXXX')
get_operation_details(id, encrypted_sk) Operation status tracking await client.get_operation_details('UUID', 'SXXX')
pay_ade_bill(data) Pay ADE water bill await client.pay_ade_bill({...})
pay_sonelgaz_bill(data) Pay Sonelgaz electricity/gas await client.pay_sonelgaz_bill({...})
pay_algerie_telecom_bill(data) Pay Algérie Télécom bill await client.pay_algerie_telecom_bill({...})
recharge_phone(data) Flexy mobile credit await client.recharge_phone({...})
recharge_internet(data) IDOOM ADSL / 4G recharge await client.recharge_internet({...})
recharge_game(data) PUBG / Free Fire recharge await client.recharge_game({...})
verify_signature(data) Verify RSA SHA-256 webhook SofizPayClient.verify_signature({...})

📖 API Reference & Examples

1. CIB & EDAHABIA Transactions (make_cib_transaction)

Generate a secure payment URL to accept CIB or EDAHABIA payments with 3D Secure support, webhook callbacks, and sandbox testing.

import asyncio
from sofizpay import SofizPayClient

async def create_payment():
    client = SofizPayClient()
    
    response = await client.make_cib_transaction({
        'account': 'GDNS27ISCGOIJFXC6CM4O5SVHVJPSWR42QEBWUFF24N5VVHGW73ZSJNQ', # Your Sofizpay receiving account
        'amount': 1500,                                                      # Amount in DZD
        'full_name': 'Ahmed Ben Ali',                                         # Customer name
        'phone': '+213555123456',                                            # Customer phone
        'email': 'ahmed.benali@example.com',                                 # Customer email
        'return_url': 'https://mystore.com/payment-callback',                # Redirect URL after checkout
        'webhook_url': 'https://mystore.com/api/cib-webhook',               # Real-time async webhook URL
        'invoice_id': 'INV-2026-001',                                        # Optional invoice ID
        'language': 'ar',                                                    # 'ar' | 'en' | 'fr'
        'memo': 'Order #12345',                                              # Payment note (max 28 bytes)
        'redirect': 'yes',                                                   # 'yes' | 'no'
        'keep_return_url': 'True',                                           # Include signed callback params
        'is_sandbox': False                                                  # Set True for Sandbox testing
    })
    
    if response.get('success'):
        print('Payment URL:', response.get('payment_url'))
        print('Transaction ID:', response.get('transaction_id'))
        print('CIB Transaction ID:', response.get('cib_transaction_id'))
        # Redirect customer to response['payment_url']
    else:
        print('Failed to initiate payment:', response.get('error'))

asyncio.run(create_payment())

Dedicated Sandbox Helper:

# Creates a CIB transaction directly in the Sandbox environment
sandbox_res = await client.make_sandbox_cib_transaction({
    'account': 'GDNS27ISCGOIJFXC6CM4O5SVHVJPSWR42QEBWUFF24N5VVHGW73ZSJNQ',
    'amount': 150.0,
    'full_name': 'Sandbox Tester',
    'phone': '0661000000',
    'email': 'sandbox@sofizpay.com',
    'memo': 'Python Sandbox Test'
})
print('Sandbox Payment URL:', sandbox_res.get('payment_url'))

2. Check CIB Transaction Status (check_cib_transaction / check_cib_status)

Verify the payment status of an order after the customer completes payment on the SATIM payment page.

# Query by order number / CIB transaction ID
check = await client.check_cib_transaction({
    'order_number': '2517039448',
    'is_sandbox': False # Set True if checking a sandbox transaction
})

if check.get('success') and check.get('status') == 'paid':
    print(f"Order {check.get('order_number')} was successfully paid! Amount: {check.get('amount')} DZD")
else:
    print('Payment status:', check.get('status'), check.get('error_message'))

Dedicated Status Check Helpers:

# Check status in Production
prod_status = await client.check_cib_status('2517039448')

# Check status in Sandbox
sandbox_status = await client.check_sandbox_cib_status('40a11881d8764fe9a371')

💡 Best Practice: Secure Order Flow

For maximum security, store the cib_transaction_id in your database server-side and verify status before fulfilling orders:

# 1. Server initiates transaction
result = await client.make_cib_transaction({
    'account': 'YOUR_PUBLIC_KEY',
    'amount': 5000,
    'full_name': 'Customer Name',
    'phone': '0555000000',
    'email': 'customer@example.com',
    'memo': 'Order #9921'
})

if result.get('success'):
    cib_id = result.get('cib_transaction_id')
    # Save cib_id to database linked to order #9921
    # db.orders.update_one({'id': 9921}, {'$set': {'cib_id': cib_id}})
    payment_url = result.get('payment_url')

# 2. When customer returns or webhook triggers, verify server-side:
status = await client.check_cib_status(cib_id)
if status.get('success') and status.get('status') == 'paid':
    # Mark order as PAID in database and dispatch goods
    pass

3. Products Catalog (get_products)

Retrieve available products and services with their prices in DZT, with optional search filtering.

# Get all available products
catalog = await client.get_products('YOUR_SECRET_KEY')

print(f"Available products count: {catalog.get('count')}")
for product in catalog.get('products', []):
    print(f"{product.get('name')}: {product.get('price')} DZT")

# Search for specific products (e.g., PUBG, Free Fire, Mobilis)
search_result = await client.get_products({
    'encrypted_sk': 'YOUR_SECRET_KEY',
    'search': 'PUBG'
})
print('Found products:', search_result.get('products'))

4. Utility Bill Payments (pay_bill)

Pay Algerian utility bills directly via the Python SDK:

ADE (Algérienne Des Eaux - Water Bill)

ade_payment = await client.pay_ade_bill({
    'encrypted_sk': 'YOUR_SECRET_KEY',
    'amount': 2500,
    'bill': '0123456789' # Bill reference number
})

if ade_payment.get('success'):
    print('ADE Bill Paid! Operation ID:', ade_payment.get('operation_id'))

Sonelgaz (Electricity & Gas)

sonelgaz_payment = await client.pay_sonelgaz_bill({
    'encrypted_sk': 'YOUR_SECRET_KEY',
    'amount': 3500,
    'customerId': 'CUST-100234', # Customer ID
    'ebb': 'EBB-987654',         # EBB Number
    'bill': 'BILL-456789'        # Bill Number
})

if sonelgaz_payment.get('success'):
    print('Sonelgaz Bill Paid! Operation ID:', sonelgaz_payment.get('operation_id'))

Algérie Télécom Bill

telecom_payment = await client.pay_algerie_telecom_bill({
    'encrypted_sk': 'YOUR_SECRET_KEY',
    'amount': 2000,
    'phone': '021234567', # Landline or subscription number
    'bill': 'BILL-00129'
})

5. Mobile, Internet & Game Top-ups

Phone Recharge (Flexy: Mobilis, Djezzy, Ooredoo)

flexy = await client.recharge_phone({
    'encrypted_sk': 'YOUR_SECRET_KEY',
    'phone': '0661234567',
    'operator': 'djezzy', # 'mobilis' | 'djezzy' | 'ooredoo'
    'amount': 500,
    'offer': 'prepaid'
})

IDOOM Internet Recharge (ADSL & 4G LTE)

internet = await client.recharge_internet({
    'encrypted_sk': 'YOUR_SECRET_KEY',
    'phone': '0458230823',          # 10 digits for 4G, 9 digits for ADSL
    'operator': 'idoom',
    'amount': 1000,
    'offer': 'IDOOM 4G 1000'        # e.g. 'IDOOM 4G 1000' or 'IDOOM ADSL 2000'
})

Gaming Credits (PUBG & Free Fire)

game = await client.recharge_game({
    'encrypted_sk': 'YOUR_SECRET_KEY',
    'operator': 'pubg',             # 'pubg' | 'freefire'
    'playerId': '5123456789',       # Player in-game ID
    'amount': 1200,
    'offer': '60'                   # '60' | '325' | '660' for PUBG, '110' | '210' for Free Fire
})

6. Operation Details & History

# Get details of a specific operation
details = await client.get_operation_details({
    'operation_id': '550e8400-e29b-41d4-a716-446655440000',
    'encrypted_sk': 'YOUR_SECRET_KEY'
})

# Get operation history
history = await client.get_operation_history('YOUR_SECRET_KEY', limit=10, offset=0)
print('Recent Operations:', history.get('data'))

7. Digital Signature Verification (verify_signature)

Verify webhook callbacks signed with RSA SHA-256:

from fastapi import FastAPI, Request, HTTPException
from sofizpay import SofizPayClient

app = FastAPI()

@app.post("/api/cib-webhook")
async def cib_webhook(request: Request):
    payload = await request.json()
    message = payload.get("message")
    signature = payload.get("signature_url_safe")
    
    is_valid = SofizPayClient.verify_signature({
        "message": message,
        "signature_url_safe": signature
    })
    
    if not is_valid:
        raise HTTPException(status_code=400, detail="Invalid signature")
    
    # Process authentic payment confirmation
    return {"status": "success", "received": True}

8. Direct Stellar Wallet Payments & Balance

# Get DZT balance
balance = await client.get_balance('GDNS27ISCGOIJFXC6CM4O5SVHVJPSWR42QEBWUFF24N5VVHGW73ZSJNQ')
print('Balance:', balance)

# Search transactions by memo
search_res = await client.search_transactions_by_memo(
    'GDNS27ISCGOIJFXC6CM4O5SVHVJPSWR42QEBWUFF24N5VVHGW73ZSJNQ',
    'Order #12345',
    limit=50
)
print('Search Results:', search_res.get('transactions'))

# Real-time transaction streaming
def handle_tx(tx):
    print('Live Payment Received:', tx.get('amount'), tx.get('memo'), tx.get('from'))

stream_id = await client.setup_transaction_stream(
    'GDNS27ISCGOIJFXC6CM4O5SVHVJPSWR42QEBWUFF24N5VVHGW73ZSJNQ',
    handle_tx,
    from_now=True,
    check_interval=30
)

# Later, stop stream:
client.stop_transaction_stream(stream_id)

🧪 Testing with CIB Sandbox

SofizPay provides a mock testing environment to test CIB / EDAHABIA payments without real cards:

Set is_sandbox=True in SofizPayClient(is_sandbox=True) or pass 'is_sandbox': True to make_cib_transaction / check_cib_transaction.

Test Card Numbers:

Card Number Expiry CVV Expected Result
6280581001234567 12/28 123 Approved
6280581009876543 12/29 456 Approved
6280581005555555 06/28 999 Declined by issuer
6280581004444444 09/28 444 Insufficient funds
6280581003333333 03/21 333 Expired card
6280581002222222 11/28 222 Timeout

Sandbox OTP: Use 123456 for any test transaction.


🔒 Security Best Practices

  1. Protect Secret Keys: Never hardcode secret keys in frontend or public code. Always use environment variables (os.environ.get('SOFIZPAY_SECRET_KEY')).
  2. Verify Webhooks: Always use SofizPayClient.verify_signature() to validate incoming webhook payloads before updating database records.
  3. Check Status Server-side: When a customer returns to your return_url, verify the transaction using check_cib_transaction() from your server before granting access or fulfilling orders.

📜 License

MIT © SofizPay Team

Built with ❤️ for Algerian Fintech | docs.sofizpay.com