feat(paya): Level 3 line-item data for Paya commercial-card transactions - #1
Open
dnplkndll wants to merge 1 commit into
Open
feat(paya): Level 3 line-item data for Paya commercial-card transactions#1dnplkndll wants to merge 1 commit into
dnplkndll wants to merge 1 commit into
Conversation
Scaffolds a Saleor Payment App for the Paya / Sage Payments Bankcard API. The reason for building it rather than reusing an existing gateway app is Level 3. Paya attaches a default Level 3 record to commercial-card transactions, which qualifies partially and no further. Full line-item detail has to be POSTed to /v2/transactionlevel3s, and that is what earns the interchange reduction of roughly 0.5-1.5% on a commercial card. On a ~$2,250 average order that is $11-34 per order. The WooCommerce gateway the legacy DuroPC store used never made that call, so the old store qualified on Paya's defaults only. Visa retired standalone Level 2 interchange on 18 April 2026 under its Commercial Enhanced Data Program, so on Visa it is now full Level 3 or no discount. The mapping therefore always emits the Visa-required order-level tax rate and per-item commodity code rather than treating them as optional; a missing commodity code fails the line rather than degrading it, so unclassified products get the UNSPSC 'unable to classify' placeholder. Two behaviours are encoded because they are easy to get wrong and expensive to discover late. Each POST to /v2/transactionlevel3s overwrites the previous Level 3 data rather than merging, so the client method is named replace and always sends the complete set. And tax rates are derived from the amounts rather than passed alongside them, because a rate supplied independently can disagree with the amounts after rounding and the processor rejects the record. Includes isLevel3EnabledForLocation(), which performs the check Paya documents for whether a merchant location is actually enabled. This matters before trusting any of the above: a correct integration on a location the processor has not enabled qualifies for nothing, and eligibility varies by backend processor. No code is derived from the legacy WooCommerce plugin. It is GPL v3, this repository is BSD-3, and the licences are incompatible; it was read only to establish that the account uses the v2 REST API rather than the older eftbankcard.dll endpoint. Writing fresh from the public API docs is also what keeps an upstream contribution possible. The six payment webhooks are not yet wired to authorise/capture calls. Claude-Session: https://claude.ai/code/session_016SKxntFG3G68SS5jQDnPpf
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
Scaffolds
apps/paya, a Saleor Payment App for the Paya / Sage Payments Bankcard API. Level 3 is implemented first because it is the reason to build the app at all.Level 3 line-item data
Paya attaches a default Level 3 record to commercial-card transactions, which qualifies partially and no further. Full line-item detail must be POSTed to
/v2/transactionlevel3s, and that is what earns the interchange reduction of roughly 0.5–1.5% on a commercial card. On a ~$2,250 average order that is $11–34 per order. The WooCommerce gateway the legacy DuroPC store used never made that call, so the old store qualified on Paya's defaults only.Visa retired standalone Level 2 interchange on 18 April 2026 under its Commercial Enhanced Data Program, so on Visa it is now full Level 3 or no discount at all. Mastercard still recognises both.
Three behaviours are encoded because they are easy to get wrong and expensive to discover late:
replaceLevel3Data, notupdate. Each POST overwrites the previous Level 3 data rather than merging, so the payload is always complete.Enablement check
isLevel3EnabledForLocation()runs the check Paya documents. This matters before trusting any of the above: a correct integration on a location the processor has not enabled qualifies for nothing, and eligibility varies by backend processor (TSYS, FirstData, Vantiv).Provenance
No code is derived from the legacy WooCommerce gateway plugin. It is GPL v3, this repository is BSD-3, and the licences are incompatible. The plugin was read only to establish that the merchant account uses the v2 REST API at
api.sagepayments.comrather than the oldereftbankcard.dllendpoint. Writing fresh from the public API docs is also what keeps an upstream contribution tosaleor/appspossible.Tests
7 unit tests passing over the Level 3 mapping.
Not in this PR
The six payment webhooks have directories but no handlers:
PAYMENT_GATEWAY_INITIALIZE_SESSION,TRANSACTION_INITIALIZE_SESSION,TRANSACTION_PROCESS_SESSION,TRANSACTION_CHARGE_REQUESTED,TRANSACTION_REFUND_REQUESTED,TRANSACTION_CANCELATION_REQUESTED. There is also no manifest or register route yet, so the app cannot be installed into Saleor from this branch.Note that the Saleor payment-apps documentation page lists only three of those six events; the first-party Stripe app implements all six, which is the contract this app will follow.
Blocked on two external answers: whether the merchant location is enabled for Level 3, and credentials for the certification environment so authorise/capture can be exercised against the sandbox rather than written blind.
https://claude.ai/code/session_016SKxntFG3G68SS5jQDnPpf