🇪🇺 Whitelist-ready egress for PayPay

Static IP for PayPay

PayPay's production API only accepts calls from whitelisted IPs, and PayPay supports static addresses only. Send every signed Open Payment API call through two fixed static EU IPs, register the pair once, and stop fearing your next redeploy.

payments-team · shell

# one variable, fixed egress for everything

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

# the sandbox checks no IPs; production drops

# anything that is not whitelisted

curl -s -X POST https://apigw.paypay.ne.jp/v2/codes \

  -H "Authorization: hmac OPA-Auth:$KEY:$MAC:$NONCE:$EPOCH:$HASH" \

  -H "Content-Type: application/json" -d "$BODY"

The whitelist sits on PayPay's side. The moving part is your egress.

Production PayPay refuses calls from addresses it has never been told about, and telling it about a new address is a support request with a waiting period. Most platforms cannot promise an address that holds still.

Sandbox passes, live mode refuses

PayPay's test environment applies no IP address control, so certification goes smoothly and every sandbox call succeeds. Production is a different animal: an IP address whitelist is in place there, and the first live call from an unregistered address comes back UNAUTHORIZED with result code 08100016.

Whitelist changes take up to 4 days

Adding an address means a request to PayPay support that carries your API key and merchant ID, and PayPay states it may take up to 4 days to configure after the request. If your platform rotates its egress, a routine redeploy can quietly become a multi-day payment outage.

Static addresses are a hard requirement

PayPay's FAQ is blunt on this point: they only support static IP addresses, and if you do not have one you are asked to change your system configuration to use a static IP address. Serverless runtimes and container platforms that recycle their outbound addresses cannot satisfy that sentence on their own.

One merchant contract, many exit points

Order capture from the app servers, refund workers on a schedule, PayPay Points cashback calls, CI probing the sandbox before a release: each can leave from a different address unless they share a pair. Then you are registering a growing list with PayPay support and hoping none of the entries drifts.

The Solution

One fixed EU IP pair for every signed PayPay call

Your Platform

signed OPA calls

HTTPS Proxy

(Static EU IP)

PayPay

apigw.paypay.ne.jp

Register both fixed addresses in PayPay's production whitelist once, and every signed request afterwards arrives from an origin PayPay already trusts, whichever runtime issued it.

Set HTTPS_PROXY once in your platform's environment; order capture, refunds and cashback calls then leave from your fixed pair.
Both addresses are whitelisted, so they stand in for each other. If either proxy node drops out, the other keeps answering and your registered origin never wobbles.
TLS passes straight through to PayPay. Your API key, nonce and HMAC signature stay encrypted past the proxy hop; we never see them.

Why payment teams pin PayPay traffic to OutboundGateway

Whitelist tickets stop being routine

PayPay applies whitelist updates through a support request that can take up to 4 days to configure. A pair you register once removes the entire category of change tickets, no matter how often you redeploy behind it.

Wired for the documented auth model

Built around what PayPay actually specifies: one Authorization header in the hmac OPA-Auth format, an HMAC-SHA256 over the request path, method, nonce, epoch, content type and body hash, keyed with your API secret. The proxy pins the origin; your signing code stays untouched.

Recognizable on both sides

PayPay publishes the source IPs its webhook notifications come from, so inbound deliveries can be pinned too, and your outbound calls become recognizable in PayPay's logs instead of dissolving into a cloud range. Selling on other rails? Our Payfast static IP guide covers the same pattern for South African checkouts.

Designed for

Teams collecting through PayPay who want live traffic to leave from addresses PayPay has already whitelisted.

Merchants on the Open Payment API

Dynamic QR codes for in-store checkout, web payment links, app invoke flows. Whatever creates the payment on the customer's phone, the API call behind it can leave from one predictable pair.

Platforms running refunds and cashback

Reversals and PayPay Points cashback calls run unattended on schedules. Unattended jobs are exactly where a rotated egress address fails quietly, with an UNAUTHORIZED sitting in the logs until someone looks.

EU fintechs on Japanese rails

PayPay launched in 2018 as a joint venture involving SoftBank and Yahoo Japan and now counts more than 70 million registered users. Reaching Japanese consumers should not mean pushing your compliance perimeter outside the EU.

