Endpoints

Endpoints

The system provides 2 endpoints for Merchants

orgId and merchantId are issued by the provider when you sign up — you don't create them yourself


Create a Pay-In Request

POST https://api.please-payment.com/api/PaymentRequest/org/{orgId}/action/SubmitPayInRequest/{merchantId}

Creates a Payment Request and returns a QR Code for the customer to scan and transfer funds directly into the Merchant's account.

Request Body

Field Type Required Description
RefId1 string ✅ Reference ID from the Merchant (must be unique)
RefId2 string ❌ Additional reference 2
RefId3 string ❌ Additional reference 3
PayerName string ✅ Name of the payer
RequestedAmount number ✅ Amount (must be greater than 0 and within the range set by the Merchant)
Currency string ✅ Currency — currently only THB is supported
QrProvider string ✅ Bank issuing the QR — PP (PromptPay) or SCB
Description string ❌ Description of the transaction
CustomerEmail string ❌ Customer's email
CustomerPhone string ❌ Customer's phone number
Tags string ❌ Tag for grouping transactions

Sample Request

{
  "RefId1": "ORDER-20260701-001",
  "PayerName": "Somchai Jaidee",
  "RequestedAmount": 325,
  "Currency": "THB",
  "QrProvider": "PP",
  "Description": "Payment for goods",
  "RefId2": "CUST-12345"
}

Response

{
  "status": "OK",
  "description": "Success",
  "paymentResponse": {
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "sessionId": "session-abc123",
    "type": "PayIn",
    "status": "Pending",
    "requestedAmount": 325.00,
    "generatedAmount": 325.52,
    "currency": "THB",
    "qrCode": "00020101021...",
    "qrCodeImage": "data:image/png;base64,...",
    "paymentUrl": "https://...",
    "websocketPath": "/realtime/payment-tx",
    "createdAt": "2026-07-01T10:00:00Z",
    "expireAt": "2026-07-01T10:15:00Z",
    "isQrAvailable": true,
    "payInBankCode": "SCB",
    "payInBankAccountNo": "xxx-xxxxx-x",
    "payInBankAccountName": "Company Name",
    "payInPromptPayId": null,
    "slipUploadUrl": "/payin-slip-upload/org123/3fa85f64-5717-4562-b3fc-2c963f66afa6/a1b2c3d4-..."
  }
}

Response Fields

Field Description
id UUID of the Payment Request — keep it for reference
status Current status (see Payment Status)
requestedAmount The amount requested
generatedAmount The actual amount to be paid (may include a randomized fraction of a baht for matching)
isQrAvailable true if a QR Code is ready for the customer to scan, false if the destination account doesn't support QR (e.g. not linked to PromptPay) — see details below
qrCodeImage The QR Code image as Base64 — can be displayed directly in your app (empty when isQrAvailable is false)
payInBankCode Destination bank code
payInBankAccountNo Destination account number
payInBankAccountName Destination account name
payInPromptPayId Destination PromptPay number (if any)
sessionId Used to connect via WebSocket to receive real-time status
websocketPath The WebSocket path (/realtime/payment-tx)
expireAt When the QR Code expires
slipUploadUrl Relative path to the slip upload page — has no domain prefix, must be concatenated with https://merchant.please-payment.com (see explanation below) to form the full URL, then given to the customer to open the slip upload page without needing to log in

Important — which domain to concatenate: slipUploadUrl is a relative path only. You must concatenate it with the https://merchant.please-payment.com domain yourself. For example, if slipUploadUrl is /payin-slip-upload/org123/xxx/yyy, form the full URL as https://merchant.please-payment.com/payin-slip-upload/org123/xxx/yyy

Displaying the QR and Account Info

Always check isQrAvailable before rendering:

Scenario How to display
isQrAvailable = true Show the QR Code from qrCodeImage for the customer to scan as usual
isQrAvailable = false No QR Code — show the account details (payInBankCode, payInBankAccountNo, payInBankAccountName, payInPromptPayId) so the customer can enter the transfer manually

Note: It's recommended to always show the account details (payInBankCode, payInBankAccountNo, payInBankAccountName, payInPromptPayId) alongside the QR Code — some customers may prefer to transfer manually even when a QR is available

