Skip to main content

IP Whitelisting

Money leaving your wallet needs a second factor on top of your API key. A leaked key alone should never be enough to drain a balance.

When a person approves a payout in the dashboard, that second factor is an OTP. When your server approves a payout, there is nobody to read an OTP, so the second factor is where the request came from: POST /api/v2/payment/approve only accepts calls from an IP address you have registered against your project.

This is the only place IP whitelisting applies. Collections, payout creation, and every read endpoint work from anywhere.

Registering an address

Add it in the dashboard under Settings. The whitelist endpoints require a dashboard login in addition to your API key, so this is deliberately not something an API key alone can change: an attacker holding your key cannot add their own IP.

The underlying endpoints, for reference:

EndpointPurpose
GET /api/v2/project/whitelistList entries
POST /api/v2/project/whitelistAdd an entry, body { "ip_address": "196.192.0.10", "name": "Production API server" }
DELETE /api/v2/project/whitelist/{id}Remove an entry

Both IPv4 and IPv6 addresses are accepted.

Register every address you can leave from

Entries are matched as exact strings. There is no CIDR or wildcard support, so 196.192.0.0/24 is not a valid entry and will not match anything.

That means one entry per egress address. In practice, register:

  • every application server that calls the approve endpoint,
  • every NAT gateway or egress IP your platform hands out, not just the one you happened to observe,
  • both addresses of any active/standby pair,
  • any outbound proxy you route through.

Autoscaling groups and most managed container platforms can egress from a pool of addresses. Pin your outbound traffic to a fixed NAT gateway or a static egress IP before you rely on this, or approvals will fail intermittently and look like a MALIPOPAY fault.

How your address is determined

MALIPOPAY reads the first entry in the X-Forwarded-For header, falling back to the socket's remote address. If your requests pass through a proxy or CDN on the way out, the address that matters is the one that proxy presents, not your server's private address.

The fastest way to find out what MALIPOPAY actually sees is to attempt an approval and read the 403: it names the address it rejected.

Debugging a 403

A 403 on POST /api/v2/payment/approve means one of:

  1. The calling address is not registered.
  2. It is registered but the entry has been deactivated or removed.
  3. Your egress address changed, typically after a redeploy, a scaling event, or a change of network path.
  4. The apiToken itself is invalid or missing, which produces the same status.

Confirm the token independently with a harmless call such as GET /api/v2/payment/channels. If that succeeds and approve still 403s, it is the IP.

Two known limits

  • expires_at is not enforced. If you set an expiry on an entry, it is recorded but the approval gate ignores it. Treat entries as permanent until deleted, and remove them yourself when a server is decommissioned.
  • No CIDR support, as above. A range will never match.

Operational hygiene

  • Name every entry after the system it belongs to. An unnamed list of addresses becomes impossible to prune safely.
  • Remove entries when you decommission a server. An address that has returned to a cloud provider's pool can end up belonging to someone else.
  • Review the list whenever you change hosting.