Teams mid-way through a live cutover

Sandbox certification passed, and the first live calls return UNAUTHORIZED 08100016? PayPay's own troubleshooting puts the registered source IP third on the checklist. Registering a fixed pair is often the fastest route to a live environment that stays working.

Implementation

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

Shell / environment

Set the variable wherever your platform runs, then sign requests exactly the way the OPA docs describe: MD5 over content type and body, HMAC-SHA256 over the newline-joined fields.

# .env, ECS task definition, Kubernetes secret, wherever config lives
HTTPS_PROXY=https://user:pass@eu-01.outboundgateway.com:8443

# sign it the OPA way: nonce, epoch, body hash, then HMAC
NONCE=$(openssl rand -hex 4)
EPOCH=$(date +%s)
BODY='{"merchantPaymentId":"order_4821","amount":{"amount":1000,"currency":"JPY"},"codeType":"ORDER_QR"}'
CT='application/json'
HASH=$( { printf %s "$CT"; printf %s "$BODY"; } | openssl dgst -md5 -binary | base64)
MAC=$(printf '%s\n%s\n%s\n%s\n%s\n%s\n' /v2/codes POST "$NONCE" "$EPOCH" "$CT" "$HASH" \
  | openssl dgst -sha256 -hmac "$API_SECRET" -binary | base64)

# create a payment code, egressing from your static EU IP
curl -s -X POST https://apigw.paypay.ne.jp/v2/codes \
  -H "Authorization: hmac OPA-Auth:$API_KEY:$MAC:$NONCE:$EPOCH:$HASH" \
  -H "Content-Type: application/json" -d "$BODY"

Python (requests)

requests reads HTTPS_PROXY from the environment automatically. The official paypayopa SDK signs the same way internally; set the variable next to it and the origin is pinned with zero signing code of your own.

import base64, hashlib, hmac, os, time, requests

def opa_headers(path, method, body, key, secret):
    nonce, epoch = os.urandom(4).hex(), str(int(time.time()))
    ct = "application/json"
    body_hash = base64.b64encode(hashlib.md5(ct.encode() + body).digest()).decode()
    payload = "\n".join([path, method, nonce, epoch, ct, body_hash])
    mac = base64.b64encode(hmac.new(secret.encode(), payload.encode(),
                                    hashlib.sha256).digest()).decode()
    return {"Content-Type": ct,
            "Authorization": f"hmac OPA-Auth:{key}:{mac}:{nonce}:{epoch}:{body_hash}"}

# create a payment code, egressing from your static EU IP
body = b'{"merchantPaymentId":"order_4821","amount":{"amount":1000,"currency":"JPY"},"codeType":"ORDER_QR"}'
requests.post("https://apigw.paypay.ne.jp/v2/codes",
              data=body,
              headers=opa_headers("/v2/codes", "POST", body,
                                  os.environ["PAYPAY_API_KEY"],
                                  os.environ["PAYPAY_API_SECRET"]))

Node.js (undici ProxyAgent)

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

import { ProxyAgent } from 'undici';
import crypto from 'node:crypto';

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

const nonce = crypto.randomBytes(4).toString('hex');  // 8 chars
const epoch = Math.floor(Date.now() / 1000);            // seconds
const body = JSON.stringify({
  merchantPaymentId: 'order_4821',
  amount: { amount: 1000, currency: 'JPY' },
  codeType: 'ORDER_QR',
});
const contentType = 'application/json';
const bodyHash = crypto.createHash('md5')
  .update(contentType).update(body).digest('base64');
const payload = ['/v2/codes', 'POST', nonce, epoch, contentType, bodyHash].join('\n');
const mac = crypto.createHmac('sha256', process.env.PAYPAY_API_SECRET)
  .update(payload).digest('base64');

const res = await fetch('https://apigw.paypay.ne.jp/v2/codes', {
  method: 'POST',
  dispatcher,
  headers: {
    'Content-Type': contentType,
    'Authorization': `hmac OPA-Auth:${process.env.PAYPAY_API_KEY}:${mac}:${nonce}:${epoch}:${bodyHash}`,
  },
  body,
});

