スキル一覧に戻る

payfast-integration

mkelam / PDFLab

1🍴 0📅 2025年12月12日

PayFast payment gateway integration specialist for FastAPI and Node.js. Use when debugging PayFast signature validation, ITN webhooks, sandbox-to-production migration, or implementing onsite/offsite/recurring billing. Covers MD5 signature generation, webhook security, PCI-DSS compliance, and production deployment checklists.

SKILL.md

---
name: payfast-integration
description: PayFast payment gateway integration specialist for FastAPI and Node.js. Use when debugging PayFast signature validation, ITN webhooks, sandbox-to-production migration, or implementing onsite/offsite/recurring billing. Covers MD5 signature generation, webhook security, PCI-DSS compliance, and production deployment checklists.
---

# PayFast Integration Specialist

Production-grade PayFast integration with systematic debugging workflows for FastAPI and Node.js applications.

## Diagnostic Interview

Before jumping to solutions, gather these critical details:

**Error Context:**
- Exact error message (include stack trace if available)
- When does it occur? (payment submission, ITN callback, signature validation)
- Environment: sandbox or production

**Integration Details:**
- Integration type: onsite, offsite, or recurring billing
- Framework: FastAPI or Node.js (which version?)
- Recent changes: code updates, PayFast dashboard settings, server migrations

**Configuration Status:**
- merchant_id and merchant_key verified against PayFast dashboard
- Passphrase set (required for recurring billing and signatures)
- Return/cancel/notify URLs publicly accessible (not localhost)

## Top 3 Failure Modes

### 1. MD5 Signature Mismatch

**Symptoms:**
- "Generated signature does not match" error
- Payment form rejected
- ITN validation fails

**⚠️ CRITICAL: PayFast Signature Requirements (NON-NEGOTIABLE)**

**Production Lesson Learned (Nov 5, 2025)**: PayFast signature mismatch caused 100% payment failure in production. Issue: empty passphrase was being included in signature generation when production mode doesn't use passphrases.

**Mandatory Signature Generation Steps:**

1. **✅ Sort keys alphabetically (a-z)** - EXACT alphabetical order required
2. **✅ URL encode values** - Spaces as `+`, not `%20`
3. **✅ Exclude empty values** - Do NOT include parameters with empty strings
4. **❌ NO passphrase in production mode** - Only use passphrase in sandbox if configured
5. **✅ MD5 hash the parameter string** - Use lowercase output

**Before vs After (Real Production Issue):**

```javascript
// ❌ WRONG: Including empty passphrase in production
const signature = generateSignature(paymentData, PAYFAST_CONFIG.passphrase);
// passphrase = "" gets included → signature mismatch

// ✅ CORRECT: No passphrase parameter in production
const signature = generateSignature(paymentData);
// Only actual payment parameters → signature valid
```

**Root Causes & Fixes:**

| Issue | Detection | Solution | Real Production Impact |
|-------|-----------|----------|----------------------|
| **Empty passphrase included** | Check if empty passphrase in signature params | Exclude passphrase entirely in production mode | ✅ **FIXED Nov 5** - 100% payment failure |
| **Wrong parameter order** | Compare param order to PayFast docs | Parameters MUST be alphabetically sorted (a-z) | Critical - always fails |
| **Trailing spaces in merchant_key** | Copy merchant_key, check length | Trim whitespace when storing credentials | Common copy-paste error |
| **Empty fields included** | Check for blank `value=""` fields | Exclude empty parameters from signature string | Causes intermittent failures |
| **Uppercase MD5 hash** | Check hash output casing | Use `.toLowerCase()` on hash | Always fails validation |
| **URL encoding inconsistent** | Special chars in item descriptions | Spaces as `+`, special chars URL encoded | Fails with special characters |

**Mandatory Pre-Integration Testing:**

```bash
# Step 1: Generate signature manually
□ Create parameter string with exact alphabetical order
□ Exclude empty values
□ Do NOT include passphrase in production
□ MD5 hash and convert to lowercase

# Step 2: Test with PayFast signature validator
□ Use PayFast's signature validation endpoint
□ Send test payment with known signature
□ Verify "Signature valid" response

# Step 3: Test with real payment amounts
□ Test with minimum amount (R5.00)
□ Test with decimal amounts (R85.50)
□ Test with large amounts (R1850.00)

# Step 4: Verify parameter ordering
□ Print parameter string before hashing
□ Confirm alphabetical order visually
□ Compare with PayFast documentation example
```

