3.1 Create PayIn
POST /api/v2/deposits
- p2c
- p2p
Request
- Headers
- Body
| Parameter | Type | Required | Description |
|---|---|---|---|
| X-Api-Key | string | Yes | Your enabled merchant API key. |
| X-Signature | string | Yes | Lowercase hexadecimal HMAC-SHA256 of the exact raw JSON body, using the API signing secret. |
| Content-Type | string | Yes | application/json. |
v2 does not require X-Timestamp or X-Request-Id. See authentication.
| Parameter | 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 BDT 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. |
fields.mobile_number | string | Shop-dependent | Customer mobile number, corresponding to v1 paymentData.mobile_number. For a shop accepting the local BDT format, use "01700000000"; keep the leading zero. |
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 request
BDT example including the customer mobile number from the v1 guide. Replace your_bdt_shop with your actual shop code and confirm that its PayIn schema accepts mobile_number in this format. Include any other fields required by that shop:
{
"order_id": "DEP-BDT-1001",
"amount": 500,
"currency": "BDT",
"method": "your_bdt_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": {
"mobile_number": "01700000000",
"merchant_user_ip": "203.0.113.10"
}
}
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.
The number belongs inside fields, not at the top level or inside paymentData. Do not rename it to phone: these are different keys. If the shop has an input schema that does not list mobile_number, the API ignores this key. The local format here does not define the format for a withdrawal's account_number.
When migrating from v1, also check the request-field mapping and customer-data limitations. A string such as merchant-user-001 is not a valid customer_account_id, and the v1 customer IP is supplied as fields.merchant_user_ip.
Response
Response fields
HTTP 200.
| Parameter | Type | Description |
|---|---|---|
| transaction_id | string | Payfield transaction ID. Store it for status requests. |
| redirect_url | string | Full signed payment URL. Redirect the customer to this URL unchanged. |
Example response
- Success
- Error
{
"transaction_id": "12346",
"redirect_url": "https://pay.example.com/payin-pages/12346?expires=1801227600&signature=example-signature"
}
HTTP 400 for an invalid request:
{
"error": {
"code": 400,
"message": "Bad request"
}
}
See API errors for other responses.
Use your assigned P2P shop code as method and its configured fields. Confirm that the PayIn channel is enabled for your shop. The v2 request and response structure is shared across these shop types.
Request
- Headers
- Body
| Parameter | Type | Required | Description |
|---|---|---|---|
| X-Api-Key | string | Yes | Your enabled merchant API key. |
| X-Signature | string | Yes | Lowercase hexadecimal HMAC-SHA256 of the exact raw JSON body, using the API signing secret. |
| Content-Type | string | Yes | application/json. |
v2 does not require X-Timestamp or X-Request-Id. See authentication.
| Parameter | 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 BDT 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. |
fields.mobile_number | string | Shop-dependent | Customer mobile number, corresponding to v1 paymentData.mobile_number. For a shop accepting the local BDT format, use "01700000000"; keep the leading zero. |
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 request
BDT example including the customer mobile number from the v1 guide. Replace your_bdt_shop with your actual shop code and confirm that its PayIn schema accepts mobile_number in this format. Include any other fields required by that shop:
{
"order_id": "DEP-BDT-1001",
"amount": 500,
"currency": "BDT",
"method": "your_bdt_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": {
"mobile_number": "01700000000",
"merchant_user_ip": "203.0.113.10"
}
}
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.
The number belongs inside fields, not at the top level or inside paymentData. Do not rename it to phone: these are different keys. If the shop has an input schema that does not list mobile_number, the API ignores this key. The local format here does not define the format for a withdrawal's account_number.
When migrating from v1, also check the request-field mapping and customer-data limitations. A string such as merchant-user-001 is not a valid customer_account_id, and the v1 customer IP is supplied as fields.merchant_user_ip.
Response
Response fields
HTTP 200.
| Parameter | Type | Description |
|---|---|---|
| transaction_id | string | Payfield transaction ID. Store it for status requests. |
| redirect_url | string | Full signed payment URL. Redirect the customer to this URL unchanged. |
Example response
- Success
- Error
{
"transaction_id": "12346",
"redirect_url": "https://pay.example.com/payin-pages/12346?expires=1801227600&signature=example-signature"
}
HTTP 400 for an invalid request:
{
"error": {
"code": 400,
"message": "Bad request"
}
}
See API errors for other responses.
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.