Send Money Security: Registered Recipients and Cooling Periods

PayMongo has introduced a set of security enhancements for the PayMongo Wallet that protect your funds against unauthorized transfers — even in the worst case where your API keys or dashboard account are compromised. This guide explains what changes, how to register and verify recipients, and how to update your integration.

🛡️

Why we built this

Most wallet fraud follows the same pattern: an attacker gains access to a merchant's credentials, adds their own bank account as a destination, and drains the wallet within minutes. These enhancements break that pattern in three places — transfers can only go to destinations you have registered in advance, registering a destination requires a one-time password (OTP) sent to the account owner's email, and newly registered destinations must wait through a cooling period before they can receive funds. The result: stolen credentials alone are no longer enough to move your money.

What's changing

When these security features are enabled on your organization:

EnhancementWhat it means for you
Registered recipients onlyInstaPay and PESONet transfers can only be sent to bank accounts or e-wallets that you have registered as recipients of your wallet. Transfers to unregistered destinations are rejected.
OTP verification for new recipientsRegistering a new recipient triggers a one-time password sent to your account owner's registered email address. The recipient is only created once the OTP is verified.
Recipient cooling period (12 hours)A newly registered recipient cannot receive transfers until 12 hours after it was registered. Transfers attempted during this window are rejected.
Wallet settings cooling period (12 hours)Sensitive wallet changes — wallet type, transfer limits, and account name — no longer take effect immediately. They are queued as a pending change and applied automatically after 12 hours.

Everything else about sending money stays the same: the transfer endpoints, request format, fees, statuses, and webhooks described in Send Money are unchanged.

Prerequisites

  1. An activated PayMongo Wallet.
  2. The security enhancements enabled on your organization — this is done by PayMongo during onboarding (see below).
  3. Access to your account owner's registered email address — this is where recipient verification OTPs are sent.
  4. Your recipient's details: bank or e-wallet name, account name, and account number.

How the features are enabled

These security features are enabled per organization by PayMongo as part of your onboarding. If you're unsure whether the features are active on your account, or you'd like them enabled, reach out to your PayMongo account manager or [email protected].

⚠️

Register your recipients before activation

The moment the features are enabled on your organization, every InstaPay and PESONet transfer must go to a registered recipient — any transfer to an unregistered destination is rejected, including destinations you were paying out to regularly before activation. To avoid interrupted payouts, register and verify all of your payout destinations at least 12 hours before your activation date, so they are past their cooling period when the switch is flipped. Your PayMongo team will walk you through this during onboarding.

Until the features are enabled on your organization, transfers behave exactly as before.

Registering a recipient

Registering a recipient is a two-step process: create the recipient (which sends an OTP to your account owner's email), then verify the OTP.

Step 1: Create the recipient

Register the destination against the wallet that will send the funds. The bank_code is the institution's BIC — the same code returned by the receiving institutions endpoint you already use for transfers.

curl -X POST https://api.paymongo.com/v2/wallets/recipients \
  -u sk_live_xxxxxxxx: \
  -H "Content-Type: application/json" \
  -d '{
    "wallet_id": "wallet_xxxxxxxx",
    "provider": "instapay",
    "bank_code": "BOPIPHMMXXX",
    "bank_account_name": "Juan Dela Cruz",
    "bank_account_number": "001234567890"
  }'

When recipient verification is enabled, this does not immediately create the recipient. Instead, it sends a 6-digit OTP to your account owner's registered email and returns a challenge:

{
  "data": {
    "id": "chal_xxxxxxxx",
    "expires_at": 1755672000
  }
}

expires_at is a Unix timestamp indicating when the OTP expires. If it lapses, simply create the recipient again to receive a fresh OTP.

Step 2: Verify the OTP

Submit the code from the email using the challenge ID from Step 1:

curl -X POST https://api.paymongo.com/v2/wallets/recipients/challenges/chal_xxxxxxxx/verify \
  -u sk_live_xxxxxxxx: \
  -H "Content-Type: application/json" \
  -d '{ "code": "123456" }'

On success, the recipient is created and returned:

{
  "data": {
    "id": "wr_xxxxxxxx",
    "wallet_id": "wallet_xxxxxxxx",
    "provider": "instapay",
    "bank_code": "BOPIPHMMXXX",
    "bank_account_name": "Juan Dela Cruz",
    "bank_account_number": "001234567890"
  }
}

An invalid or expired code returns a validation error — request a new challenge by repeating Step 1.

📘

Registering the same destination twice

If a recipient with the same provider, bank code, and account number already exists on the wallet, no duplicate is created — you'll still be asked to verify an OTP, and after verification the existing recipient is returned. This does not reset its cooling period.

