Official Python SDK for the Jokoor API
Project description
Jokoor Python SDK
Official Python SDK for the Jokoor API. Send SMS messages, accept payments, manage payouts, and more.
Features
- SMS: Send messages, manage campaigns, templates, and contacts
- Payments: Accept payments via Wave, card, Afrimoney, and QMoney
- Invoices: Create, send, and track invoices with automatic tax calculation
- Payouts: Withdraw funds to bank accounts and Wave B2P recipients
- Webhooks: Configure webhook endpoints to receive event notifications
- Type-safe: Full type hints for better IDE support and type checking
- Tuple return pattern: Returns
(data, error)tuples - no exceptions raised - Automatic retries: Built-in retry logic with exponential backoff
- Connection pooling: Efficient HTTP connection management
Installation
pip install jokoor
poetry add jokoor
pipenv install jokoor
Quick Start
from jokoor import Jokoor
from datetime import datetime, timezone # For scheduled operations
# Initialize the client
client = Jokoor('sk_test_your_api_key')
# Send an SMS message
sms, error = client.sms.send(
recipient_phone='+2207654321',
message_body='Hello from Jokoor!'
)
if error:
print(f'Error: {error}')
else:
print(f'SMS sent: {sms["id"]}')
Note on DateTime Parameters:
For scheduled operations, you can use either ISO 8601 strings or Python datetime objects:
# Option 1: ISO 8601 string (recommended)
scheduled_at='2024-12-25T10:00:00Z'
# Option 2: Python datetime object
from datetime import datetime, timezone
scheduled_at=datetime(2024, 12, 25, 10, 0, tzinfo=timezone.utc)
Authentication
Get your API keys from the Jokoor Dashboard.
API Key Types
- Secret keys (
sk_test_xxx,sk_live_xxx) - Full API access, use server-side only - Publishable keys (
pk_test_xxx,pk_live_xxx) - Limited access for client-side operations
Test vs Live Mode
- Test keys (
_test_) - For testing and development, no real charges - Live keys (
_live_) - For production use with real transactions
# Test environment
test_client = Jokoor('sk_test_your_api_key')
# Production environment
live_client = Jokoor('sk_live_your_api_key')
Configuration
from jokoor import Jokoor
client = Jokoor(
api_key='sk_test_xxx',
base_url='https://api.jokoor.com/v1', # Optional: custom API URL
timeout=30, # Optional: request timeout (seconds)
max_retries=3, # Optional: max retry attempts
debug=False, # Optional: enable debug logging
)
Error Handling
The SDK uses a tuple return pattern (data, error) instead of raising exceptions:
# Success case
sms, error = client.sms.send(
recipient_phone='+2207654321',
message_body='Hello!'
)
if error:
print(f'Error: {error}')
return
# Use data
print(f'SMS sent: {sms["id"]}')
API Reference
SMS
Send SMS
sms, error = client.sms.send(
recipient_phone='+2207123456',
message_body='Your verification code is 123456',
sender_id='MyApp', # Optional
scheduled_at='2024-12-25T10:00:00Z', # Optional
is_draft=False, # Optional
)
Get SMS Message
sms, error = client.sms.get('msg_123')
List SMS Messages
result, error = client.sms.list(
offset=0,
limit=20,
status='delivered',
start_date='2024-01-01T00:00:00Z',
end_date='2024-12-31T23:59:59Z',
)
if result:
print(f"Total: {result['count']}")
for sms in result['items']:
print(sms['id'])
Payment Links
Create Payment Link
link, error = client.payment_links.create(
title='Premium Subscription',
amount='500.00',
currency='GMD',
description='Monthly premium features',
success_url='https://example.com/success',
failure_url='https://example.com/cancel',
)
if link:
# Share this URL with customers
print(f"Payment URL: {link['payment_url']}")
# Example: https://pay.jokoor.com/pay/pl_abc123
Note: Payment links have hosted payment pages. Customers visit the payment_url to complete payment - no need to call the initialize endpoint.
List Payment Links
result, error = client.payment_links.list(limit=20, status='active')
Checkouts
Checkouts support both hosted pages and custom integration.
Option 1: Hosted Checkout Page (Simple)
checkout, error = client.checkouts.create(
amount='100.00',
currency='GMD',
description='Service payment',
)
if checkout:
# Share payment_url with customer
print(f"Send customer to: {checkout['payment_url']}")
# https://pay.jokoor.com/checkout/chk_abc123
# Customer completes payment on hosted page
Option 2: Custom SDK Integration (Full Control)
# Step 1: Create checkout
checkout, error = client.checkouts.create(
amount='100.00',
currency='GMD',
description='Service payment',
)
if error:
print(f'Error: {error}')
exit()
# Step 2: Initialize with client_secret
session, error = client.payments.initialize(
client_secret=checkout['client_secret'],
payment_method='wave',
customer_phone='+2207654321',
customer_email='customer@example.com',
)
if session:
# Redirect customer to payment provider
print(f"Redirect to: {session['payment_url']}")
Initialize Payment (Embedded Checkout)
Use this endpoint when building a custom payment UI with checkouts.
# After creating a checkout with client_secret
session, error = client.payments.initialize(
client_secret=checkout['client_secret'],
payment_method='wave',
customer_phone='+2207654321',
customer_email='customer@example.com',
customer_name='John Doe',
)
if session:
# Redirect customer to payment provider
print(f"Redirect to: {session['payment_url']}")
When to use:
- ✅ Embedded checkout integrations (custom payment UI)
- ❌ NOT for payment links, donations, or invoices (they have hosted pages)
Invoices
Create Invoice
invoice, error = client.invoices.create(
customer_email='customer@example.com',
customer_name='John Doe',
items=[
{
'description': 'Consulting Services',
'quantity': 10,
'unit_price': '50.00',
},
],
currency='GMD',
due_date='2024-12-31T23:59:59Z',
tax_rate=15, # Optional: 15% tax
)
if invoice:
print(f"Invoice Number: {invoice['invoice_number']}")
print(f"Payment URL: {invoice['payment_url']}") # Customer pays here
print(f"PDF URL: {invoice['pdf_url']}") # Download PDF
Record Offline Payment
For cash, bank transfers, checks, etc. (NOT Wave/Afrimoney/card):
invoice, error = client.invoices.record_payment(
'inv_123',
amount='1150.00',
payment_method='bank_transfer',
transaction_id='BANK-REF-123456',
notes='Received via wire transfer',
)
Two ways to pay invoices:
- Online: Customer visits
payment_url(Wave, Afrimoney, card) - Offline: Use
record_payment()for cash, bank transfers, checks
Donation Campaigns
campaign, error = client.donations.create(
title='Help Build a School',
description='Raising funds to build a new school',
target_amount='50000.00', # Optional goal
currency='GMD',
slug='school-building-fund', # Custom URL slug
)
if campaign:
print(f"Donation URL: {campaign['donation_url']}")
# Example: https://donate.jokoor.com/school-building-fund
print(f"Slug: {campaign['slug']}")
print(f"Progress: {campaign['progress_percentage']}%")
Customers
customer, error = client.customers.create(
email='customer@example.com',
phone='+2207123456',
name='John Doe',
)
Products
product, error = client.products.create(
name='Premium Subscription',
description='Monthly premium features',
price='29.99',
currency='GMD',
active=True,
)
Transactions
result, error = client.transactions.list(
offset=0,
limit=20,
status='completed',
start_date='2024-01-01T00:00:00Z',
end_date='2024-12-31T23:59:59Z',
)
if result:
for txn in result['items']:
print(f"{txn['id']}: {txn['amount']} {txn['currency']}")
Refunds
# Full refund
refund, error = client.refunds.create(
'txn_123',
reason='Customer request',
)
# Partial refund
refund, error = client.refunds.create(
'txn_123',
amount='50.00',
reason='Partial refund for damaged item',
)
Subscriptions
subscription, error = client.subscriptions.create(
customer_id='cus_123',
amount='29.99',
currency='GMD',
interval='monthly',
)
Payouts
Get Balance
balance, error = client.payouts.get_balance()
if balance:
print(f"Available: {balance['available_balance']} {balance['currency']}")
print(f"Pending: {balance['pending_balance']} {balance['currency']}")
List Bank Accounts
accounts, error = client.bank_accounts.list()
Note: Creating/updating bank accounts requires OTP and must be done via the web dashboard.
Send Payout to Recipient (Wave B2P)
payout, error = client.payout_recipients.send_payout(
recipient_id='recip_123',
amount='500.00',
reference='Salary payment',
# Note: OTP required - must be obtained via dashboard
)
Webhooks
Create Webhook Endpoint
webhook, error = client.webhooks.create(
url='https://myapp.com/webhooks/jokoor',
enabled_events=[
'payment.succeeded',
'payment.failed',
'sms.delivered',
'sms.failed',
],
)
if webhook:
# Secret is only shown once - store it securely
print(f"Webhook Secret: {webhook['secret']}")
List Webhook Events
result, error = client.webhook_events.list(
offset=0,
limit=20,
type='payment.succeeded',
start_date='2024-01-01T00:00:00Z',
)
Complete Examples
Accept Payment with Hosted Page
from jokoor import Jokoor
client = Jokoor('sk_test_xxx')
# Create a payment link
link, error = client.payment_links.create(
title='Product Purchase',
amount='500.00',
currency='GMD',
)
if error:
print(f'Error: {error}')
else:
# Share payment_url with customer
print(f'Send customer to: {link["payment_url"]}')
# Customer visits URL and completes payment on hosted page
Custom Payment Integration
from jokoor import Jokoor
client = Jokoor('sk_test_xxx')
# 1. Create checkout
checkout, error = client.checkouts.create(
amount='100.00',
currency='GMD',
description='Service payment',
)
if error:
print(f'Error: {error}')
exit()
# 2. Initialize payment with custom UI
session, error = client.payments.initialize(
client_secret=checkout['client_secret'],
payment_method='wave',
customer_phone='+2207654321',
customer_email='customer@example.com',
)
if session:
# Redirect customer to payment provider
print(f'Redirect to: {session["payment_url"]}')
Create and Send Invoice
# Create invoice
invoice, error = client.invoices.create(
customer_email='customer@example.com',
customer_name='John Doe',
items=[
{
'description': 'Web Development',
'quantity': 1,
'unit_price': '1000.00',
},
],
currency='GMD',
due_date='2024-12-31T23:59:59Z',
tax_rate=15,
)
if error:
print(f'Error: {error}')
exit()
# Send invoice to customer
client.invoices.send(invoice['id'])
# Customer can pay online at:
print(f"Payment URL: {invoice['payment_url']}")
# Or record offline payment (cash, bank transfer):
client.invoices.record_payment(
invoice['id'],
amount='1150.00',
payment_method='bank_transfer',
transaction_id='BANK-123',
notes='Received via wire transfer',
)
Bulk SMS Campaign
# 1. Create contact group
group, error = client.contact_groups.create(name='Campaign Recipients')
# 2. Add contacts
contact_ids = ['contact_1', 'contact_2', 'contact_3']
client.contact_groups.add_contacts(group['id'], contact_ids)
# 3. Create and send campaign
campaign, error = client.campaigns.create(
name='Product Launch',
message_body='Check out our new product!',
group_ids=[group['id']],
)
# Send immediately
client.campaigns.send(campaign['id'])
# Or send asynchronously (recommended for large campaigns)
client.campaigns.send_async(campaign['id'])
Type Hints
The SDK includes comprehensive type hints for better IDE support:
from typing import Tuple, Optional
from jokoor import Jokoor
from jokoor.types import PaymentLink, Checkout, Invoice
def create_payment(client: Jokoor) -> Tuple[Optional[PaymentLink], Optional[str]]:
return client.payment_links.create(
name='Test Payment',
amount='100.00',
currency='GMD',
)
# IDE will provide autocomplete and type checking
link, error = create_payment(client)
if link:
print(link['payment_url']) # IDE knows this field exists
print(link['livemode']) # Full autocomplete support
Migration from v1.x
Field Name Changes
# Invoice items field renamed
# OLD
invoice['line_items']
# NEW
invoice['items'] # Now matches API field name
# Donation campaign fields renamed
# OLD
campaign['goal_amount']
campaign['raised_amount']
# NEW
campaign['target_amount'] # Renamed for API consistency
campaign['current_amount'] # Renamed for API consistency
# Payment link URL field renamed
# OLD
link['url']
# NEW
link['payment_url'] # Now includes full hosted page URL
New Fields Available
Checkouts:
payment_url- Hosted payment page URLclient_secret- For SDK integrationlivemode- Payment mode indicator
Payment Links:
payment_url- Hosted payment page URLlivemode- Payment mode indicator
Invoices:
payment_url- Public payment URLpdf_url- PDF download URLremaining_amount- Balance remainingreceipts- Payment receipts
Donation Campaigns:
slug- SEO-friendly URL slugdonation_url- Public donation page URLdonor_count- Number of donorsprogress_percentage- Campaign progressorganizer_details- Organizer information
Rate Limiting
client = Jokoor('sk_test_xxx', max_retries=5)
Debugging
client = Jokoor('sk_test_xxx', debug=True)
# Logs all requests and responses
Support
- Documentation: https://docs.jokoor.com
- API Reference: https://docs.jokoor.com/api
- Email: hello@jokoor.com
License
MIT License - see LICENSE file for details.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file jokoor-2.0.0.tar.gz.
File metadata
- Download URL: jokoor-2.0.0.tar.gz
- Upload date:
- Size: 34.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fc7af6d5081454b24638df20ba31e9cbec60934edacabb19c99e635831eb2463
|
|
| MD5 |
faadc59f73d24efb7e7bf47b49488950
|
|
| BLAKE2b-256 |
0436a30c86177477191f581a6c8d4b7f2846767b6a3ef4109486b62254febc74
|
File details
Details for the file jokoor-2.0.0-py3-none-any.whl.
File metadata
- Download URL: jokoor-2.0.0-py3-none-any.whl
- Upload date:
- Size: 45.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b4ee9b76e3c894d04a8a32c5ca45616eb6a0bce3f1600457c4e7ae191d628e9d
|
|
| MD5 |
aad3ff11dde32f9bb459f58e333b3c9f
|
|
| BLAKE2b-256 |
7407499d9176fb9456201b878c5c01c531ffbebd60768b23079b518350dcffbc
|