Signing Seller API Requests (multipart/form-data)
The Create Seller and Update Seller APIs send data as
multipart/form-data (because they include a file upload in the files field), unlike most other
Baokim APIs which send application/json. Because of this, how you compute the Signature for these two
APIs differs from the general guidance on the API Introduction page — this page covers
that difference.
Before continuing, make sure you're familiar with
6. Signature Format Details and
7. General Security Guidelines on the Introduction page —
the rules about keyVersion, algorithm, the RSA/ED25519 key pair, and the Signature header still
apply as-is. Only the content being signed (plaintext) is different.
1. Difference from regular JSON APIs
| Regular JSON API | Create/Update Seller API | |
|---|---|---|
| Content-Type | application/json | multipart/form-data |
| Signed data (plaintext) | The raw JSON request body, verbatim | A JSON object rebuilt from all parsed form fields (see section 2) |
Baokim determines whether a request is "multipart" based on the Content-Type header. If this header
contains multipart/form-data or application/x-www-form-urlencoded, the system does not use the
raw body to verify the signature (the raw body of a multipart request contains boundaries, per-part
headers, and binary file data — it can't be signed/compared directly like JSON). Instead, the system
rebuilds a JSON object from all the parsed fields, and verifies against that.
2. How to build the plaintext to sign
plaintext = JSON of every field in the form (including the files field), encoded with the
JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE flags.
plaintext = json_encode(<all parsed form fields>, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)
Important notes when rebuilding this object on your side:
-
Regular text/array fields (
request_id,request_time,merchant_code,seller_id,platform, ...): include the exact value you sent, keeping the same data type (string/array) as documented in the Request table of each API. -
The
filesfield — this is the easiest part to get wrong: the binary content of the file is not included in the plaintext. On the server side, eachfileelement in thefilesarray is an internal file-handle object with no public properties exposed — so when the whole payload isjson_encode()-ed, everyfileelement always serializes to an empty object{}, regardless of the actual file name or content. When you rebuild the plaintext to sign on your side, replace the value of eachfilekey with{}(an empty object) — not the file name, not the file content, not a base64 encoding of the file.Example (2
fileselements with differenttype):"files": [
{ "type": "1", "file": {} },
{ "type": "2", "file": {} }
] -
Field order: add fields to the object in the exact order they were sent in the multipart form (usually the order your HTTP client/SDK builds the request). Since
json_encode()preserves the key order of the source array, a different order produces a different plaintext → signature verification will fail.
3. Full example
Using the sample request from the Create Seller page, the plaintext to sign is:
{
"request_id": "MERCHANT12345678901234510281",
"request_time": "2024-11-15 14:36:00",
"merchant_code": "MERCHANT001",
"sub_merchant_code": "MERCHANT001",
"seller_id": "SELLER123456",
"seller_name": "Nguyễn Văn A",
"platform": [
{
"type": "2",
"links": "https://shopee.vn/seller123",
"platform_seller_id": "SHOPEE123456"
}
],
"files": [
{ "type": "1", "file": {} },
{ "type": "2", "file": {} }
],
"representative_DOB": "1990-01-01",
"representative_ID_number": "001099012345",
"representative_name": "Nguyen Van A",
"representative_nationality": "Vietnam",
"representative_address": "1 Dai Co Viet Street, Hai Ba Trung District, Ha Noi",
"seller_business_type": "2",
"seller_business_registration_no": "0123456789",
"seller_phone": "0912345678",
"seller_email": "[email protected]",
"seller_business_description": "Online retail store selling electronics",
"seller_risk_level": "1",
"gc_code": "5045",
"mcc_code": "5399"
}
Once you have this plaintext, the remaining steps (signing with your private key using the registered
algorithm, base64-encoding the signature, attaching it to the Signature header along with
keyVersion/algorithm) follow the general guidance in
section 6 of the Introduction page.
4. Common mistakes
| Symptom | Common cause |
|---|---|
| Signature always fails even though the data sent is correct | Real file content/name was put into the plaintext instead of {} |
| Signature only fails when there's more than 1 file | The order of elements in the files array doesn't match the order they were sent |
| Signature works in a pure-JSON test but fails on the real multipart submission | Signing the raw body (application/json style) was used for a multipart/form-data request |