When your African shop accepts cards, you enter PCI DSS (Payment Card Industry Data Security Standard) scope. Badly handled = an 8M XOF audit, sanctions, catastrophic leak risk. Well handled via tokenization = a clean, compliant workflow with very low overhead.
TL;DR
- PCI DSS = mandatory standard for any card-handling merchant.
- 4 compliance levels by volume — most African SMEs = Level 4 (SAQ A or A-EP).
- Delegated tokenization (Stripe, PayDunya, Adyen) brings your PCI scope to nearly zero.
- Level-4 SAQ A audit cost: ~500K-1M XOF + internal effort.
Understanding the 4 PCI DSS levels
| Level | Annual volume | Obligations |
|---|---|---|
| 1 | >6M transactions | Annual QSA audit, annual pentest, quarterly scan |
| 2 | 1-6M | SAQ + annual scan |
| 3 | 20K-1M | SAQ + annual scan |
| 4 | <20K | SAQ only (self-assessment) |
Most African SMEs (100-2,000 orders/month shops) = Level 4. SAQ = Self-Assessment Questionnaire.
Choosing the right SAQ
| SAQ | Case |
|---|---|
| A | 100% iframe e-commerce Stripe/PayDunya (you never touch the card) |
| A-EP | Stripe.js / Elements (card entered on your site but via Stripe SDK) |
| D | You touch the card number (very rare, avoid) |
SAQ A = ~22 questions, completable in 2-3h. SAQ D = ~330 questions, weeks of work.
Golden rule: arrange to be SAQ A. That means using delegated tokenization.
Tokenization: what it is
Instead of storing the customer's card number (PAN — Primary Account Number), you store a token:
- Issued by your gateway (Stripe, PayDunya)
- Linked to the real card at the gateway
- Usable for future charges (subscriptions, repeat purchases)
- Worthless if leaked (you can do nothing outside your Stripe account)
`ts
const customer = await stripe.customers.create({ email: 'client@example.com' });
// Token created via Stripe Elements on frontend
// Backend receives a payment_method_id, not the PAN
await stripe.paymentMethods.attach(paymentMethodId, { customer: customer.id });
const intent = await stripe.paymentIntents.create({
amount: 12000,
currency: 'eur',
customer: customer.id,
payment_method: paymentMethodId,
off_session: true,
confirm: true,
});
`
You store: customer.id + paymentMethodId in your DB. No card number on your side = SAQ A applicable.
SAQ A-compliant architecture
`
[Browser client]
↓
[Checkout page — Stripe Elements iframe]
↓
[Stripe.js POST direct → Stripe API] // PAN NEVER touches your server
Need a professional website?
Kolonell builds websites that attract clients, optimized for the Sénégalese market. Free quote in 2 minutes.
↓
[Stripe → token]
↓
[Token sent to your backend]
↓
[Backend stores token + customer_id in DB]
↓
[Future charges via token]
`
Arrows passing through your server NEVER contain the PAN. That's the SAQ A condition.
What you can store without risk
| Data | Storage OK? | Note |
|---|---|---|
| Stripe token / paymentMethodId | ✓ | Worthless isolated |
| Stripe Customer ID | ✓ | Stripe link |
| Last 4 digits | ✓ | OK for display |
| Expiry month/year | ✓ | OK |
| Card type (Visa/MC) | ✓ | OK |
| Cardholder name | ✓ | OK |
| Full PAN | ✗✗✗ | FORBIDDEN |
| CVV | ✗✗✗ | FORBIDDEN (never stored) |
| PIN / Track2 | ✗✗✗ | FORBIDDEN |
Common PCI mistakes
- Logging full requests without redaction → PAN potentially logged. Always mask in logger middleware.
- Saving customer emails with PAN in support tickets → leak. Process: redact on entry.
for card on your site directly (no iframe) → SAQ A-EP at best, more risk.- Contact form asking "your card" in clear → disaster. Ban.
Annual SAQ A procedure
- Complete PCI DSS SAQ A v4.0 (free, on
pcisecuritystandards.org) - Run an ASV (Approved Scanning Vendor) scan on your site → ~$150-300/year (TrustWave, Qualys)
- Sign an AOC (Attestation of Compliance)
- Submit to your acquirer (Stripe, PayDunya, or acquiring bank)
Annual total: ~500K-1M XOF + 1-2 working days.
Maximum delegation = easy Level-4 SAQ A
Recommended stack for African SME:
- Stripe Elements or PayDunya hosted page for card entry
- No PAN on your server
- Token + customer_id stored in Postgres
- Logger middleware redacting anything that looks like a PAN
With this stack, your PCI scope is ~5 pages in SAQ A, annual self-audit = 2-3h.
Real case — fashion shop avoided breach
A Dakar fashion shop suffered a 2024 DB breach via SQL injection. Leak: 12,000 emails + phones + Stripe tokens. Consequences:
- 0 cards exposed (tokens worthless isolated)
- Stripe proactively invalidated tokens
- 0 PCI fine (no PAN in DB)
- CDP Senegal notification within 48h
- Total incident cost: 4M XOF (audit + comms) vs ~50M+ if PAN leaked
That's exactly the value of delegated tokenization.
FAQ
Q: Stripe Connect / Marketplace = same rule?
A: Yes. Marketplaces use Connect with destination charges. PAN never touches your server. SAQ A applicable.
Q: Recurring payments without Stripe?
A: Use another tokenizing provider (Adyen, PayDunya recurring, Mollie). PAN on your server = SAQ D = hell.
Q: Apple Pay / Google Pay reduce obligations?
A: Yes, they're tokenized wrappers. PAN is never transmitted. Coupled to Stripe, you stay SAQ A.
Conclusion
PCI DSS feels scary but is manageable with the right architecture. The simplifying rule: NEVER touch the PAN. Delegate 100% card entry to Stripe or PayDunya. Store only tokens. You stay SAQ A, auto-assessed audit, near-free compliance. That's the strategy of 95% of well-run African e-commerce SMEs in 2026.
Mohamed Bah
Fondateur, Kolonell
Passionate about digital and entrepreneurship in Africa, Mohamed has been helping Sénégalese businesses with their digital transformation since 2020. Founder of Kolonell, he believes every SME deserves a professional and accessible online présence.
