PayFast ITN "Invalid signature" in WooCommerce
Your PayFast log says Invalid signature or Security signature mismatch, and orders stay pending. Here is what the signature is and why it breaks.
How PayFast signs a notification
PayFast takes every field it posts to your notify URL, in the order it sends them, and joins them as name=value pairs with &. Values are URL encoded with upper-case hex (%3A, not %3a) and spaces as +. If you set a salt passphrase in your PayFast account, &passphrase=... is added to the end. The MD5 hash of that string is the signature field.
Your plugin rebuilds the same string from what it received and compares the hashes. Any difference in one character gives "Invalid signature".
Cause 1 (most common): the passphrase does not match
- A passphrase is set in PayFast but the plugin field is empty, or the reverse.
- A space or line break was copied in with the passphrase.
- You are in sandbox mode but entered your live passphrase, or the other way round. Sandbox and live are separate accounts with separate passphrases.
Fix: in your PayFast dashboard go to Settings, set a new Salt Passphrase, save, then paste the same value into your plugin's passphrase field for the same mode (live or sandbox). WooCommerce's own PayFast documentation gives the same advice: if the passphrases look identical, reset it and copy it again. See also PayFast passphrase mismatch.
Cause 2: the plugin rebuilds the string differently
PayFast's help centre names the second cause: the variables are hashed in the wrong order. Other ways plugins get it wrong:
- dropping empty fields (for example an empty
custom_str1) before hashing, while PayFast includes them; - trimming or re-decoding values instead of using them exactly as posted;
- lower-case URL encoding, or
%20instead of+for spaces.
If the passphrase is definitely right and you still see the error, update the plugin. If you wrote the integration yourself, compare your string building line by line with the PHP example in PayFast's developer docs (the pfValidSignature function).
We hit this ourselves: version 0.1.1 of our plugin skipped empty fields and rejected genuine sandbox notifications. Version 0.1.2 fixed it by hashing every posted field exactly as received.
Cause 3: the wrong sandbox account
PayFast's shared sandbox has more than one test merchant. Subscriptions, tokenization and anything that needs a passphrase must use a sandbox merchant that has a passphrase set, or your own sandbox account (create one at sandbox.payfast.co.za and set its Salt Passphrase under Settings).
Our plugin
Skillmerc Payment Gateway for PayFast is free on WordPress.org. It ships with working sandbox credentials (a sandbox merchant with a passphrase), keeps separate sandbox and live credentials, and its debug log records each notification it received followed by the reason it was rejected, such as "ITN rejected: signature mismatch". It is independent and not made by PayFast.