3.1 Create deposit
POST /api/v2/deposits
Send one JSON object with the v2 authentication headers. Send no query string. The successful response is HTTP 200, including when the operation already has a failed result; always retrieve its status.
| Field | Type | Required | Description |
|---|---|---|---|
order_id | string, max 255 characters | Yes | Your deposit identifier. Unique per merchant and operation type for idempotency. |
amount | JSON number | Yes | Positive amount, at most two decimal places. Do not send a quoted string. |
currency | string, 3 letters | Yes | Use VND for this guide; it must match the selected shop's currency. |
method | string | No | Exact active shop code. Omit to use your default active shop. Do not add surrounding spaces. |
customer_account_id | JSON integer | No | Your customer's account identifier used by the shared payment checks. Send an integer, not a quoted number; 0 is preserved. Omit or use null when unavailable. |
callback_url | HTTPS URL | Yes | Absolute callback URL without embedded credentials. |
success_url | HTTP(S) URL | Yes | Browser return destination when the current v2 status is SUCCESS. |
pending_url | HTTP(S) URL | Yes | Browser return destination when the current v2 status is PENDING. |
fail_url | HTTP(S) URL | Yes | Browser return destination when the current v2 status is FAILED. |
fields | JSON object | No* | Additional data defined by the selected shop's PayIn schema. See shop fields. |
fields.merchant_user_ip | string (IPv4 or IPv6) | Shop-dependent | Customer IP address. Supported for every shop; required only when the selected shop's input schema requires it. Omit or use null when optional and unavailable. |
All four URL fields must be non-empty strings containing absolute URLs without embedded credentials, whitespace, or control characters. callback_url must use HTTPS; browser return URLs accept HTTP or HTTPS. Do not send a separate return_user_url: v2 selects among the three supplied destinations.
The v2 protocol does not require fields, but the selected shop may require individual keys. fields must be a JSON object, not an array. It cannot override protocol fields such as method, customer_account_id, success_url, pending_url, fail_url, or return_user_url.
Example for an active VND EPT PayIn shop configured with payer account details. Replace your_vnd_shop with your actual shop code and use the field schema assigned to that shop:
{
"order_id": "DEP-VND-1001",
"amount": 250000,
"currency": "VND",
"method": "your_vnd_shop",
"customer_account_id": 77,
"callback_url": "https://merchant.example.com/webhooks/payfield",
"success_url": "https://merchant.example.com/payment/success",
"pending_url": "https://merchant.example.com/payment/pending",
"fail_url": "https://merchant.example.com/payment/fail",
"fields": {
"account_number": "0123456789",
"holder": "Nguyen Van An",
"merchant_user_ip": "203.0.113.10"
}
}
Response 200:
{
"transaction_id": "12346",
"redirect_url": "https://pay.example.com/payin-pages/12346?expires=1801227600&signature=example-signature"
}
Treat redirect_url as the full URL returned by the API; do not build it from transaction_id. Store transaction_id and check its status. A retry with the same order_id and equivalent request returns the same operation. Reusing that ID with different request data returns 409. Idempotency is scoped to the merchant and deposit type, across shops; an existing v1 deposit with the same ID also conflicts. See API errors.
Customer page and preparation
The returned URL opens a signed Payfield page. If payment preparation is still in progress, it shows a preparation message and refreshes approximately every two seconds. Once ready, it opens the configured payment page or displays payment instructions. Reopening the URL does not create another deposit.
If preparation stops while the financial result is still unknown, the page may show a waiting message and a return option. Keep the order pending and retrieve its status; a delay is not proof of failure. When the operation already has a terminal v2 result, opening the Payfield entry page follows the corresponding return destination instead of offering an old payment artifact.
Returning to your site
Your configured payment page or provider return link sends the customer through a signed Payfield return URL. At that moment Payfield reads the current status and selects:
| Current status | Saved destination |
|---|---|
SUCCESS | success_url |
FAILED | fail_url |
PENDING | pending_url |
Confirm that this return link is enabled for your shop's payment page/provider flow. Return handling is a browser navigation action: it neither confirms a payment nor changes its result. Use the authenticated status endpoint to decide whether to fulfill the order. To correlate browser returns, include your own order reference in the three merchant URLs when creating the deposit.
Keep signed Payfield URLs unchanged, including their query parameters. The example signature above is illustrative, not usable. Links expire according to the configured payment-page access window; an expired or altered signature is refused with HTTP 403. Repeating create does not renew that window. A page-link expiry does not by itself mean that the deposit failed: continue to use the status API. Previously issued provider links may retain their earlier return behavior; confirm compatibility during onboarding.