PayFast Cancel Subscription API Getting 401 “Merchant authorization failed

Hi everyone,

I’m trying to integrate PayFast Cancel Subscription API in my Bubble app, but I keep getting the same error every time I call the endpoint.

Status code 401
{
“code”: 401,
“status”: “failed”,
“data”: {
“response”: “Merchant authorization failed.”,
“message”: false
}
}
What I’m Doing

  • I’m using the official PayFast endpoint to cancel a subscription.

  • I pass merchant_id, passphrase / signature, and other required fields.

  • The API connector is set to POST.

  • The subscription ID is correct.

  • I tested with both live and sandbox credentials.

Still getting the same 401 error.

Questions

  1. Does anyone know the correct way to authenticate PayFast’s subscription-cancel API in Bubble?

  2. Do I need to generate a signature differently?

  3. For sandbox mode, should I use a different passphrase or encoding method?

Any help or example setup would be appreciated. Thank you!

Hi! That 401 error usually means something is off with the authentication. With PayFast, the signature/passphrase must match exactly what they expect, and the parameters need to be in the right order and encoding.

A few things to check: make sure you’re using the correct passphrase for live vs sandbox. Sandbox and live credentials are separate, so using one with the other will fail. Also, PayFast requires the POST body to be URL-encoded exactly as documented, otherwise the signature won’t match.

In Bubble’s API Connector, set the method to POST, add the body parameters as form-data or JSON depending on their docs, and include merchant_id + subscription_id + signature. You might need to generate the signature dynamically in Bubble if it includes timestamp or parameter concatenation.

Here’s the answer for the PayFast 401 “Merchant authorization failed” error:​

Problem: Getting 401 authorization error when calling PayFast Cancel Subscription API from Bubble despite using correct merchant_id and subscription_id.

Root Cause: PayFast authentication requires a correctly generated signature/passphrase that must match exactly what their system expects. The issue is usually with signature generation or parameter formatting.

Solutions:

1. Signature Generation Issue:
PayFast requires parameters to be concatenated in a specific order with the passphrase, then MD5 hashed. The signature format is:

text

parameter1=value1&parameter2=value2&passphrase=your_passphrase

Then MD5 hash this entire string.

2. Correct Setup in Bubble API Connector:

  • Method: PUT (not POST) - PayFast cancel subscription uses PUT

  • Content type: application/x-www-form-urlencoded

  • Endpoint: https://api.payfast.co.za/subscriptions/{token}/cancel

  • Headers:

    • merchant-id: your merchant ID

    • version: v1

    • timestamp: ISO 8601 format (e.g., 2025-12-01T19:00:00+02:00)

    • signature: MD5 hash generated from parameters

3. Parameter Order Matters:

Alphabetically order ALL parameters (including merchant-id, version, timestamp) before hashing.

4. Sandbox vs Live:

  • Sandbox merchant ID: 10000100

  • Sandbox passphrase: (different from live)

  • Make sure you’re using matching credentials for the environment

5. Dynamic Signature Generation in Bubble:

You need to generate the signature dynamically because it includes a timestamp. Use a backend workflow or plugin to:

  • Concatenate: merchant-id={id}&passphrase={passphrase}&timestamp={timestamp}&version=v1

  • Generate MD5 hash

  • Pass this as the signature header

6. Working Example Setup:

text

URL: https://api.payfast.co.za/subscriptions/{subscription_token}/cancel
Method: PUT
Headers:
merchant-id: <dynamic>
timestamp: <dynamic ISO timestamp>
signature: <dynamic MD5 hash>
version: v1

Key Points:

  • Use PUT, not POST

  • Signature must include timestamp (that’s why it needs to be dynamic)

  • All parameters must be in alphabetical order before hashing

  • Sandbox and live have different passphrases

The signature generation is the tricky part - you may need a server-side plugin or backend workflow to generate the MD5 hash properly with all parameters in the right order.

Hi,

Have you fixed the above issue?

If so, could you please help me generate the signature correctly?

For example:
Endpoint: PUT https://api.payfast.co.za/subscriptions/{token}/…
Token (in URL): 673254de-933d-45f6-86e7-bcb9e4cbe60b

Headers:

  • merchant-id: 10044923

  • version: v1

  • timestamp: 2026-01-16T00:10:00+05:30

  • signature: ???

Note: Before starting the actual coding, I am testing this in Postman.

Thanks in advance.