Official PalPluss Python SDK
Project description
PalPluss Python SDK
Official Python SDK for the PalPluss payments API — accept M-Pesa STK Push payments, send B2C payouts, and manage your service wallet from Python.
Requirements
- Python >= 3.9
httpx>= 0.27
Installation
pip install palpluss
Quick start
from palpluss import PalPluss
client = PalPluss(api_key="pk_live_your_api_key")
# STK Push (Lipa na M-Pesa)
result = client.stk_push(
amount=500,
phone="254712345678",
account_reference="ORDER-001",
)
print(result["transactionId"]) # "tx_..."
print(result["status"]) # "PENDING"
Async usage
import asyncio
from palpluss import AsyncPalPluss
async def main():
async with AsyncPalPluss(api_key="pk_live_your_api_key") as client:
result = await client.stk_push(amount=500, phone="254712345678")
print(result["transactionId"])
asyncio.run(main())
Configuration
| Parameter | Type | Default | Description |
|---|---|---|---|
api_key |
str |
PALPLUSS_API_KEY env var |
Your PalPluss API key |
timeout |
float |
30.0 |
Request timeout in seconds |
auto_retry_on_rate_limit |
bool |
True |
Auto-retry on HTTP 429 |
max_retries |
int |
3 |
Max retry attempts |
Set PALPLUSS_BASE_URL to override the API base URL (e.g. for sandbox).
API Reference
STK Push
result = client.stk_push(
amount=500, # Required: amount in KES
phone="254712345678", # Required: recipient phone
account_reference="ORDER-001", # Optional
transaction_desc="Payment", # Optional
channel_id="ch_...", # Optional
callback_url="https://...", # Optional
credential_id="cred_...", # Optional
)
B2C Payout
result = client.b2c_payout(
amount=1000,
phone="254712345678",
reference="PAY-001", # Optional
description="Salary", # Optional
idempotency_key="my-unique-key", # Optional — auto-generated if omitted
)
Service Wallet
# Get balance
balance = client.get_service_balance()
print(balance["availableBalance"])
# Topup
topup = client.service_topup(
amount=5000,
phone="254712345678",
idempotency_key="topup-001", # Optional — caller must provide for safe retry
)
Transactions
# Get single transaction
tx = client.get_transaction("tx_...")
# List transactions (cursor-based pagination)
page = client.list_transactions(limit=20, status="SUCCESS", type="STK")
print(page["items"])
print(page["next_cursor"]) # pass to next call, or None when exhausted
# Pagination
cursor = page["next_cursor"]
while cursor:
page = client.list_transactions(limit=20, cursor=cursor)
print(page["items"])
cursor = page["next_cursor"]
Payment Wallet Channels
# Create
channel = client.create_channel(
type="PAYBILL",
shortcode="123456",
name="Main Paybill",
)
# Update
channel = client.update_channel("ch_...", name="Updated Name")
# Delete
client.delete_channel("ch_...")
Webhooks
from palpluss import parse_webhook_payload
# In your webhook endpoint handler:
def webhook_handler(request_body: str):
payload = parse_webhook_payload(request_body)
print(payload["event_type"]) # "transaction.success"
print(payload["transaction"]["status"]) # "SUCCESS"
Error handling
from palpluss import PalPluss, PalPlussApiError, RateLimitError
client = PalPluss(api_key="pk_live_...")
try:
result = client.stk_push(amount=500, phone="bad-phone")
except RateLimitError as e:
print(f"Rate limited, retry after {e.retry_after}s")
except PalPlussApiError as e:
print(f"API error [{e.code}] {e.http_status}: {e}")
print(f"Request ID: {e.request_id}")
Error attributes
| Attribute | Type | Description |
|---|---|---|
message |
str |
Human-readable error message |
code |
str |
Machine-readable code (e.g. INVALID_PHONE) |
http_status |
int |
HTTP status code |
details |
dict |
Additional error context |
request_id |
str | None |
Trace ID for support |
RateLimitError additionally exposes retry_after: int | None (seconds).
Context manager
# Sync
with PalPluss(api_key="pk_live_...") as client:
result = client.stk_push(amount=500, phone="254712345678")
# Async
async with AsyncPalPluss(api_key="pk_live_...") as client:
result = await client.stk_push(amount=500, phone="254712345678")
Or call .close() / await .close() manually when done.
Development
# Install with dev dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Type check
mypy palpluss
# Lint
ruff check palpluss
Design
- Flat public API — one obvious way to do each thing
- Zero magic — no hidden side effects
- Typed — full type annotations, TypedDict responses, ships with
py.typed - Transport isolation — HTTP concerns in
palpluss.http - No phone normalization — pass numbers as-is
- No SDK-side validation — trust the server
Links
Project details
Release history Release notifications | RSS feed
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 palpluss-0.1.0.tar.gz.
File metadata
- Download URL: palpluss-0.1.0.tar.gz
- Upload date:
- Size: 9.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
15aa7bbac9f3c5dbc8ad53bbffe856c9093db69baf764ef086d88053db535323
|
|
| MD5 |
4dcd707509bdd00c68537f2e412c91f9
|
|
| BLAKE2b-256 |
42a55a0559231841efce68e9ed0688ee9d8dedf0f1fde1f8cc044ae31524cec0
|
Provenance
The following attestation bundles were made for palpluss-0.1.0.tar.gz:
Publisher:
release-python.yml on Palpluss/Palpluss-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
palpluss-0.1.0.tar.gz -
Subject digest:
15aa7bbac9f3c5dbc8ad53bbffe856c9093db69baf764ef086d88053db535323 - Sigstore transparency entry: 1173401379
- Sigstore integration time:
-
Permalink:
Palpluss/Palpluss-sdk@a50db9d7a1b16111a4480034765c47d15e0ce0ce -
Branch / Tag:
refs/tags/python-v0.1.1 - Owner: https://github.com/Palpluss
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release-python.yml@a50db9d7a1b16111a4480034765c47d15e0ce0ce -
Trigger Event:
push
-
Statement type:
File details
Details for the file palpluss-0.1.0-py3-none-any.whl.
File metadata
- Download URL: palpluss-0.1.0-py3-none-any.whl
- Upload date:
- Size: 15.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
69c2ec84e03362c6f465003d58804466d6588e9a190d7ec89129115f032645cb
|
|
| MD5 |
96952181aed41006b75b8eea973866ad
|
|
| BLAKE2b-256 |
bd570a6119dfd1b384db5f72b3b68eb6518ec88a4581090031c3ff672d0fb43a
|
Provenance
The following attestation bundles were made for palpluss-0.1.0-py3-none-any.whl:
Publisher:
release-python.yml on Palpluss/Palpluss-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
palpluss-0.1.0-py3-none-any.whl -
Subject digest:
69c2ec84e03362c6f465003d58804466d6588e9a190d7ec89129115f032645cb - Sigstore transparency entry: 1173401454
- Sigstore integration time:
-
Permalink:
Palpluss/Palpluss-sdk@a50db9d7a1b16111a4480034765c47d15e0ce0ce -
Branch / Tag:
refs/tags/python-v0.1.1 - Owner: https://github.com/Palpluss
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release-python.yml@a50db9d7a1b16111a4480034765c47d15e0ce0ce -
Trigger Event:
push
-
Statement type: