Skip to content

feat: add Paystack recurring payment plans (#310)#421

Closed
Ginaonuh wants to merge 1 commit into
JosephOnuh:mainfrom
Ginaonuh:feat/paystack-recurring-310
Closed

feat: add Paystack recurring payment plans (#310)#421
Ginaonuh wants to merge 1 commit into
JosephOnuh:mainfrom
Ginaonuh:feat/paystack-recurring-310

Conversation

@Ginaonuh
Copy link
Copy Markdown

@Ginaonuh Ginaonuh commented Jun 1, 2026

Summary

Resolves #310 — Add Paystack recurring payment plans for automated circle contributions.

Acceptance Criteria

Criterion Implementation
✅ Paystack plan created when circle is created createPlan() called in createCircle(), plan code stored in circles.paystack_plan_code
✅ Members subscribe to plan on join subscribeToPlan() called in joinCircle() when authorizationCode provided, code stored in members.paystack_subscription_code
✅ Subscription auto-charges on cycle date Handled by Paystack's plan interval (weekly/biweekly/monthly mapped from cycleFrequency)
✅ Failed charge triggers notification subscription.charge_failed webhook event sends SMS via notifySubscriptionChargeFailed()

Changes

  • src/lib/paystack.ts — Added createPlan(), subscribeToPlan(), cancelSubscription()
  • src/server/services/circle.service.tscreateCircle() creates a Paystack plan (best-effort, non-blocking on failure); joinCircle() accepts optional paystackAuthCode and subscribes active members
  • src/types/schemas.ts — Added optional authorizationCode to joinCircleSchema
  • src/app/api/v1/circles/[id]/join/route.ts + legacy — Pass authorizationCode through to joinCircle()
  • src/app/api/v1/webhooks/paystack/route.ts + legacy — Handle subscription.charge_failed: look up member by paystack_subscription_code, send SMS
  • src/lib/sms.ts — Added sendSubscriptionChargeFailedSms()
  • src/server/services/notification.service.ts — Added notifySubscriptionChargeFailed()
  • migrations/1748700000000_add-paystack-recurring.ts — Adds paystack_plan_code to circles, paystack_subscription_code to members

Notes

  • Plan creation and subscription are best-effort: failures are logged but do not block circle creation or joining
  • The client must obtain a Paystack authorization_code (from a prior transaction) and pass it in the join request body as authorizationCode
  • cancelSubscription() is exported for future use when a member leaves or a circle is cancelled

- paystack.ts: add createPlan(), subscribeToPlan(), cancelSubscription()
- circle.service: call createPlan() on circle creation, store paystack_plan_code
- circle.service: call subscribeToPlan() on join when plan + auth code present,
  store paystack_subscription_code on member row
- schemas: add optional authorizationCode to joinCircleSchema
- join routes (v1 + legacy): pass authorizationCode through to joinCircle()
- webhook (v1 + legacy): handle subscription.charge_failed — look up member
  by subscription code and send SMS notification via notifySubscriptionChargeFailed()
- sms.ts: add sendSubscriptionChargeFailedSms()
- notification.service: add notifySubscriptionChargeFailed()
- migration: add paystack_plan_code to circles, paystack_subscription_code to members

Closes JosephOnuh#310
@drips-wave
Copy link
Copy Markdown

drips-wave Bot commented Jun 1, 2026

@Ginaonuh Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@JosephOnuh JosephOnuh closed this Jun 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Paystack payment plan for recurring contributions

2 participants