🇪🇺 Predictable egress for Payfast accounts

Static IP for Payfast

Payfast secures your account with login restrictions and signature checks, not locked-down egress. Give every dashboard login and signed API call two fixed static EU IPs with one HTTPS_PROXY variable, and pin your account's Allow hosts list for good.

payments-team · shell

# one variable, fixed egress for everything

HTTPS_PROXY=https://user:pass@eu-01.outboundgateway.com:8443

# sandbox check, arriving from your static IP

curl -s https://sandbox.payfast.co.za/ping

# signed call: sorted fields + passphrase, MD5

curl -s -X PUT https://sandbox.payfast.co.za/subscriptions/$TOKEN/cancel \

  -H "merchant-id: $MERCHANT_ID" \

  -H "timestamp: $TIMESTAMP" \

  -H "version: $API_VERSION" \

  -H "signature: $SIGNATURE"

The controls are on your account. The moving part is your egress.

Login Restrictions, signature checks, published callback IPs: Payfast's security model leans on addresses staying knowable, at both ends of the wire. Most platforms cannot promise that.

Allow hosts wants an address that doesn't move

Login Restrictions in the Payfast dashboard accept an IP or hostname, and Payfast's own guidance suggests dynamic DNS for lines that lack a static address. Rotating platform egress leaves you two bad options: an empty list, or a list that locks your own team out after the next deploy.

July 2025 proved IP lists break silently

Payfast migrated its Payment API from on-premises to AWS by 31 July 2025, and every callback IP changed with it. Merchants running hardcoded whitelists of the old addresses watched integrations stop matching overnight. Address pinning is load-bearing in both directions, and it needs addresses that are actually stable.

Signatures authenticate the message, not the machine

API calls carry a lowercase MD5 signature over alphabetically sorted fields, salted with the passphrase from your Payfast settings, and ITN callbacks are verified the same way. Nothing in that construction ties a request to a recognizable origin. Attribution, audit trails, and abnormal-login alerts all fall back on the source address.

One merchant account, many egress points

Dashboard logins from the office, subscription calls from a Kubernetes job, sandbox tests from a CI runner: each leaves from a different address unless you route them through one pair. The result is a Login Restrictions list that can never describe where your money-moving traffic really comes from.

The Solution

One fixed EU IP pair for every login and signed call

Your Platform

logins + signed API calls

HTTPS Proxy

(Static EU IP)

Payfast

api.payfast.co.za

Both addresses go into Login Restrictions under Allow hosts, so dashboard access stays pinned to your pair while every signed request arrives from an EU address Payfast can expect, whichever runtime issued it.

Set HTTPS_PROXY once in your platform's environment; dashboard tooling and signed API calls then leave from your fixed pair.
Two addresses stand in for each other. If either proxy node drops out, the other keeps answering, so the host your Login Restrictions record never wobbles.
TLS passes straight through to Payfast. Your merchant-id and passphrase stay encrypted past the proxy hop; we never see them.

Why payment teams pin Payfast traffic to OutboundGateway

Login Restrictions you can keep on

Allow hosts and allow countries only protect you while they stay configured. A pair of addresses you actually own is what makes the restriction compatible with autoscaling, container churn, and everything else that reshuffles your egress.

Wired for the documented auth model

Built around what Payfast actually specifies: merchant-id, timestamp, version and signature headers, a lowercase MD5 over alphabetised fields salted with your passphrase, and MD5 verification on inbound ITN posts. No SDK surgery required.

Attributable on both sides

Payfast publishes the source IPs its ITN callbacks come from, so inbound traffic can be pinned. Your outbound logins and signed calls deserve the same treatment. Paystack also serves South African checkouts; see our Paystack static IP guide for the same pattern there.

Designed for

Teams collecting through Payfast who want Login Restrictions to hold and their egress to stop being the weak link.

Stores selling into South Africa

ZAR checkouts on WooCommerce, PrestaShop, Shopify or Xero, with 18+ payment methods from Instant EFT to SnapScan and Zapper QR. Plugin callbacks and custom API calls all benefit from one predictable origin.

SaaS running subscriptions and Payment Requests

Recurring charges, tokenized payments and Payment Request links emailed to buyers. Update and cancel calls run unattended against the subscriptions API, so a rotated egress address fails where nobody is watching.

Finance and ops teams behind Login Restrictions

Reconciliation and refund work happens in the dashboard. Restricting logins to chosen hosts and countries only stays fair to the team when everyone's sessions arrive from the same two addresses.

EU businesses collecting in rands

Payfast operates as a PCI-DSS Level 1 Service Provider with built-in fraud protection. Keeping your side of the connection inside EU data centres gives auditors one clean residency story for the customer data in your calls.

Implementation

One environment variable, and your Payfast traffic leaves from a fixed EU address.

Shell / environment

Set the variable wherever your platform runs. curl picks it up with no other change.

# .env, Heroku config vars, Vercel env settings, Lambda env
HTTPS_PROXY=https://user:pass@eu-01.outboundgateway.com:8443

# sandbox health check, egressing from your static EU IP
curl -s https://sandbox.payfast.co.za/ping

# signed subscription cancel against the sandbox
curl -s -X PUT https://sandbox.payfast.co.za/subscriptions/$TOKEN/cancel \
  -H "merchant-id: $MERCHANT_ID" \
  -H "timestamp: $TIMESTAMP" \
  -H "version: $API_VERSION" \
  -H "signature: $SIGNATURE"

Python (requests)

requests reads HTTPS_PROXY from the environment automatically. The signature is a lowercase MD5 over alphabetically sorted fields, salted with the passphrase from your Payfast settings.