**Signature Validation Endpoint (for testing):**
```bash
# Test your signature generation
curl -X POST https://www.payfast.co.za/eng/query/validate \
  -d "merchant_id=YOUR_ID" \
  -d "signature=YOUR_GENERATED_SIGNATURE" \
  -d "amount=85.00"
```

**Verification Script:**
See `scripts/validate_signature.py` for standalone signature validator.

**Real Production Test Results (Nov 5, 2025):**
```
=== Before Fix ===
Generated Signature: a1b2c3d4e5f6 (with empty passphrase)
PayFast Expected: c857dc1297ea380cd431307f75d42bea
Result: ❌ Signature mismatch - 100% payment failure

=== After Fix ===
Generated Signature: c857dc1297ea380cd431307f75d42bea (no passphrase)
PayFast Expected: c857dc1297ea380cd431307f75d42bea
Result: ✅ Signatures match - payments working
```

### 2. ITN (Instant Transaction Notification) Webhook Failures

**Symptoms:**
- Payment succeeds but order not updated
- "ITN not received" in PayFast logs
- 307 redirect or non-200 response
- Empty `req.body` in webhook handler

**Root Causes & Fixes:**

| Issue | Detection | Solution |
|-------|-----------|----------|
| **Not returning 200 OK** | Check webhook logs for status code | Webhook MUST return `200` before any async processing |
| **notify_url redirects (307)** | Test URL with curl | Use exact URL (no trailing slash mismatch), ensure HTTPS |
| **localhost URL** | Check if notify_url uses localhost | Use ngrok/tunneling for dev or deploy to accessible server |
| **Body parsing middleware missing** | Check if `req.body` populated | FastAPI: use `Form(...)`, Node.js: `express.urlencoded()` |
| **Source IP not from PayFast** | Log incoming IP in webhook | Verify IP in PayFast ranges (see Security Checks below) |
| **Signature validation failing** | Log received vs computed signature | Apply same signature logic as payment submission |

**Advisory Security Checks:**
Consider implementing these ITN validations:
- Verify source IP belongs to PayFast (range: `197.97.145.144/28`)
- Validate signature matches received data
- Confirm payment amount matches order total
- Check payment status is `COMPLETE` before fulfilling order

**Testing Script:**
See `scripts/test_itn_endpoint.py` to simulate PayFast ITN callbacks.

### 3. Configuration & Environment Issues

**Symptoms:**
- Works in sandbox, fails in production
- "Invalid merchant_id or merchant_key"
- Recurring billing signature errors

**Root Causes & Fixes:**

| Issue | Detection | Solution |
|-------|-----------|----------|
| **Sandbox creds in production** | Check if merchant_id is 10000100 (sandbox) | Switch to live merchant_id and merchant_key from PayFast dashboard |
| **merchant_id vs merchant_key swapped** | Double-check credential assignment | merchant_id is numeric, merchant_key is alphanumeric |
| **Passphrase not set** | Check PayFast dashboard Settings | Required for recurring billing; set in Integration > Security |
| **Recurring billing not enabled** | Test subscription payment | Enable in PayFast dashboard Settings > Integrations |
| **CURL disabled on server** | Test: `curl --version` | Contact hosting provider to enable CURL/outbound requests |
| **Firewall blocks PayFast IPs** | Check server firewall logs | Whitelist PayFast IP ranges |

## Systematic Debugging Workflow

**Step 1: Isolate Failure Point**
- **Client-side?** Check browser console for JS errors, form submission logs
- **Server-side?** Check application logs for exceptions in payment initiation
- **Gateway?** Check PayFast dashboard transaction logs for rejection reason
- **Webhook?** Check ITN logs for delivery failures or 5xx errors

**Step 2: Verify Configuration**
Run this checklist:
```
□ merchant_id matches PayFast dashboard (case-sensitive)
□ merchant_key matches PayFast dashboard (no spaces)
□ Passphrase set in PayFast dashboard if using signatures
□ Environment matches credentials (sandbox vs production)
□ notify_url publicly accessible (test with curl)
□ return_url and cancel_url use HTTPS
```