Recommended: Turn slipUploadUrl into a QR Code displayed on your payment page — the customer scans it with their phone camera and opens the slip upload page directly, without typing the URL. Works for both standard Pay-In and Pay-In P2P

Slip Upload Page

When the customer opens the Slip Upload URL, they'll see the slip upload page for that Payment Request, which offers:

  • Upload slip image — choose an image from the camera or the phone's gallery
  • Slip reference number — enter the first 4 and last 4 digits of the slip reference number (alphanumeric) for matching and duplicate detection
  • Note — an optional field for additional text
  • Duplicate slip check — the system automatically warns if a slip with the same reference number already exists
Upload Payment Slip
Upload your transfer slip

Select a payment slip image to upload

Tap to select image
JPG, PNG, WebP
—
First 4 digits Last 4 digits
⚠️
Duplicate slip found!
If the same reference number is found, the system shows a warning with the option to continue uploading or cancel

The customer does not need to log in to use this page — the URL already has a token embedded and expires after 24 hours

Even if the HTTP status code is 200, you must still check the status field in the response body — if "OK", it succeeded; any other value indicates an error (see Error Handling)


Create a Pay-In Request (P2P)

POST https://api.please-payment.com/api/PaymentRequest/org/{orgId}/action/SubmitPayInRequestP2P/{merchantId}

Creates a Peer-to-Peer (P2P) Pay-In Request — the system automatically matches it with a pending Pay-Out Request, and the customer transfers funds directly to the recipient's account (instead of transferring via the system's QR Code).

What is P2P? Instead of funds going into the Merchant's account first and then being transferred out, P2P lets the sender transfer directly to the recipient — the system's role is to match and confirm the transaction.

Request Body

Field Type Required Description
RefId1 string ✅ Reference ID from the Merchant (must be unique)
RefId2 string ❌ Additional reference 2
RefId3 string ❌ Additional reference 3
PayerName string ✅ Name of the payer
RequestedAmount number ✅ Amount (must be greater than 0 and within the range set by the Merchant)
Currency string ✅ Currency — currently only THB is supported
QrProvider string ✅ PP or SCB (used internally by the system for matching)
Description string ❌ Description of the transaction

Sample Request

{
  "RefId1": "P2P-ORDER-20260701-001",
  "PayerName": "Somchai Jaidee",
  "RequestedAmount": 1000,
  "Currency": "THB",
  "QrProvider": "PP"
}

Response

{
  "status": "OK",
  "description": "Success",
  "paymentResponse": {
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "type": "PayIn",
    "status": "Pending",
    "requestedAmount": 1000.00,
    "generatedAmount": 1000.00,
    "currency": "THB",
    "qrCode": null,
    "qrCodeImage": "",
    "isQrAvailable": false,
    "payInBankCode": "KBANK",
    "payInBankAccountNo": "012-3-45678-9",
    "payInBankAccountName": "Recipient Account Name",
    "payInPromptPayId": "0812345678",
    "slipUploadUrl": "/payin-slip-upload/org123/3fa85f64-5717-4562-b3fc-2c963f66afa6/a1b2c3d4-..."
  }
}

Differences from Standard Pay-In

Standard Pay-In Pay-In P2P
isQrAvailable true (usually) false (usually) — P2P accounts are often not linked to PromptPay
qrCodeImage QR Code image Empty ("") when isQrAvailable = false
payInBankAccountName Merchant's account The recipient's account (from the matched Pay-Out Request)
Transfer method Scan the QR Code Transfer directly to the account specified in the response (enter account details manually)
slipUploadUrl ✅ ✅ (very important — the customer must upload a slip as proof)

Important: For P2P — isQrAvailable is usually false because the destination account may not be linked to PromptPay. In this case you must display the account details (payInBankCode, payInBankAccountNo, payInBankAccountName, payInPromptPayId) so the customer can enter the transfer manually, and also show slipUploadUrl so they can upload proof of transfer.

Important — which domain to concatenate: slipUploadUrl is a relative path, same as standard Pay-In. You must concatenate it with https://merchant.please-payment.com yourself, e.g. https://merchant.please-payment.com/payin-slip-upload/org123/xxx/yyy (see the full explanation in Response Fields above)

Recommended: Turn slipUploadUrl into a QR Code shown alongside the destination account details — the customer transfers funds, then scans the QR to open the slip upload page directly without typing the URL (see the slip upload page example above)