import os, hashlib, requests

def payfast_signature(fields, passphrase):
    base = "&".join(f"{k}={fields[k]}" for k in sorted(fields))
    if passphrase:
        base += f"&passphrase={passphrase}"
    return hashlib.md5(base.encode()).hexdigest()

# cancel a sandbox subscription, egressing from your static EU IP
requests.put(
    f"https://sandbox.payfast.co.za/subscriptions/{token}/cancel",
    headers={
        "merchant-id": merchant_id,
        "timestamp": timestamp,
        "version": api_version,
        "signature": payfast_signature(payload, passphrase),
    },
)

# verify an inbound ITN: same MD5 over the posted fields
def itn_valid(post):
    fields = {k: v for k, v in post.items() if k != "signature"}
    return payfast_signature(fields, passphrase) == post.get("signature")

Node.js (undici ProxyAgent)

Node's native fetch ignores proxy env vars; hand it undici's ProxyAgent instead.

import { ProxyAgent } from 'undici';

const dispatcher = new ProxyAgent(process.env.HTTPS_PROXY);

const res = await fetch(`https://sandbox.payfast.co.za/subscriptions/${token}/cancel`, {
  method: 'PUT',
  dispatcher,
  headers: {
    'merchant-id': process.env.PAYFAST_MERCHANT_ID,
    'timestamp': timestamp,
    'version': apiVersion,
    'signature': signature,
  },
});

Dashboard logins, same pair

Login Restrictions only work if human sessions arrive from known addresses too. Route your browser and CLI through the same proxy pair.

# system or browser proxy, same credentials as your platform
HTTPS_PROXY=https://user:pass@eu-01.outboundgateway.com:8443

# finance and ops logins now hit Allow hosts from the fixed pair,
# and abnormal-login alerts stop firing on legitimate traffic

Pin both addresses in Login Restrictions

Your account ships with a pair of static EU IPv4 addresses. In the Payfast dashboard, open the Profile tab, edit the security info, and under Login Restrictions add both to the Allow hosts box; consider allow countries for the markets your team works from. The passphrase stays in your secret store and never appears in any list. Abnormal login notifications stop flagging your own team.

Which traffic is covered? Your outbound dashboard logins and signed API calls, to sandbox.payfast.co.za in test and api.payfast.co.za in production. Payfast ITN callbacks arrive inbound at your notify_url from Payfast's own published addresses, which its July 2025 AWS migration moved to the 3.163.x.x ranges; the canonical list lives at developers.payfast.co.za under Ports and IPs. Allowlist those on your firewall and verify the MD5 signature on every ITN; the WooCommerce Payfast plugin (1.7.7 and later) validates ITN source IPs itself when test mode is off. Callbacks never route through the proxy.

📖 Complete Documentation: For detailed examples, error handling, and advanced configurations, see the Python guide, the Node.js guide, or all guides.

South African payment rails, European egress

Payfast connects you to cards, Instant EFT, wallets and QR payments across South Africa. Where your requests leave from is still your decision.

EU residency for your side of the wire

Payfast was founded in South Africa in 2007 and is part of Network International. Your outbound hop stays in EU data centres, keeping one simple residency story for the customer data riding in your API calls and dashboard sessions.

Sealed end to end

The connection to Payfast is never terminated at the proxy. Your merchant-id, passphrase and payment payloads stay encrypted the whole way, on top of a PCI-DSS Level 1 certified gateway.

What you get

Built for Allow hosts

Two single public IPv4 addresses, exactly the kind of entry the Login Restrictions form expects. No dynamic DNS tricks required.

Outlives your infrastructure

Pods reschedule, deploys roll, laptops move cafés. The address pair stays put while everything behind it churns.

Sealed past the proxy

TLS passthrough keeps your merchant-id, passphrase and payment payloads encrypted through the proxy hop.

One pair, every surface

Dashboard logins, live API calls and sandbox CI tests all arrive from the same two addresses, so one Allow hosts list describes everything.

Attributable egress

Every signed request becomes recognizable in Payfast logs and your own audit trail, instead of dissolving into a cloud provider's range.

Simple pricing

Starting from €19/month. Flexible plans for every scale. Cancel anytime.

Give every Payfast login and API call one stable origin

Set one environment variable and dashboard sessions, sandbox tests and signed live calls all leave from two fixed EU addresses.

Starting from €19/month. Flexible plans for every scale. Cancel anytime.

Frequently asked questions

Does Payfast support IP whitelisting?

Not as a single outbound egress list. What Payfast documents is complementary: Login Restrictions that limit dashboard access to chosen hosts and countries, MD5 signature checks on API calls and ITN callbacks, and a published list of Payfast's own callback IPs you can whitelist inbound (see developers.payfast.co.za, Ports and IPs). Fixed addresses on your side make all three of those workable.

Do both proxy IPs go in Allow hosts?

Yes. Add both fixed EU IPv4 addresses to the Allow hosts box under Login Restrictions. Either address can carry your entire traffic, so login restrictions keep holding even while the proxy pair fails over between the two.

What about ITN callbacks from Payfast?

They arrive inbound only, as POSTs to your notify_url from Payfast's published source addresses, which moved to the 3.163.x.x ranges in the July 2025 AWS migration. Allowlist those on your own firewall and verify the MD5 signature on every callback; the field order and your passphrase both matter. The proxy covers your outbound logins and API calls, not Payfast's deliveries to you.

Your Payfast account, pinned to two addresses

Happy to talk through how a managed EU proxy pair fits your payment stack.

Contact Our Founders →