**Step 3: Test Signature Generation**
Use `scripts/validate_signature.py` to:
- Generate reference signature from sample data
- Compare with your application's signature output
- Identify parameter ordering or encoding issues

**Step 4: Test Webhook Reception**
Use `scripts/test_itn_endpoint.py` to:
- Send mock ITN payload to your endpoint
- Verify 200 response returned immediately
- Check if order status updates correctly

**Step 5: Check Logs Systematically**
- **Application logs:** Exceptions, signature mismatches, validation errors
- **PayFast ITN logs:** Dashboard > Integrations > View ITN Log
- **Server access logs:** Confirm ITN POST requests arriving
- **Network traces:** Use browser DevTools or Wireshark for API calls

## Framework-Specific Patterns

**FastAPI:** See `references/fastapi-patterns.md` for:
- Pydantic models for payment requests
- Async webhook handlers
- Signature validation middleware
- Type-safe configuration management

**Node.js:** See `references/nodejs-patterns.md` for:
- Express route setup
- Body parsing middleware
- Signature generation utilities
- Error handling patterns

## Sandbox-to-Production Migration

**Repeatable Workflow:**

**Step 1: Export Sandbox Configuration**
```bash
# Document current working sandbox setup
□ merchant_id (sandbox): __________
□ merchant_key (sandbox): __________
□ Passphrase (if set): __________
□ Test transaction IDs: __________
□ Working notify_url pattern: __________
```

**Step 2: Update PayFast Dashboard (Production)**
- Navigate to Settings > Integration
- Set passphrase (copy from sandbox if consistent)
- Configure notify_url with production domain
- Enable recurring billing if needed
- Save and note new production credentials

**Step 3: Update Application Configuration**
```bash
□ Update merchant_id to production value
□ Update merchant_key to production value
□ Change API endpoint: sandbox.payfast.co.za → payfast.co.za
□ Update notify_url to production domain
□ Verify HTTPS certificate valid on all URLs
```

**Step 4: Validation Checklist**
```bash
□ Run scripts/validate_signature.py with production creds
□ Test small transaction (minimum amount)
□ Verify ITN callback received and processed
□ Check order status updates correctly
□ Confirm email notifications sent (if enabled)
□ Test edge cases: cancelled payment, failed payment
```

**Step 5: Monitoring Setup**
Consider implementing:
- Alert on ITN failures (non-200 responses)
- Log signature mismatches for analysis
- Track transaction completion rate
- Monitor webhook response times
- Set up PayFast dashboard email notifications

## Security Best Practices

**Advisory Recommendations:**

**PCI-DSS Compliance:**
- Never log full card numbers or CVV codes
- Use HTTPS for all payment-related endpoints
- Implement rate limiting on payment submission endpoints
- Store credentials in environment variables, not code

**Signature Validation:**
- Always validate ITN signatures before processing
- Use timing-safe comparison for signature checks
- Regenerate signature server-side; never trust client values

**Webhook Security:**
- Consider source IP validation (PayFast IPs only)
- Implement idempotency checks to prevent duplicate processing
- Return 200 immediately, process async to avoid timeouts
- Log all ITN payloads for audit trail

**Data Handling:**
- Validate amount precision (2 decimal places for ZAR)
- Check currency matches expected value (ZAR)
- Sanitize user input in item descriptions
- Use database transactions for order state updates

## Code Snippet Guidelines

When providing code examples:
- Include inline comments explaining PayFast-specific requirements
- Flag security risks explicitly (e.g., exposed keys, weak validation)
- Show error handling for network failures and signature mismatches
- Demonstrate idempotent webhook processing patterns
- Provide both sync and async examples where applicable

## Production Resilience

**Recommended Monitoring:**
- Webhook delivery success rate (target: >99%)
- Average ITN processing time (target: <500ms)
- Signature validation failure rate (investigate if >1%)
- Payment-to-order completion rate (identify drop-offs)

**Alerting Triggers:**
- Webhook returning non-200 status
- Repeated signature mismatches from same user
- ITN not received within 5 minutes of payment
- Unusual spike in failed transactions