Phase 3 — ClickPesa integration + PaymentProvider trait #4
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Tracks s2-005 work for the Hero onboarding parallel track (Agent 2 / Track B). Sub-issue of #1 (meta-issue / full plan).
ClickPesa docs: https://docs.clickpesa.com/
Scope
Introduce a
PaymentProvidertrait incrates/hero_onboarding_server/src/payment.rs, extract the Phase 2 Stripe code site behind it asStripeProvider, then addClickPesaProvideras the second impl. The freezone in-house backend (znzfreezone/src/znzfreezone_code/znzfreezone_backend/src/providers/payment.rs, 520 LOC) is production-validated against the live ClickPesa API and lifts cleanly — wire shape, two-step Bearer-token auth, and webhook handling are taken verbatim modulo refactoringureqblocking →reqwestasync to match our axum/tokio stack.Phase B simplified the trait shape: ClickPesa Checkout Link returns a hosted-URL redirect just like Stripe Checkout, so no
TopUpHandoffenum needed; both providers return a plainStringredirect URL.Trait
Both providers return a plain
Stringredirect URL; the webhook handler inmain.rsruns identical dedup-on-external_ref+ apply-credit logic regardless of provider.ClickPesa specifics (from freezone lift)
POST /generate-tokenwith headersclient-id+api-key→ JWT → Bearer onPOST /checkout-link/generate-checkout-url.{ totalPrice, orderReference, orderCurrency, description, customerEmail, notificationUrl, redirectUrl }.orderReferencemust be alphanumeric-only (our SIDs are 26-char ULIDs, already alphanumeric).{ data: { orderReference, status, id } }. Dedup onorderReference; success onstatus == "success".onboarding):CLICKPESA_CLIENT_ID,CLICKPESA_API_KEY. Env-var fallback for dev.CLICKPESA_API_URL(defaulthttps://api.clickpesa.com/third-parties),CLICKPESA_WEBHOOK_URL(the public URL ClickPesa POSTs to; passed asnotificationUrlin checkout requests).Webhook signature stance — freezone-aligned, launch-day TODO
The production freezone impl does no ClickPesa webhook signature verification — it trusts the body shape + dedups on
orderReference. User confirms this is production-stable. Lifting verbatim.This ships a clearly-marked launch-day TODO: a follow-up issue will track enabling signature verification (either ClickPesa's official scheme if/when documented, or an HMAC-over-body MAC against
CLICKPESA_WEBHOOK_SIGNING_KEYif not). The env-var placeholder is plumbed through so flipping the verifier on at launch is a config change, not a code change.Similarly for Stripe: signing key already env-var/secret-store backed; production webhook URL setup in the Stripe dashboard happens at launch, not today.
Routes
POST /payment/intent— adds optionalproviderform/query field; defaults tostripe.POST /webhooks/stripe— existing, unchanged behaviour.POST /webhooks/clickpesa— new (body-trust, dedup onorderReference).Acceptance gates
cargo check --workspacegreen.cargo test -p hero_onboarding_servergreen (Stripe sig verifier unit tests preserved; ClickPesa webhook-body parser unit tests added).lab build --release --install --workspaceVICTORY.lab infocheck3/3 clean.scripts/smoke_payments.sh~20 white-box checks covering both providers' webhook flows.Decision lock
D-13 — payment-provider-trait — locks the trait shape + ClickPesa freezone-aligned body-trust stance + launch-day signature TODO.
Out of scope