How to build a local AI product with Nigerian naira pricing
Local AI service deployed, Paystack integration, naira pricing strategy
What this does
Packaging a local AI service as a monetized product requires integrating Paystack for naira-denominated payments, defining subscription tiers, and handling payment webhooks. This guide covers currency display with the ₦ symbol, tier configuration, webhook verification, and subscription management for Nigerian customers.
Steps
1. Install Paystack SDK
pip install paystackpy python-dotenv
2. Define subscription tiers
TIERS = {
"starter": {
"name": "Starter",
"price_ngn": 5_000,
"display": "₦5,000/month",
"requests_per_month": 1_000,
"features": ["basic_ai_access", "email_support"],
},
"professional": {
"name": "Professional",
"price_ngn": 15_000,
"display": "₦15,000/month",
"requests_per_month": 10_000,
"features": ["advanced_ai_access", "priority_support", "api_access"],
},
"enterprise": {
"name": "Enterprise",
"price_gn": 50_000,
"display": "₦50,000/month",
"requests_per_month": -1, # unlimited
"features": ["full_access", "dedicated_support", "sla"],
},
}
3. Initialize Paystack and create a subscription
import paystackpy as paystack
from dotenv import load_dotenv
load_dotenv()
ps = paystack.Paystack(secret_key=os.getenv("PAYSTACK_SECRET_KEY"))
def create_subscription(email: str, tier: str) -> dict:
plan_code = f"ai_{tier}_monthly"
return ps.subscription.create(
email=email,
plan=plan_code,
)
4. Build the webhook handler Verify Paystack webhook signatures to prevent spoofed payment notifications:
import hmac, hashlib
from fastapi import FastAPI, Request, HTTPException
app = FastAPI()
@app.post("/webhook/paystack")
async def paystack_webhook(request: Request):
payload = await request.body()
signature = request.headers.get("x-paystack-signature")
expected = hmac.new(
os.getenv("PAYSTACK_WEBHOOK_SECRET").encode(),
payload, hashlib.sha512
).hexdigest()
if signature != expected:
raise HTTPException(status_code=403, detail="Invalid signature")
event = await request.json()
if event["event"] == "charge.success":
await activate_subscription(event["data"]["customer"]["email"])
return {"status": "received"}
5. Display prices in naira throughout the UI Use the Intl.NumberFormat API for consistent formatting:
const formatter = new Intl.NumberFormat('en-NG', {
style: 'currency',
currency: 'NGN',
minimumFractionDigits: 0,
});
// formatter.format(15000) → "₦15,000"
- Record the local run evidence. Save the exact command, runtime or package version, model name if applicable, and observed output so the result can be reproduced later.
Verification
Test the subscription creation:
curl -X POST http://localhost:8000/subscription \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","tier":"professional"}'
Expected: {"status":"success","subscription_code":"SUB_xxx","amount_display":"₦15,000/month"}
Test the webhook locally:
curl -X POST http://localhost:8000/webhook/paystack \
-H "Content-Type: application/json" \
-H "x-paystack-signature: <valid_hmac_hex>" \
-d '{"event":"charge.success","data":{"customer":{"email":"[email protected]"}}}'
Expected: {"status":"received"} with HTTP 200
Common failures
- Currency display mismatch: Always store prices as integers in kobo (smallest unit) and convert to naira at display time to avoid floating-point rounding errors.
- Webhook replay attacks: Validate the signature on every request and maintain a deduplication log using the payment reference to prevent processing the same event twice.
- Failed webhook verification in test mode: Paystack test mode requires a valid test secret key. Never hardcode production keys in development.
- Subscription renewal failures: Set up a daily reconciliation job that checks subscription expiry dates and sends renewal reminders 3 days before expiration.
Related guides
- How to set up agent scheduling with cron and triggers — A nightly reconciliation agent syncs Paystack subscription status and deactivates expired accounts.
- How to build an AI content generation pipeline — The content pipeline becomes the core product feature that subscribers pay for via these tiers.