Upgrade from API v1
Detailed comparison between legacy userapi and API v2 to help plan your migration.
Changes from Legacy (userapi/)
| Aspect | Legacy (userapi/) | API v2 (/v2/) |
|---|---|---|
| Base URL | https://my.sepay.vn/userapi/ | https://userapi.sepay.vn/v2 |
| Authentication errors | HTTP 200, empty body | HTTP 401, JSON body |
| Business errors | HTTP 200 | HTTP 422 with error_code |
| Response key | transactions, bankaccounts, count_transactions | Always data |
| Identifiers | Numeric auto-increment | UUID |
| Currency type | float (string) | integer |
| Pagination | limit (default 5000), since_id | page/per_page (default 20, max 100), since_id for polling |
| Amount filters | Exact match (amount_in=X) | Range (amount_in_min/amount_in_max) |
| Date filters | transaction_date_min/_max | transaction_date_from/_to |
| Rate limit header | x-sepay-userapi-retry-after | Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset |
Legacy endpoints (userapi/*) remain unchanged and continue to work normally. You can use both legacy and API v2 in parallel during migration.
Endpoint Mapping
| V1 | V2 | Note |
|---|---|---|
GET /userapi/transactions/list | GET /v2/transactions | |
GET /userapi/transactions/details/{id} | GET /v2/transactions/{uuid} | Numeric ID -> UUID |
GET /userapi/transactions/count | (removed) | Use pagination.total |
GET /userapi/bankaccounts/list | GET /v2/bank-accounts | |
GET /userapi/bankaccounts/details/{id} | GET /v2/bank-accounts/{uuid} | Numeric ID -> UUID |
GET /userapi/bankaccounts/count | (removed) | Use pagination.total |
GET /userapi/bidv/{id}/orders | GET /v2/bank-accounts/{uuid}/orders | |
POST /userapi/bidv/{id}/orders | POST /v2/bank-accounts/{uuid}/orders | |
GET /userapi/bidv/{id}/orders/{oid} | GET /v2/bank-accounts/{uuid}/orders/{uuid} | |
DELETE /userapi/bidv/{id}/orders/{oid} | DELETE /v2/bank-accounts/{uuid}/orders/{uuid} | |
POST /userapi/bidv/{id}/orders/{oid}/vas | POST /v2/bank-accounts/{uuid}/orders/{uuid}/va | |
DELETE /userapi/bidv/{id}/orders/{oid}/vas/{va} | DELETE /v2/bank-accounts/{uuid}/orders/{uuid}/va/{va} | |
| (none) | GET /v2/bank-accounts/{uuid}/va | New: Virtual Accounts API |
Migration Steps
Update Base URL
Change https://my.sepay.vn/userapi/ to https://userapi.sepay.vn/v2.
Switch from Numeric IDs to UUIDs
All v2 endpoints use UUIDs instead of numeric IDs. Get UUIDs from list responses or save them when creating new resources.
Update amount handling (float -> integer)
V1: "amount_in": "18067000.00" (string, float)V2: "amount_in": 18067000 (integer)
Remove float/string parsing functions when processing amounts from v2.
Update pagination (limit -> page/per_page)
V1 uses limit (default 5000). V2 uses page/per_page (default 20, max 100). To fetch all data, iterate through pages until has_more: false.
Update error handling
V1 always returns HTTP 200; you need to parse the body to detect errors. V2 returns proper HTTP status codes (401, 404, 422, 429). Check the HTTP status before parsing the body.
Comparison Examples
List transactions:
curl -X GET "https://my.sepay.vn/userapi/transactions/list?limit=20" \-H "Authorization: Bearer YOUR_TOKEN"
curl -X GET "https://userapi.sepay.vn/v2/transactions?per_page=20" \-H "Authorization: Bearer YOUR_TOKEN"
Response format:
{"status": 200,"messages": {"success": true},"transactions": [...]}
{"status": "success","data": [...],"meta": {"pagination": {"total": 150,"per_page": 20,"has_more": true}}}
Handling IDs
API v2 uses UUIDs for all identifiers. Numeric IDs from v1 do not work with v2 endpoints.
Example:
- V1:
GET /userapi/transactions/details/12345 - V2:
GET /v2/transactions/a1b2c3d4-e5f6-7890-abcd-ef1234567890
To get the corresponding UUID, call the v2 list endpoint and map based on business fields (account number, reference number, etc.).
Pagination
| V1 | V2 | |
|---|---|---|
| Parameters | limit | page, per_page |
| Default | 5000 records | 20 records/page |
| Maximum | 5000 | 100 records/page |
| Polling | since_id (numeric) | since_id (UUID) |
| Check for more data | Compare returned count with limit | meta.pagination.has_more |
To fetch all data, increment page until has_more: false:
# Page 1GET /v2/transactions?page=1&per_page=100# Page 2 (if has_more: true)GET /v2/transactions?page=2&per_page=100