agentsclimarketplace

Payfast

Skill tzone85/sa-fintech-skills/skills/payfast

PayFast (SA) integration — generate form-post MD5 signatures in the documented field order with URL-encoded values, and verify ITN POST signatures using the same algorithm.From its SKILL.md

Install
npx -y skills add tzone85/sa-fintech-skills --skill payfast

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

5.6 KB, ~1.3k tokens by cl100k_base, as published. Nobody here has run it

PayFast — South African payment integration

Use when the user is wiring a frontend or backend to PayFast for South African card / EFT / Instant EFT / wallet payments. PayFast is form-post + ITN (Instant Transaction Notification) callback, not REST. The signing algorithm is the #1 source of integration failure — get it exactly right.

Triggers

  • "payfast"
  • "ITN"
  • "instant transaction notification"
  • "signature mismatch"
  • "merchant_id"
  • "m_payment_id"
  • "passphrase"
  • "sandbox.payfast.co.za"
  • "process.payfast"

Examples

Canonical signature algorithm

PayFast's signature algorithm is documented in their PHP reference. Replicating it precisely is the only way the signatures match. The algorithm in TypeScript:

for each (key, value) in fields_in_documented_order:
    if value === "" then skip
    output += key + "=" + phpUrlEncode(value.trim()) + "&"
output = output.slice(0, -1)          # drop trailing &
if passphrase:
    output += "&passphrase=" + phpUrlEncode(passphrase.trim())
md5(output).hex()

Three rules that trip everyone up:

  1. Field order matters and it is NOT alphabetical. The "attributes description" order from the docs is canonical: merchant_id, merchant_key, return_url, cancel_url, notify_url, name_first, name_last, email_address, cell_number, m_payment_id, amount, item_name, item_description, custom_int1..5, custom_str1..5, email_confirmation, confirmation_address, payment_method, subscription_type, billing_date, recurring_amount, frequency, cycles, subscription_notify_email, subscription_notify_webhook, subscription_notify_buyer. PayFast explicitly warns: do not use the alphabetical API-signature ordering for form posts and ITNs.
  2. URL-encode with PHP semantics — spaces become +, not %20. encodeURIComponent in JavaScript uses %20 and will mismatch. Implement a small phpUrlEncode helper that calls encodeURIComponent then replaces %20 with +.
  3. Empty fields are skipped, not included as key=. And value.trim() strips leading/trailing whitespace before encoding.

ITN four-step validation (do all four)

  1. Verify signature — same algorithm as form-post, using the fields exactly as PayFast posted them (preserving the order in which they arrived).
  2. Source-IP check — PayFast publishes ITN IP ranges (https://www.payfast.co.za/notify_method/host). Reject ITNs from any other source.
  3. Data integrity round-trip — POST the entire received body back to https://sandbox.payfast.co.za/eng/query/validate (sandbox) or https://www.payfast.co.za/eng/query/validate (live) and expect VALID in the response.
  4. Internal sanity checkamount_gross matches the order, m_payment_id matches an open order in your DB, payment isn't already marked complete (idempotency).

Skip any one of the four and you can be replay-attacked or spoofed.

URLs

EnvironmentForm POST URLValidate URL
Sandboxhttps://sandbox.payfast.co.za/eng/processhttps://sandbox.payfast.co.za/eng/query/validate
Livehttps://www.payfast.co.za/eng/processhttps://www.payfast.co.za/eng/query/validate

Use m_payment_id (your own UUID) as the idempotency key everywhere you persist ITN data.

Common mistakes

  • URL-encoding spaces as %20 instead of + — signature mismatches every time. Use a PHP-compatible encoder.
  • Sorting fields alphabetically — that is the API-signature format, not the form-post format. PayFast warns against this in the docs.
  • Including empty fields — the algorithm skips them. Including cell_number=& when the buyer didn't provide one will break the hash.
  • Not trimming values before encoding — leading/trailing whitespace from a textarea can silently break the signature.
  • Trusting an ITN that passes signature only — without IP + validate-endpoint + DB sanity check, an attacker who can guess your passphrase or grab one valid ITN can replay it.
  • Using encodeURIComponent without the + substitution — equivalent to mistake #1 above.

Configuration

  • PAYFAST_MERCHANT_ID, PAYFAST_MERCHANT_KEY, PAYFAST_PASSPHRASE from the Merchant Dashboard. Sandbox values from https://sandbox.payfast.co.za.
  • The passphrase is optional but every PayFast support page recommends setting one.
  • The ITN URL (notify_url) must be HTTPS and reachable from PayFast's IPs.

See also

What ships with it: 5 files

12.1 KB alongside SKILL.md, 3 of them executable

examples/

Keep looking

Skills are one crate of 326,782. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.