Register the pair, then forget the form

The whitelist request is the one piece PayPay does by hand. Make it once, for both addresses, and the topic is closed.

# whitelist registration request to PayPay support:
#   your API key and merchant ID, plus both fixed IPv4 addresses
# PayPay notes configuration can take up to 4 days after the request

# route sandbox traffic through the same pair before the cutover,
# so going live changes credentials but never the source IP
HTTPS_PROXY=https://user:pass@eu-01.outboundgateway.com:8443

# debugging a live error? quote the X-REQUEST-ID response header
# to support; it identifies the exact call in PayPay's systems

Pin both addresses in the production whitelist

Your account ships with a pair of static EU IPv4 addresses. When you apply for production access, register both with PayPay, and use the same request form for any later change; include your API key and merchant ID and allow up to 4 days. Because both addresses are whitelisted, a proxy failover never turns into a support ticket, and PayPay supports subnet-mask entries if your footprint ever grows.

Which traffic is covered? Your outbound signed API calls, to the sandbox host in test and apigw.paypay.ne.jp in production (the legacy api.paypay.ne.jp host is marked deprecated in the current OPA docs). Route the sandbox through the pair as well, so switching environments changes credentials but never your source address. Webhook notifications arrive inbound at your server from PayPay's own published addresses; in production those are 52.68.128.84, 52.192.112.175, 13.115.29.37, 13.208.67.224, 13.208.235.224 and 13.208.127.89. Allowlist those on your firewall and validate every delivery; 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.

Japanese payment rails, European egress

PayPay puts your checkout in front of Japan's dominant mobile wallet, accepted at more than 10 million merchant locations. Where your requests leave from is still your decision.

EU residency for your side of the wire

PayPay launched in 2018 as a joint venture involving SoftBank and Yahoo, now LY Corporation, and serves more than 70 million registered users. Your outbound hop stays in EU data centres, keeping one simple residency story for the customer data riding in your API calls.

Sealed end to end

The connection to PayPay is never terminated at the proxy. Your API key, HMAC signature and payment payloads stay encrypted the whole way to PayPay, so nothing sensitive ever appears in the clear on the proxy hop.

What you get

Built for the production whitelist

Two single public IPv4 addresses, exactly the artifact PayPay's whitelist expects. Register them once and the static-address requirement is satisfied for good.

Outlives your infrastructure

Deploys roll, pods reschedule, functions cold-start. The address pair PayPay knows you by stays constant through all of it.

Sealed past the proxy

TLS passthrough keeps your Authorization header, nonce and payment payloads encrypted through the proxy hop.

One pair, every surface

Live API calls, sandbox certification runs and CI smoke tests all arrive from the same two addresses, so one whitelist entry set describes everything.

Either IP carries the load

Failover between the two nodes is invisible to PayPay: both addresses are registered, both are trusted, and neither needs a support ticket to take over.

Simple pricing

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

Register once, then stop thinking about egress

Set one environment variable and sandbox runs, live calls and batch jobs all leave from two fixed EU addresses PayPay already trusts.

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

Frequently asked questions

Does PayPay require a static IP?

Effectively, yes, in production. PayPay's FAQ states that the production environment applies IP address whitelist control while the test environment does not, and that only static IP addresses are supported: without one, you are asked to change your system configuration to use a static IP address. A fixed proxy pair satisfies the requirement without touching your architecture.

How do I whitelist my proxy IPs with PayPay?

Through the PayPay support request form: include your API key and merchant ID alongside the addresses. PayPay notes it may take up to 4 days to configure after the request, so register both fixed IPs up front; subnet-mask entries are supported if you ever need them.

What about webhooks from PayPay?

They arrive inbound at your server, not through the proxy. PayPay publishes its webhook source IPs; in production the list includes 52.68.128.84 and 13.208.127.89 among six addresses. Allowlist those on your firewall and validate every notification. The proxy carries your outbound API traffic only.

Your PayPay integration, pinned to two addresses

Tell us how your PayPay integration ships today, and we will map the fixed pair onto it.

Contact Our Founders →