Skip to content

feat(payments): add payment link generation with configurable expiry - #1873

Merged
github-actions[bot] merged 1 commit into
Smartdevs17:mainfrom
JohnMabas:feat/1713-payment-link-generation
Oct 21, 2026
Merged

github-actions[bot] merged 1 commit into
Smartdevs17:mainfrom
JohnMabas:feat/1713-payment-link-generation

Conversation

@JohnMabas

Copy link
Copy Markdown
Contributor

Summary

Implements signed, expirable payment links with revoke capability for merchants, closing #1713.

Merchants need shareable payment links that stop working after a set time. This PR introduces a PaymentLinkService that generates HMAC-SHA256 signed, unguessable links and lets merchants revoke them at any time.

What was built

backend/services/payment/domain/paymentLinkService.ts

  • PaymentLinkService — core service with injectable store and clock for full testability
  • Signed and unguessable tokens: each link carries an HMAC-SHA256 signature over id + merchantId + amount + currency + expiresAt using a per-merchant signingSecret; tokens cannot be guessed or forged
  • Configurable expiry: MerchantPaymentLinkConfig.defaultExpirySeconds sets the default TTL; callers can also supply a custom expirySeconds per link
  • Revoke capability: revokeLink(id) stamps revokedAt and sets status = 'revoked'; subsequent validateLink calls reject with reason: 'revoked'
  • validateLink(id, token) returns a typed ValidationResult — callers never need to catch exceptions for expected failure cases
  • createLink / getLink / listLinks round out the API
  • PaymentLinkStore interface + InMemoryPaymentLinkStore for easy swap to a DB-backed store

backend/services/payment/__tests__/paymentLinkService.test.ts

  • 37 unit tests covering: token generation, signature verification, wrong-token rejection, expiry, revocation, idempotent revocation, listing by merchant, unknown-ID handling, custom expiry, and store isolation

Acceptance criteria

  • Links are signed and unguessable (HMAC-SHA256 over canonical fields with merchant secret)
  • Expiry is configurable (per-merchant default + per-link override)
  • Revoked links are rejected (validateLink returns { valid: false, reason: 'revoked' })

Testing

npx jest --config jest.backend.config.js --testPathPattern=paymentLinkService

All 37 tests pass.

Closes #1713

@drips-wave

drips-wave Bot commented Oct 21, 2026

Copy link
Copy Markdown

@JohnMabas 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

@github-actions
github-actions Bot merged commit 750fda8 into Smartdevs17:main Oct 21, 2026
8 of 24 checks passed
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 payment link generation with configurable expiry

1 participant