Security & compliance
Built to be checked.
Card numbers never reach our payment API, and card payments go live once our PCI DSS certification completes. Every key does one job and is shown once. Every webhook is signed and timestamped. Offline taps are signed in secure hardware on both devices and checked again at settlement. Identity data stays in Nigeria.
Evaluating PediWave for a bank or platform? Talk to sales
Certifications and testing
What we hold, and what we are working towards.
Each item shows its real status today. When a status changes, this page changes the same day.
PCI DSS v4.0.1
Tokeniser and card vault
In assessment · certification pendingThe tokeniser and card vault are the architecture being assessed: the only parts of PediWave inside the cardholder data environment. They are not yet certified. Card payments go live once a Qualified Security Assessor completes the certification; quarterly ASV scans and an annual penetration test follow.
NDPA 2023 and GAID
Personal data of your customers
Processor under a DPAYou are the controller of your customers' data and PediWave is your processor, under a data processing agreement. Profiling features such as fraud scoring and Smart Dunning are covered by a data protection impact assessment.
CBN licensing
Payment gateway, aggregation and terminals
Through licensed partnersPediWave orchestrates licensed acquirers, banks and switches. We do not route agent cash across principals. Our own licence position is published here when it is granted.
Your PCI scope
Merchants using hosted fields or Checkout, once cards go live
SAQ A, when cards go liveWhen card acceptance launches, card numbers are entered in fields we host, so they never touch your servers. That keeps you on the shortest self-assessment questionnaire. We do not offer a raw card API.
How we are checked
| Test | When | Status |
|---|---|---|
| Static analysis and dependency scanning | Every code change | Running |
| Secret scanning on code and container images | Every code change | Running |
| Contract tests that must refuse a forged batch, a replayed tap pair, a tap after revocation, a stale policy and a software-attested terminal | Before offline payments go live | Running |
| Published webhook signature test vectors | With every SDK release | Published with the SDKs |
| Red-team exercise on the offline protocol with real devices: cloning, rollback, replay and interception over BLE and Wi-Fi | Before offline payments go live | Planned |
| PCI DSS v4.0.1 assessment of the cardholder data environment by a QSA | Before live cards | Planned |
| ASV scans | Quarterly, once live | Planned |
| External penetration test of the API, Checkout and the tokeniser | Annually, and before go-live | Planned |
| Failure drills: cache loss, secret lease expiry, ledger unavailable, provider timeouts | Before go-live | Planned |
Summaries of completed assessments and tests are shared under a non-disclosure agreement. Ask through Contact security.
Controls
Six places we draw the line.
Scoping is written into every query, so no check depends on memory. These are the controls behind it.
Keys
Every key does one job.
- Four key types: secret and restricted keys for your servers, publishable keys for browsers and apps, and terminal keys bound to one terminal.
- Restricted keys carry only the scopes you choose, such as
payment_intents:writeorrefunds:read. - A key is shown once, when you create it. After that the dashboard shows only its prefix and last four characters.
- Optional IP allowlist and optional request signing per key. Signing is required for payout keys above a threshold you set.
- Roll a key with up to 72 hours of overlap, or revoke it at once.
- Repeated failed sign-ins from one address are rate-limited for ten minutes and reported to you.
Card data
Card numbers stay inside one boundary.
Card acceptance is coming: card payments go live once PCI DSS certification completes
- Card fields are hosted on a separate origin and run in an isolated frame on your page.
- The tokeniser and card vault are the only components in the cardholder data environment.
- Every other endpoint rejects anything that looks like a card number with
400 raw_card_data. - Card tokens are single use and expire after 15 minutes.
- CVC is never stored. Stored card data is encrypted with a separate key for each record.
- Network tokens, so the card number can be dropped from the vault. Coming (coming, not yet available)
Webhooks
Every event is signed and timestamped.
-
PediWave-Signaturecarries a timestamp and an HMAC-SHA256 over the timestamp and the raw body. - Reject anything older than five minutes. Every SDK compares signatures in constant time.
- Rotate a secret with a grace window; both signatures are sent while it runs.
- Deliveries come from a fixed set of IP addresses listed in the docs, follow no redirects and never go to private addresses.
- Payloads never carry keys, client secrets, PINs, device ids or card data beyond the last four digits.
- A provider's webhook never moves money on its own. We confirm with the provider first.
Offline
A tap made with no network is checked when it returns.
Applies when offline acceptance is enabled for your account
- Device keys are generated and held in secure hardware (StrongBox or a trusted execution environment).
- Payer identity is vouched for by a signed assertion that expires after 24 hours.
- Every tap is signed by both devices. Settlement checks all three signatures against registered keys.
- Signed policies set the per-tap limit, the outstanding ceiling and the settlement window on each terminal.
- Revoking a terminal stops its future taps. Honest taps made before revocation still settle.
- You choose who carries a double-spend loss before you accept a single tap.
Data
Identity data stays in Nigeria.
- BVN, NIN, CAC numbers and KYB documents go straight to our identity platform in Nigeria. PediWave services keep masked values and references only.
- Your customers' names, emails and phone numbers are held in encrypted columns.
- Export or delete a customer's data on request. Deletion anonymises the record once the retention period ends.
- Logs are structured and redacted. A card-number detector runs on the log pipeline as a last line.
- PINs and device headers pass through to be checked and are never stored or logged.
Operations
Sensitive changes need two people.
- Routing rules, connector switches, offline ceilings, assurance movements and large payout batches need a second approver.
- An append-only audit log records each change to keys, webhooks, routing and policies: who, from where, the request id, before and after.
- You can see your own API requests, redacted, for 30 days.
- No person has a standing account in the cardholder data environment. Emergency access needs two approvals and is recorded.
- Secrets live in a vault and rotate on a schedule. None appear in configuration files.
- When a system we depend on is down, money-moving calls fail closed with
503. We never report a success we have not confirmed.
Outside the dashed line: tok_ and pm_ ids, brand, last4. Never the card number.
Card data Coming
Card numbers never reach our payment API.
Your customer types their card into fields served from our tokens origin. The tokeniser turns the card into a single-use token in under a second, and your page sends only that token on. Your server, the PediWave API and everything behind it see token ids, the brand and the last four digits. Nothing else.
Card acceptance is coming. This is the architecture being assessed for PCI DSS; it is not yet certified, and card payments go live once certification completes. From then, merchants using hosted fields or Checkout qualify for SAQ A, because card numbers never touch their systems.
What is in scope
| Component | In the cardholder data environment | Sees a card number |
|---|---|---|
| Hosted card fields, served from our tokens origin | Yes | Yes, in your customer's browser |
| Tokeniser | Yes | Yes, in memory, for under a second |
| Card vault | Yes | Stored encrypted only where a provider requires the full number; otherwise provider and network tokens only |
| PediWave API, router, offline engine, events and database | No | Never. Any input that looks like a card number is refused |
| Ledger platform | No | Never. It receives a token reference only |
| Provider connections that forward card numbers to an acquirer | Yes, deployed inside the same boundary | Yes, in transit to the acquirer |
What we do not support, on purpose
-
A raw card API. Sending
card[number]to create a payment would pull you into the longest questionnaire, SAQ D. The API refuses it and the error explains hosted fields. - Storing CVC, ever.
Offline threat model
Bounded before the tap. Verified after it. Paid for by a party you chose.
The ledger cannot be spent twice: a second settlement against the same balance fails. What can go wrong offline is who carries a loss, and how large it can grow. Each threat below has a control and, where one exists, the risk that remains.
| Ref | Threat | Control | What remains |
|---|---|---|---|
| Taps and terminals | |||
| O1 | Double-spend, by cloning a payer's device or rolling back its local balance | The second settlement fails because the device balance cannot go below zero. Each terminal has a per-tap limit, an outstanding ceiling and a settlement window. The payer's device is blocked and a fraud case opened on the first event, and the terminal's policy tightens automatically | The party named in your loss policy carries the first loss. That risk is priced into the acceptance fee |
| O2 | Forged payer, using a fake identity assertion | The terminal checks the assertion's signature against a public key it fetched online with its policy. Assertions last 24 hours. Settlement checks again against the payer's registered device key | A terminal whose policy is older than 24 hours stops accepting taps |
| O3 | Rogue terminal or merchant uploading invented taps | Every tap needs the payer's signature over the terminal's fingerprint and the collection reference. No payer signature, no money. Batches are signed by the enrolled terminal key, hash-chained and numbered | A payer who colludes can only move their own real balance |
| O4 | Replay of a genuine tap pair | Each settlement reference is unique. Nonces and sequence numbers are stored, and a pair seen in any earlier batch is rejected. Pair hashes are kept for seven years | None recorded |
| O5 | Stolen terminal accepting taps with no network | Revocation at PediWave and on the ledger; the terminal key stops working. Taps signed after the revocation time are quarantined; taps signed before it settle | Up to the terminal's outstanding ceiling of honest-looking taps, until payers' assertions age out |
| O6 | Oversized or stale taps | Per-tap limit, taps-per-hour limit and settlement window. A tap's time must fall after enrolment and before upload, and no upload is accepted more than 30 days late | None recorded |
| O7 | A receipt without funds, where the payer shows a "paid" screen the terminal never signed | Only the pair signed by both devices is a payment. The payer's app shows "Paid" only after the terminal's acknowledgement verifies | Persuading a cashier with a fake screen is social engineering, outside the protocol |
| O8 | Tampering with the policy on a terminal | Policies and key sets are signed with PediWave's policy key and the SDK refuses an unsigned policy. The device's attestation level is recorded and gates what it may accept | Rooted devices are allowed only at the software attestation level, with lower ceilings |
| O9 | A merchant hiding or losing a batch | Gaps in batch numbering raise an alert. Every reconnect sends a signed "no taps since" attestation, so silence is provable. Payers can settle their side first, which exposes a terminal that never uploaded | None recorded |
| O10 | Compromise of PediWave's policy or assertion signing keys | Keys are held in the secrets vault and versioned. Terminals carry the current and the next key, and keys rotate every 90 days | The keys are loaded in memory in hardened services, not yet in a hardware security module. A hardware module is planned; until then short rotation limits the window |
| O11 | Bypassing settlement fees or caps | Fees are quoted by the ledger at settlement and agent and collector caps are enforced there. PediWave shows the headroom; it does not decide it | None recorded |
| O12 | Privacy: who paid whom offline | Statements carry device fingerprints and an alias, not names or phone numbers. Proof bundles are disclosed only in a dispute | None recorded |
| Wallets in your app | |||
| O13 | A compromised merchant backend trying to drain its customers' wallets | Customer sessions are bound to one device. Money-moving calls need the customer's PIN and a signature from a key only the phone holds. The merchant's secret key can block a device, with two approvers, but cannot load, unload, settle or transfer | A malicious app build could capture PINs on screen. The SDK's own PIN pad, attestation level and device integrity checks reduce this; they do not remove it |
| Cash at agents | |||
| O14 | The same cash-out code redeemed at two offline agents | Codes are signed by PediWave, single use, bound to an amount and an expiry, and PIN-protected, with three tries per terminal. The first redemption wins at settlement; the second is quarantined with both signed redemptions as evidence, and the loss falls as the issuing bank's policy says | Bounded by the maximum code amount times the number of agents an attacker can reach before the code expires |
| O15 | A rogue agent terminal forging a deposit to credit a friend's account | A deposit only moves the agent's own prefunded float to the bank's float, so a forged deposit costs the agent. Caps apply per deposit and per outstanding batch, and the bank acknowledges each credit with a core reference | None recorded |
| O16 | Misuse of float custody | Floats are accounts on the ledger with its usual guards and approval chains. PediWave operations staff can move float only through recorded instructions with two approvers. Floats are reconciled daily against the bank's core extract | None recorded |
| O17 | An agent paying cash against a card it expects to decline, or colluding with a customer | The agent lends its own money until the bank approves at settlement, so a decline is the agent's loss by policy. Caps apply per withdrawal and in total; the card's cryptogram is validated by the issuer, and declines tighten the agent's ceiling automatically | Bounded by the agent's outstanding ceiling |
| O18 | A walk-in withdrawal replayed, or an unknown answer treated as approved | Each withdrawal is idempotent on its id. The agent pays only on an explicit approval; an unknown answer is checked again, and a late approval with no cash paid is reversed with the bank | None recorded |
Who carries a loss is your choice, made in advance
Every merchant accepting offline taps chooses a loss policy during underwriting. It applies to verified double-spend losses only.
- Merchant. You carry the loss. This is the default.
- PediWave-assured. PediWave covers verified double-spend losses from an assurance pool, in return for a premium on your offline volume, quoted in basis points.
- Shared. The loss is split in a proportion agreed with you.
In every case the payer's device is blocked, a fraud case is opened, and money recovered from the payer later repays whoever carried the loss. Movements out of the assurance pool need two approvers and a fraud case reference.
Data handling
What we keep, where, and for how long.
You decide what customer data to send us. Here is what we do with each kind.
| Data | How we handle it | How long we keep it |
|---|---|---|
| BVN, NIN, CAC numbers and KYB documents | Posted straight from hosted onboarding to our identity platform in Nigeria. PediWave services store references, masked values and verification status | Held by the identity platform under its retention rules |
| Customer names, emails, phone numbers, addresses | Sent at your discretion. Stored in encrypted columns. Exported or deleted per customer on request | Anonymised on deletion once the retention period ends |
| Card data | Inside the cardholder data environment only. See Card data | CVC never. Card numbers dropped where provider or network tokens suffice |
| PINs and device headers | Passed through to be verified. Never stored, never logged | Not kept |
| Offline proofs | Signed tap statements with device fingerprints and aliases, no names | Seven years, as evidence |
| Bank account numbers on deposit instructions | Full value only until you confirm the credit; then masked and hashed | Masked value kept with the payment record |
| Payment records | Every payment object and its history | Seven years, as regulation requires |
| Events | Signed event records, available through the API | 30 days online, then archived |
| Idempotency records | The first response to each Idempotency-Key | 24 hours |
| API request logs | Method, path, status, request id, key fingerprint and a redacted body | 30 days |
You are the controller of your customers' personal data and PediWave is your processor, under our data processing agreement. Consent to save a payment method is recorded with its time, IP address and the version of the text shown. Fraud scoring and Smart Dunning are covered by a data protection impact assessment, and signals shared across merchants are aggregated by issuer, never by person.
Regulation
Where each obligation lands.
The positions below are current. Where a decision is still open, we say so.
| Obligation | Our position |
|---|---|
| CBN payment service licensing (payment gateway and aggregation; terminals) | PediWave operates through licensed acquirers, banks and switches. Its own licence position is published here when granted |
| Agent banking and the one-principal rule in force from April 2026 | Agent cash runs only under your own principal. We do not route cash across principals until the licensing position allows it |
| PCI DSS, as the CBN requires for card processing | The tokeniser and card vault form the cardholder data environment. Its PCI DSS assessment by a QSA is in progress; card payments go live once certification completes. See Card data |
| NDPA 2023 and GAID: lawful basis, impact assessments, registration and audit | You are controller; PediWave is processor under a DPA. Impact assessments cover fraud scoring and Smart Dunning |
| Breach notification within 72 hours | A breach runbook meets the 72-hour notification duty, and the DPA sets how we tell you |
| BVN data localisation | BVN data never leaves our identity platform in Nigeria. PediWave services keep references only |
| Consumer protection: refund timelines and dispute acknowledgement | Refund progress is reported to you as refund.* events. Offline payer claims follow fraud case numbering and timelines |
| KYC reliance, where you have verified customers yourself | Only merchants granted the attestation capability may register verified customers without a fresh check. Each attestation records who, how, the evidence and when. A random sample is re-verified each month, and every attested customer is still screened for sanctions |
PCI DSS v4.0.1 requirement summary
A summary for orientation. The Report on Compliance is the authority once issued.
| Requirement | Where it lands |
|---|---|
| 1 and 2: network controls and secure configuration | A separate namespace and node pool for the cardholder data environment, network policies, hardened images |
| 3: protect stored account data | Encryption with a per-record key, no CVC, card numbers dropped where network tokens suffice, card fingerprints by keyed hash |
| 4: encrypt transmission | TLS 1.2 or later everywhere, mutual TLS between the API and the tokeniser |
| 5 and 6: malware protection and secure development | Code review, dependency and secret scanning on every change |
| 7 and 8: access control and identification | No standing human access to the cardholder data environment; emergency access with two approvals; scoped keys for merchants |
| 9: physical security | Cloud provider attestation |
| 10: logging and monitoring | Append-only audit log and log retention with integrity controls |
| 11: testing | The programme under Certifications and testing |
| 12: policies | A written security policy and incident response runbook |
| Guidance for merchants | Hosted fields and Checkout put you on SAQ A |
Disclosure
Found a vulnerability? Tell us first.
We work with researchers who report in good faith, and we credit them when they want credit.
Security contact
What we ask
- Report to the security contact, encrypted where possible, with steps to reproduce.
- Give us reasonable time to fix the issue before you disclose it publicly.
- Use test accounts and sandbox keys. Do not access, change or keep other people's data.
- Do not degrade the service: no denial-of-service testing, spam or social engineering of staff or merchants.
What we do
- Keep you informed until the issue is fixed.
- Credit you, if you want, once the fix is live.
In scope
pediwave.com, docs.pediwave.com, dashboard.pediwave.com, the public API, hosted Checkout and payment pages, the tokeniser origin, and our published SDKs.
Out of scope
Denial of service, physical attacks, social engineering, third-party services we link to, and reports from automated scanners without a demonstrated impact.
Contact: mailto:[email protected]
Expires: 2027-10-10T00:00:00.000Z
Preferred-Languages: en
Canonical: https://www.pediwave.com/.well-known/security.txt
Policy: https://www.pediwave.com/security#disclosure Customers and merchants with an urgent operational incident should use the support route in the dashboard. The security contact is for vulnerability reports.
Shared responsibility
Our half, and your half.
Most incidents we can prevent start on one side of this line. Here is who does what.
| Area | What PediWave does | What you do |
|---|---|---|
| Keys | Shows each key once, scopes it, allowlists and signs on request, rolls with a grace window, rate-limits abuse and tells you about it | Keep secret and restricted keys on your servers. Use restricted keys for each integration. Roll a key the moment you suspect it has leaked |
| Card data | Hosts the card fields, runs the tokeniser and vault inside the cardholder data environment, refuses card numbers anywhere else | Use hosted fields or Checkout. Never log or forward card numbers. Complete your SAQ A each year |
| Webhooks | Signs and timestamps every event, sends from fixed IP addresses, retries and lets you replay | Verify the signature and the timestamp on every delivery. Ignore duplicates by event id. Confirm high-value orders by reading the object back from the API |
| Customer data | Encrypts it, keeps identity numbers in Nigeria, redacts logs, supports export and deletion | Collect only what you need, with a lawful basis. Answer your customers' data requests, using our export and delete calls |
| Offline acceptance | Signs policies, verifies every tap at settlement, quarantines what fails, enforces revocation | Set per-tap limits and ceilings that suit your risk. Revoke a lost terminal at once. Choose your loss policy |
| Agents and floats | Holds floats on the ledger with approval chains, reconciles daily, enforces caps | Review agent floats and ceilings. Reconcile our daily delivery against your core |
| Payouts | Requires a second approver above your threshold, pays only to verified settlement accounts | Set the approval threshold. Keep approver accounts personal and protected |
| Incidents | Monitors around the clock, pages on card-number detector hits and double-spend spikes, notifies you as the DPA sets out | Keep your contact details current in the dashboard. Report anything suspicious to the security contact |
Your first duty: verify every webhook.
A forged "paid" event is the cheapest attack on any merchant. Twelve lines stop it. Compute the HMAC over the timestamp and the raw body, compare in constant time, and reject anything older than five minutes.
Webhooks in the docs (opens docs site)import crypto from "node:crypto";
export function verify(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(",").map(p => p.split("=")));
const t = Number(parts.t);
if (Math.abs(Date.now() / 1000 - t) > 300) return false; // older than 5 minutes
const expected = crypto.createHmac("sha256", secret)
.update(`${t}.${rawBody}`).digest("hex");
const v1s = header.split(",").filter(p => p.startsWith("v1=")).map(p => p.slice(3));
return v1s.some(v => v.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(v), Buffer.from(expected)));
} Questions reviewers ask.
Do I need to be PCI DSS compliant to take cards with PediWave?
Where is my customers' data held?
What happens if a customer spends the same offline balance twice?
One of our secret keys has leaked. What should we do?
DELETE /api/keys/{id}; it stops working within seconds. If you need time to redeploy, roll it instead: the new key works at once and the old one for up to 72 hours. Check your request logs for the last 30 days, then tell the security contact.Can we see your penetration test and PCI documentation?
Need the full picture?
The security overview covers every control on this page in more depth.