This guide provides a detailed walkthrough of the paystack-api-wrapper library, covering initialization, making API calls, handling responses, robust error management, and other advanced topics.
Resources:
- API Reference - List of all available endpoints and methods.
- Webhooks Guide - How to securely handle Paystack webhooks.
- GitHub Repository
For a brief overview, see the main README.md.
First, instantiate the PaystackClient with your secret key. It is strongly recommended to store your secret key as an environment variable (e.g., PAYSTACK_SECRET_KEY) rather than hardcoding it in your application.
import os
from paystack import PaystackClient
# Best practice: load your secret key from environment variables
secret_key = os.getenv("PAYSTACK_SECRET_KEY")
if not secret_key:
raise ValueError("PAYSTACK_SECRET_KEY environment variable not set.")
# Create the client instance
client = PaystackClient(secret_key=secret_key)The client object is your gateway to all Paystack APIs.
All API resources are available as properties on the client object. The structure is intuitive and follows the pattern: client.<resource>.<method>().
For example, to access the Transactions API, you use client.transactions. To access the Customers API, you use client.customers.
from paystack.exceptions import APIError
try:
data, meta = client.customers.create(
email="customer@example.com",
first_name="John",
last_name="Doe",
phone="+2348012345678"
)
print("Customer created successfully:", data)
# Expected output: {'integration': 100032, 'domain': 'test', 'customer_code': 'CUS_123abc', ...}
except APIError as e:
print(f"An error occurred: {e.message}")from paystack.exceptions import APIError
try:
# Replace with a real transaction ID from your integration
transaction_id = 123456789
data, meta = client.transactions.fetch(transaction_id=transaction_id)
print("Transaction details:", data)
# Expected output: {'id': 123456789, 'status': 'success', 'amount': 50000, ...}
except APIError as e:
print(f"An error occurred: {e.message}")Every successful API call returns a (data, meta) tuple. This provides a consistent and predictable way to handle responses.
data: Contains the primary data from the API call. This is usually adictfor single resources (like fetching one customer) or alistofdicts for collections (like listing customers).meta: Contains metadata about the response. For paginated results, thisdictholds pagination details. For non-paginated results, it's an empty dictionary{}.
When you fetch a single item, meta is empty.
# Fetching a single plan
data, meta = client.plans.fetch(id_or_code="PLN_abcdef123")
print("Plan Data:", data)
# Plan Data: {'name': 'Monthly Plan', 'plan_code': 'PLN_abcdef123', ...}
print("Metadata:", meta)
# Metadata: {}When you list resources, meta contains pagination information.
# List the first 5 customers
data, meta = client.customers.list(per_page=5)
print(f"Total Customers: {meta.get('total')}")
print(f"Current Page: {meta.get('page')}")
print(f"Customers on this page: {len(data)}")
# Total Customers: 150
# Current Page: 1
# Customers on this page: 5The library raises specific, custom exceptions for different types of API and client-side errors. All exceptions inherit from a base PaystackError, so you can catch it to handle any error from the library.
Here is the hierarchy of exceptions, found in paystack.exceptions:
PaystackError(Base class)APIError: A generic error returned by the Paystack API (e.g., for non-2xx status codes that don't fit other categories).AuthenticationError: (HTTP 401) Raised for invalid or missing API keys.ValidationError: (HTTP 400) Raised when request data is invalid. This can be due to missing required fields, invalid formats (like a bad email), or malformed data. Thefield_errorsattribute may contain a dictionary of specific field issues.NotFoundError: (HTTP 404) Raised when a requested resource (like a transaction or customer) doesn't exist.RateLimitError: (HTTP 429) Raised when you exceed API rate limits. Theretry_afterattribute may contain the number of seconds to wait before retrying.ServerError: (HTTP 5xx) Raised for server-side errors on Paystack's end. These are often temporary.NetworkError: Raised for client-side network issues like connection timeouts or DNS failures.InvalidResponseError: Raised if the API returns an unexpected or malformed JSON response.TransactionFailureError: A special case for when a transaction fails but Paystack returns an HTTP 200 status. This happens for charge and verify requests. Check thegateway_responseattribute for more details from the payment gateway.
from paystack.exceptions import (
PaystackError,
AuthenticationError,
ValidationError,
NotFoundError,
TransactionFailureError,
NetworkError
)
try:
# An example call that could fail
data, meta = client.transactions.verify(reference="an-invalid-reference")
# Check for transaction failure even on HTTP 200
if data.get('status') != 'success':
# This case is handled by TransactionFailureError, but you can also check manually
print(f"Transaction was not successful: {data.get('gateway_response')}")
except ValidationError as e:
print(f"Validation Error: {e.message}")
if e.field_errors:
print(f"Field-specific errors: {e.field_errors}")
except AuthenticationError as e:
print(f"Authentication Error: Please check your API key. Details: {e.message}")
except NotFoundError as e:
print(f"Resource Not Found: {e.message}")
except TransactionFailureError as e:
print(f"Transaction Failed: {e.message}")
if e.gateway_response:
print(f"Gateway Response: {e.gateway_response}")
except NetworkError as e:
print(f"Network Error: Could not connect to Paystack. Details: {e.message}")
except PaystackError as e:
# Catch any other Paystack-specific error
print(f"A Paystack API error occurred: {e.message}")
if e.status_code:
print(f"HTTP Status: {e.status_code}")
except Exception as e:
# Catch any other unexpected Python error
print(f"An unexpected error occurred: {e}")For endpoints that return a list of items, you can navigate through pages using the per_page and page parameters. The meta object in the response provides the necessary details to build your pagination logic.
from paystack.exceptions import APIError
# Fetch all customers, 50 at a time (Paystack's default and max is 50)
page = 1
has_more = True
while has_more:
try:
customers, meta = client.customers.list(per_page=50, page=page)
if not customers:
# No more customers to fetch
break
print(f"--- Page {page} ---")
for customer in customers:
print(f"Processing customer: {customer['customer_code']}")
# Check if there are more pages
total_customers = meta.get('total', 0)
fetched_customers = (page * 50)
if fetched_customers >= total_customers:
has_more = False
else:
page += 1
except APIError as e:
print(f"Error fetching page {page}: {e.message}")
breakThe library performs basic validation on some required fields before sending a request to the Paystack API. This can help catch simple errors early without making an unnecessary API call. If validation fails, a ValidationError is raised.
For example, the transactions.initialize method requires a valid email format and a numeric amount.
from paystack.exceptions import ValidationError
# Example of invalid email
try:
client.transactions.initialize(email="not-an-email", amount=5000)
except ValidationError as e:
print(f"Caught expected error: {e}")
# Caught expected error: Invalid email address provided.
# Example of invalid amount
try:
client.transactions.initialize(email="customer@example.com", amount="five-thousand")
except ValidationError as e:
print(f"Caught expected error: {e}")
# Caught expected error: Amount must be a valid number.