Create Conversion
Execute a foreign exchange conversion based on the FIRM quote obtained from Get FX Quote. quote_id is mandatory — conversions without a quote are not supported.
Workflow
Idempotency Mechanism
request_id is the idempotency key. If Merchant resends a request with the same request_id (due to timeout, retry), the system does not create a new order but returns the result of the original order.
Handling timeout:
- Timeout with unclear result → (1) retry with same
request_id, or (2) query via Get Conversion Detail - Do not change
request_idwhen retrying for the same order
Quote Binding Constraints
- Each
quote_idexecutes successfully only once → resending already-used quote (with differentrequest_id) → code 426 - Quote past
expires_at→ code 425, request a new quote - Quote must belong to the same
merchant_codethat obtained it; mismatch → code 425
Endpoint
- URL:
/api/v1/fx/convert - Method:
POST
Request
| Parameter | Data Type | Required | Description |
|---|---|---|---|
| request_id | string(50) | Yes | Unique code identifying the request, serving as idempotency key. See section 3 Introduction |
| request_time | string(19) | Yes | See section 3 Introduction |
| merchant_code | string(20) | Yes | See section 3 Introduction |
| quote_id | string(50) | Yes | FIRM quote code obtained from Get FX Quote, still within expiry time (expires_at) |
| from_currency | string(3) | Yes | Source currency, must match exactly with the quote |
| from_amount | decimal(18,2) | Yes | Source amount to convert, must match exactly with from_amount in the quote |
Amount Cross-Check Mechanism
from_currency and from_amount are explicit confirmation fields, must match exactly with values in the quote.
Mismatch → code 428, order not executed. Merchant wants to convert a different amount → request a new FIRM quote.
Example Request
{
"request_id": "MERCHANT1234BK202606050002",
"request_time": "2026-06-05 10:15:45",
"merchant_code": "MERCHANT1234",
"quote_id": "FXQ0605A7K2M9XD41",
"from_currency": "USD",
"from_amount": 10000.00
}
Response
| Parameter | Data Type | Required | Description |
|---|---|---|---|
| response_code | int(4) | Yes | Result code. 200 = success (check status in data), other codes = error |
| response_message | string(200) | Yes | Description of the result code |
| merchant_code | string(20) | Yes | Merchant code |
| data | Object | Yes | Conversion order details (see table below) |
data Structure
| Parameter | Data Type | Description |
|---|---|---|
| conversion_id | string(50) | Conversion order code generated by Baokim, used for querying and reconciliation |
| origin_request_id | string(50) | request_id of the original order (equals the request_id sent; useful when response comes from idempotency mechanism) |
| status | string(20) | Order status: PROCESSING (processing), SUCCESS (success), FAILED (failed, no balance movement) |
| quote_id | string(50) | Quote code executed |
| trade_type | string(4) | Transaction type (SELL/BUY) |
| currency_pair | string(10) | Normalized currency pair (e.g., USD/VND) |
| rate | decimal(18,4) | Exchange rate executed (same as rate in quote) |
| from_currency | string(3) | Source currency |
| from_amount | decimal(18,2) | Source amount deducted |
| to_currency | string(3) | Destination currency |
| to_amount | decimal(18,2) | Destination amount credited |
| created_at | string(19) | Order creation time (GMT+7), format YYYY-MM-DD HH:MM:SS |
| completed_at | string(19) | Completion time. Null when status = PROCESSING. |
Example Response
{
"response_code": 200,
"response_message": "Success",
"merchant_code": "MERCHANT1234",
"data": {
"conversion_id": "FXC202606051015450001",
"origin_request_id": "MERCHANT1234BK202606050002",
"status": "SUCCESS",
"quote_id": "FXQ0605A7K2M9XD41",
"trade_type": "SELL",
"currency_pair": "USD/VND",
"rate": 26450.0000,
"from_currency": "USD",
"from_amount": 10000.00,
"to_currency": "VND",
"to_amount": 264500000,
"created_at": "2026-06-05 10:15:45",
"completed_at": "2026-06-05 10:15:46"
}
}
Notes
Timeout or connection loss when calling this API does not mean the order failed. Merchant must handle via the idempotency mechanism above, not assume FAILED status. Use Get Conversion Detail to determine the final result.
Error Codes
| Response Code | Response Message | Description |
|---|---|---|
| 200 | Success | Check status in data for order result |
| 101 | System error | Unexpected error on Baokim's side |
| 110 | Invalid merchant code | merchant_code is undefined |
| 120 | Invalid Signature | Signature header is invalid |
| 422 | Validation error | Request field is missing or invalid |
| 425 | Quote not found, expired, or not owned by merchant | Quote past expires_at, not found, or not belonging to this merchant |
| 426 | Quote already used | This quote_id was already executed successfully (single-use) |
| 427 | Insufficient balance | Not enough source currency to execute conversion |
| 428 | Amount/currency mismatch with quote | from_currency or from_amount does not match quote |
| 429 | Too many requests | Exceeded rate limit for Merchant |