Managing recipients

List the recipients registered to a wallet:

curl -X GET "https://api.paymongo.com/v2/wallets/recipients?wallet_id=wallet_xxxxxxxx&provider=instapay" \
  -u sk_live_xxxxxxxx:

Remove a recipient you no longer transfer to:

curl -X DELETE https://api.paymongo.com/v2/wallets/recipients/wr_xxxxxxxx \
  -u sk_live_xxxxxxxx:
⚠️

Deleting and re-registering restarts the clock

If you delete a recipient and register it again later, it is treated as a new recipient and must wait through the full 12-hour cooling period again.

The recipient cooling period

A newly registered recipient enters a 12-hour cooling period starting from the moment it is created (after OTP verification). During this window, transfers to that recipient are rejected. Once 12 hours have elapsed, transfers proceed normally — no further action is needed on your part.

This delay is intentional: it gives you and your team time to notice and act on an unauthorized recipient registration before any money can move. Every recipient registration triggers an OTP email, so an unexpected email is your signal to review your account immediately.

Plan your payouts accordingly. If you know you'll need to pay a new supplier or partner, register their account at least 12 hours before the first payout is due.

Sending transfers

Transfers are created exactly as before via POST /v2/batch_transfers. With registered recipients enabled, each InstaPay or PESONet transfer in the batch is validated at creation time:

  1. The destination (bank code + account number) must match a registered recipient of the source wallet.
  2. That recipient must be past its 12-hour cooling period.

If any transfer in the batch fails validation, the entire batch is rejected and no transfers are created. The error identifies the failing item by its index in your transfers array:

{
  "errors": [
    {
      "code": "parameter_invalid",
      "detail": "transfer at index 0: destination is not a registered recipient"
    }
  ]
}
{
  "errors": [
    {
      "code": "parameter_invalid",
      "detail": "transfer at index 2: destination recipient is still in cooling period"
    }
  ]
}

Fix or remove the failing item — or wait for the cooling period to lapse — and resubmit the batch.

The wallet settings cooling period

Changes to sensitive wallet settings are also protected. When you request a change to your wallet's type, transfer limits, or account name — for example through your PayMongo account manager or support — the change no longer takes effect immediately. It is queued as a pending change and applied automatically 12 hours after it is requested.

Keep in mind:

  • One pending change at a time. A wallet can only have one change queued. If you need to revise a request that's already pending, wait for it to apply first (up to 12 hours), then request the next change.
  • Plan ahead. If you know you'll need a higher transfer limit for an upcoming payout run, request it at least 12 hours in advance.
  • Not everything is delayed. Changes like wallet status updates and statement-of-acceptance submissions are not subject to the cooling period and take effect right away.

Error reference

Error detailCauseWhat to do
destination is not a registered recipientThe transfer destination doesn't match any registered recipient of the source wallet.Register the recipient (and verify the OTP), or double-check the bank code and account number match the registered details exactly.
destination recipient is still in cooling periodThe recipient was registered less than 12 hours ago.Wait until 12 hours have passed since registration, then resubmit. Do not delete and re-register — that restarts the clock.
wallet recipient challenge not foundThe challenge ID in the verify call is wrong or no longer exists.Create the recipient again to get a new challenge.
Invalid or expired OTP codeThe code was mistyped or expires_at has passed.Re-check the code from the email, or create the recipient again for a fresh OTP.
organization account owner not foundWe couldn't find a registered account owner email to send the OTP to.Contact [email protected] to verify your account owner details.

FAQ

Do I need to change my existing transfer integration?
The transfer request format is unchanged. You need to (1) register and verify your payout destinations as recipients before transferring to them, and (2) handle the two new validation errors above when creating batch transfers.

Which transfers are affected?
InstaPay and PESONet transfers from your PayMongo Wallet. Recipient checks apply per transfer item within a batch.

How long is the cooling period?
12 hours — for both newly registered recipients and pending wallet settings changes.

What happens to destinations I was transferring to before the feature was enabled?
Past transfer history does not carry over — once the feature is enabled, only registered recipients can receive transfers, regardless of how often you paid a destination before. Register all of your payout destinations before activation. Recipients registered more than 12 hours ago are past their cooling period and can receive transfers immediately.

Who receives the OTP?
The registered account owner of your organization, via email. Make sure this inbox is monitored and secured with a strong password and two-factor authentication.

What should I do if I receive an OTP email I didn't request?
Treat it as a potential account compromise: do not share the code, rotate your API keys from the dashboard immediately, and contact [email protected].

Can the cooling period be waived for an urgent payout?
No. The cooling period is a core security control and cannot be bypassed. Plan recipient registration ahead of your payout schedule.


Did this page help you?