Error ERROR_NO_P2P_ACCOUNT_MATCH: If there is no pending Pay-Out Request in the system, you'll receive this error — meaning there's currently no matching transaction available.


Create a Pay-Out Request

POST https://api.please-payment.com/api/PaymentRequest/org/{orgId}/action/SubmitPayOutRequest/{merchantId}

Creates a request to transfer funds out to a destination account.

Request Body

Field Type Required Description
RefId1 string ✅ Reference ID from the Merchant (must be unique)
RefId2 string ❌ Additional reference 2
RefId3 string ❌ Additional reference 3
RequestedAmount number ✅ Amount (must be greater than 0)
QrProvider string ✅ Must be PP (PromptPay only, for Pay-Out)
BankCode string ✅ Destination bank code, e.g. SCB, KBANK, BAY — see all supported codes
BankAccountNo string ✅ Destination account number
BankAccountName string ✅ Destination account name
PromptPayId string ❌ Destination PromptPay number
AccountType string ❌ Account type: Native or PromptPay

Destination account details: BankCode+BankAccountNo+BankAccountName must always be sent (see Supported Bank Codes), even when paying out via PromptPay — if you also know the destination's PromptPay number, you may additionally send PromptPayId+AccountType, or send PayinBankAccountId (an ID from the system) instead of all of the above

Recommended: If you know the destination account's PromptPay number, it's recommended to send PromptPayId — transferring via PromptPay lets the system process faster, and the recipient receives funds more quickly

Sample Request (Bank Account Transfer)

{
  "RefId1": "PAYOUT-20260701-001",
  "RequestedAmount": 500,
  "QrProvider": "PP",
  "BankCode": "KBANK",
  "BankAccountNo": "0123456789",
  "BankAccountName": "Somchai Jaidee",
  "AccountType": "Native"
}

Sample Request (PromptPay Transfer)

{
  "RefId1": "PAYOUT-20260701-002",
  "RequestedAmount": 200,
  "QrProvider": "PP",
  "PromptPayId": "0812345678",
  "AccountType": "PromptPay"
}

Response

{
  "status": "OK",
  "description": "Success",
  "paymentResponse": {
    "id": "7bc95f12-3a21-4f89-c4ed-1d852a77bfc8",
    "type": "PayOut",
    "status": "Pending",
    "requestedAmount": 500.00,
    "currency": "THB",
    "createdAt": "2026-07-01T10:05:00Z"
  }
}

Create a Withdrawal Request

POST https://api.please-payment.com/api/PaymentRequest/org/{orgId}/action/SubmitWithdrawalRequest/{merchantId}

Use this endpoint when the Merchant itself is withdrawing funds out to its own account — as opposed to a standard Pay-Out, which transfers funds out to the Merchant's customer. Internally the system creates the exact same kind of request as a Pay-Out, just flagged as a withdrawal, so it appears separately from ordinary Pay-Outs in reporting.

Request body, fee calculation, response shape, and webhooks are all 100% identical to Create a Pay-Out Request — the only difference is the endpoint path (SubmitWithdrawalRequest instead of SubmitPayOutRequest). Everything documented above for Pay-Out applies here unchanged.

Request Body

Same as Create a Pay-Out Request — RefId1, RefId2, RefId3, RequestedAmount, QrProvider, and destination account fields (BankCode+BankAccountNo+BankAccountName, or PromptPayId+AccountType, or PayinBankAccountId).

Sample Request

{
  "RefId1": "WITHDRAW-20260701-001",
  "RequestedAmount": 500,
  "QrProvider": "PP",
  "BankCode": "KBANK",
  "BankAccountNo": "0123456789",
  "BankAccountName": "Somchai Jaidee",
  "AccountType": "Native"
}

Response

{
  "status": "OK",
  "description": "Success",
  "paymentResponse": {
    "id": "7bc95f12-3a21-4f89-c4ed-1d852a77bfc8",
    "type": "PayOut",
    "status": "Pending",
    "requestedAmount": 500.00,
    "currency": "THB",
    "createdAt": "2026-07-01T10:05:00Z"
  }
}

Webhooks: No new event type — a Withdrawal Request still fires the same PaymentOut.Success / PaymentOut.Rejected events documented in Webhooks, with the same payload fields.