最快開始
一次呼叫就能拿到標籤
必填的只有 ComNo(客戶代號)和收件人資料。
寄件人姓名、地址、郵務局號、特約戶編號、劃撥帳號都會依 ComNo 自動帶入。
每次呼叫都要帶上我們核發給你的金鑰。
curl -X POST http://192.168.0.99:59035/datasnap/rest/TServerMethods1/RenderLabel \
-H "Content-Type: application/json" \
-H "X-Api-Key: ptk_6fa3acf8_bdf4dc63aad99b4b9fb0ae914ec5d250" \
-d '{
"ComNo": "100009",
"RName": "李大華",
"RMobile": "0922333444",
"RAddress": "台北市中正區忠孝東路一段1號12樓之3",
"Contents": "文件",
"Weight": "1.2",
"AmountCollected": 0
}'
回應中的 pdf_base64 解碼後即為標籤 PDF。
認證
金鑰放標頭,每次呼叫都要帶
我們會為你核發一把金鑰,格式如下:
ptk_6fa3acf8_bdf4dc63aad99b4b9fb0ae914ec5d250
放在 HTTP 標頭:
X-Api-Key: ptk_6fa3acf8_bdf4dc63aad99b4b9fb0ae914ec5d250
不要把金鑰放在網址裡(例如 ?apikey=…)。
網址會被記錄在伺服器存取記錄、瀏覽器歷史與 Referer 標頭中,
等於到處留下金鑰副本。標頭不會。
金鑰綁定客戶代號
每把金鑰只能使用核發時指定的 ComNo。
拿金鑰去印其他客戶代號的標籤會被拒絕;批次中的每一筆也都會逐一檢查 ——
外層帶合法代號、內層夾帶其他代號,同樣擋得下來。
一把金鑰可以綁多個客戶代號,若你有多個寄件人身分,請在申請時一併告知。
呼叫頻率限制
| 限制 | 預設值 | 超過時 |
|---|---|---|
| 每分鐘 | 60 次 | 回傳 step: "rate-limit",稍後重試即可 |
| 每日 | 5000 次 |
用量需求較高請告知,我們可以個別調整。 注意一次批次呼叫只算一次,所以大量列印請用批次,不要逐筆呼叫。
金鑰保管
- 金鑰等同帳號密碼,請存放在設定檔或環境變數,並限制檔案存取權限。
- 不要寫進前端網頁原始碼,任何人按 F12 都看得到。
- 不要提交到版本控制,就算之後刪掉,歷史紀錄仍留存。
- 金鑰遺失無法找回(我們只保存雜湊值),請聯繫我們停用舊金鑰並重新核發。
端點
兩種呼叫方式,同一支功能
| 方法 | 路徑 | 說明 |
|---|---|---|
POST |
/datasnap/rest/TServerMethods1/RenderLabel |
JSON 直接放在 request body。建議使用,沒有長度限制。 |
GET |
/datasnap/rest/TServerMethods1/RenderLabel/{json} |
JSON 經 URL encode 後接在路徑上。長地址容易超過網址長度上限,僅供除錯。 |
GET |
/datasnap/rest/TServerMethods1/Ping |
健康檢查,確認服務存活。 |
POST 的 body 就是純 JSON,不需要 DataSnap 慣用的
{"_parameters":[...]} 包裝。
請求欄位
你要傳什麼,伺服器補什麼
| 欄位 | 型別 | 說明 |
|---|---|---|
ComNo 必填 |
字串 | 客戶代號。用來查出整組寄件人資料。 |
Rec |
整數 | 同一個 ComNo 有多筆寄件人時指定序號。省略時取序號最小的那筆。 |
RName |
字串 | 收件人姓名。 |
RMobile |
字串 | 收件人手機。 |
RPhoneDay |
字串 | 收件人日間電話(僅 74 代收標籤會印出)。 |
RAddress |
字串 | 收件人地址。 |
RZip |
字串 | 收件人郵遞區號。省略時自動以地址查詢中華郵政取得 6 碼。 |
Contents |
字串 | 內裝物品。 |
Weight |
字串或數字 | 重量(公斤)。 |
AmountCollected |
整數 | 代收貨款金額。大於 0 時自動改用 74 上下聯代收標籤, 郵件種類一律強制為 74。 |
MailClass |
字串 |
78 掛號包裹(預設)、58 快捷郵件、18 普通掛號。
有代收金額時此欄位會被忽略。
|
PackageSize |
整數 | 郵資級數 1–3,印成 * / ** / ***。 |
Express |
整數 | 快捷區 1–3,印成 ● / ▲ / □。 |
Memo |
字串 | 備註,印在標籤上。 |
MultiNo |
字串 | 單點多件編號,附在收件人地址後。 |
records |
陣列 | 批次模式。詳見批次列印。 |
由伺服器自動帶入的資料
以下欄位不需要也無法由呼叫端指定,一律依 ComNo 從客戶資料取得:
| 標籤上的內容 | 來源 |
|---|---|
| 寄件人姓名 自動 | 客戶名稱 |
| 寄件人地址、郵遞區號 自動 | 客戶地址;郵遞區號為空時自動查詢 |
| 寄件人電話 自動 | 手機、市話 |
| 收寄局名 自動 | 郵務局名 |
| 特約戶編號 自動 | 特約戶編號 |
| 劃撥戶名、帳號 自動 | 存簿劃撥資料(74 代收標籤使用) |
| 無法投遞處理方式 自動 | 客戶備註;未設定時帶入「※若無法投遞時,請退回原寄局」 |
回應格式
結果都在 result[0] 裡
回應最外層固定包一層 {"result":[ … ]},
這是 DataSnap 的格式,無法移除。呼叫端一律取 result[0]。
{
"result": [{
"ok": true,
"count": 1,
"success": 1,
"failed": 0,
"pages": 1,
"pdf_base64": "JVBERi0xLjQK…",
"mail_no": "16146183002174807001",
"mail_class": "74",
"label_type": "74上下聯",
"s_zip": "603004",
"r_zip": "807041",
"office_no": "830021",
"serial_pool": "0",
"story_rec": 517816,
"records": [ { … 同上單筆內容 … } ]
}]
}
| 欄位 | 說明 |
|---|---|
ok | 整體是否成功。 |
count / success / failed | 總筆數 / 成功 / 失敗。 |
pages | PDF 頁數,等於成功筆數。 |
pdf_base64 | 標籤 PDF,Base64 編碼。解碼後即可存檔或送印。 |
mail_no | 20 碼郵件號碼。 |
label_type | 78橫印 或 74上下聯。 |
r_zip / s_zip | 實際使用的收件人 / 寄件人郵遞區號。 |
story_rec | 交寄歷史檔的紀錄編號,可供後續對帳。 |
records | 逐筆結果陣列。單筆呼叫時,該筆內容同時攤平在頂層。 |
郵件號碼
20 碼的組成
號碼由伺服器配發,每次呼叫遞增且不重複。呼叫端不需要、也不應該自行產生號碼。
郵件種類的兩碼為 78 包裹、58 快捷、18 信函、74 代收貨款。
批次列印
多筆合併成單一多頁 PDF
把多筆資料放進 records 陣列。ComNo 可以放在外層當共用值,
個別筆需要不同寄件人時再自行覆寫。
{
"ComNo": "100009",
"records": [
{ "RName": "李大華", "RAddress": "台北市中正區忠孝東路一段1號",
"Contents": "文件", "AmountCollected": 0 },
{ "RName": "王小明", "RAddress": "高雄市三民區建工路1號",
"Contents": "生鮮", "AmountCollected": 1500 },
{ "RName": "陳先生", "RAddress": "台中市西區民權路1號",
"Contents": "急件", "MailClass": "58", "AmountCollected": 0 }
]
}
回傳的 pdf_base64 是一份多頁 PDF,每張標籤一頁,
送印一次就能印完整批。78 橫印與 74 上下聯可以混在同一批。
單筆失敗不會影響整批。
失敗的筆只會在 records 中標記錯誤原因,其餘照常產生標籤,
pages 會等於實際成功的筆數。
錯誤處理
step 會指出卡在哪一段
失敗時格式與成功一致,多出 step 與 error 兩個欄位:
{
"result": [{
"ok": false,
"step": "lookup-sender",
"error": "[21ComName] 查無此 ComNo:NOT_EXIST"
}]
}
單筆呼叫的 step 與 error 就是該筆的失敗原因。
批次呼叫若整批都失敗,頂層會是概括訊息
沒有任何一筆成功,各筆的實際原因請看 records 陣列。
step 對應伺服器的處理順序,可直接定位問題:
-
解析 JSON、檢查必填欄位 parse-payload · parse-record
-
驗證金鑰、確認可使用該客戶代號 auth
-
檢查呼叫頻率 rate-limit
-
依
ComNo查出寄件人與郵務局號 lookup-sender -
決定郵件種類(有代收金額則強制 74) resolve-mail-class
-
查詢收件人郵遞區號 zip-lookup
-
配發 20 碼郵件號碼 gen-mail-no
-
寫入交寄歷史檔 save-history
-
繪製標籤、輸出 PDF render · pdf-wrap
常見錯誤
| 訊息 | 處理方式 |
|---|---|
缺少 X-Api-Key |
請求沒有帶金鑰標頭。注意金鑰要放標頭,不是網址或 body。 |
金鑰無效 |
金鑰不存在或有誤,請確認是否完整複製(含 ptk_ 前綴)。 |
金鑰已停用 |
此金鑰已被停用,請與我們聯繫。 |
此金鑰無權使用客戶代號 … |
金鑰未綁定該客戶代號。需要新增請與我們聯繫。 |
呼叫過於頻繁 |
已達每分鐘上限,稍候再試。大量列印請改用批次。 |
缺少必填欄位 ComNo |
請確認外層或該筆有帶 ComNo。 |
查無此 ComNo |
客戶代號不存在,請確認代號是否正確。 |
郵務局號不是 6 碼 |
該客戶的寄件人資料尚未設定郵務局號,請先於後台補齊。 |
單次最多 200 筆 |
請將資料分批送出。 |
Message content is not a valid JSON value |
body 不是合法 JSON,請檢查編碼與逗號括號。 |
交寄歷史會在產生標籤之前寫入,因此 每一張印出來的標籤都必定查得到對應紀錄。 若歷史寫入失敗,該筆就不會產生標籤。
程式範例
取得 PDF 並存檔
uses
System.Net.HttpClient, System.JSON, System.NetEncoding,
System.Classes, System.IOUtils;
var
Http: THTTPClient;
Body, Resp: TStringStream;
Root, Rec: TJSONObject;
Arr: TJSONArray;
begin
Http := THTTPClient.Create;
Body := TStringStream.Create(
'{"ComNo":"100009","RName":"李大華",' +
'"RAddress":"台北市中正區忠孝東路一段1號",' +
'"Contents":"文件","AmountCollected":0}', TEncoding.UTF8);
Resp := TStringStream.Create('', TEncoding.UTF8);
try
Http.ContentType := 'application/json';
Http.CustomHeaders['X-Api-Key'] := 'ptk_6fa3acf8_bdf4dc63aad99b4b9fb0ae914ec5d250';
Http.Post('http://192.168.0.99:59035/datasnap/rest/' +
'TServerMethods1/RenderLabel', Body, Resp);
Root := TJSONObject.ParseJSONValue(Resp.DataString) as TJSONObject;
try
Arr := Root.GetValue('result') as TJSONArray;
Rec := Arr.Items[0] as TJSONObject;
if Rec.GetValue<Boolean>('ok') then
begin
TFile.WriteAllBytes('label.pdf',
TNetEncoding.Base64.DecodeStringToBytes(
Rec.GetValue<string>('pdf_base64')));
ShowMessage('郵件號碼:' + Rec.GetValue<string>('mail_no'));
end
else
ShowMessage(Format('失敗 [%s] %s',
[Rec.GetValue<string>('step'), Rec.GetValue<string>('error')]));
finally
Root.Free;
end;
finally
Resp.Free; Body.Free; Http.Free;
end;
end;
const BASE = 'http://192.168.0.99:59035/datasnap/rest/TServerMethods1';
const resp = await fetch(`${BASE}/RenderLabel`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Api-Key': 'ptk_6fa3acf8_bdf4dc63aad99b4b9fb0ae914ec5d250'
},
body: JSON.stringify({
ComNo: '100009',
RName: '李大華',
RMobile: '0922333444',
RAddress: '台北市中正區忠孝東路一段1號',
Contents: '文件',
Weight: '1.2',
AmountCollected: 0
})
});
const r = (await resp.json()).result[0];
if (!r.ok) throw new Error(`[${r.step}] ${r.error}`);
console.log('郵件號碼', r.mail_no);
// 開新分頁顯示 PDF
const bytes = Uint8Array.from(atob(r.pdf_base64), c => c.charCodeAt(0));
const url = URL.createObjectURL(new Blob([bytes], { type: 'application/pdf' }));
window.open(url, '_blank');
using System.Net.Http;
using System.Text;
using System.Text.Json;
const string Base = "http://192.168.0.99:59035/datasnap/rest/TServerMethods1";
var payload = new {
ComNo = "100009",
RName = "李大華",
RAddress = "台北市中正區忠孝東路一段1號",
Contents = "文件",
AmountCollected = 0
};
using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-Api-Key",
"ptk_6fa3acf8_bdf4dc63aad99b4b9fb0ae914ec5d250");
var content = new StringContent(
JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json");
var resp = await http.PostAsync($"{Base}/RenderLabel", content);
var json = JsonDocument.Parse(await resp.Content.ReadAsStringAsync());
var r = json.RootElement.GetProperty("result")[0];
if (!r.GetProperty("ok").GetBoolean())
throw new Exception($"[{r.GetProperty("step").GetString()}] " +
$"{r.GetProperty("error").GetString()}");
Console.WriteLine($"郵件號碼 {r.GetProperty("mail_no").GetString()}");
File.WriteAllBytes("label.pdf",
Convert.FromBase64String(r.GetProperty("pdf_base64").GetString()));
$base = 'http://192.168.0.99:59035/datasnap/rest/TServerMethods1'
$payload = @{
ComNo = '100009'
RName = '李大華'
RAddress = '台北市中正區忠孝東路一段1號'
Contents = '文件'
AmountCollected = 0
} | ConvertTo-Json
$headers = @{ 'X-Api-Key' = 'ptk_6fa3acf8_bdf4dc63aad99b4b9fb0ae914ec5d250' }
$resp = Invoke-RestMethod -Uri "$base/RenderLabel" -Method Post `
-Headers $headers -ContentType 'application/json' -Body $payload
$r = $resp.result[0]
if (-not $r.ok) { throw "[$($r.step)] $($r.error)" }
Write-Host "郵件號碼 $($r.mail_no)"
[System.IO.File]::WriteAllBytes(
"$PWD\label.pdf", [Convert]::FromBase64String($r.pdf_base64))
限制與注意
上線前先確認這幾點
| 項目 | 數值 |
|---|---|
| 單批筆數上限 | 200 筆 |
| 產生速度 | 約 110 ms/張 |
| PDF 大小 | 約 165 KB/頁 |
| 200 筆預估 | 約 22 秒、33 MB |
- 號碼一經呼叫即配發。 即使後續列印失敗,該號碼也不會回收,會留下斷號。斷號本身無害, 但請避免以重試的方式測試。
-
郵遞區號查詢依賴中華郵政的外部服務。
若該服務暫時無法連線,會改以
000代替而不會讓整張標籤失敗。 要避免這種情況,可在請求中自行帶入RZip。 - 大批次請預留逾時時間。 HTTP client 的 timeout 建議設為 120 秒以上。
- 標籤紙為 10×15 公分。 列印時請確認印表機紙張設定,並關閉「縮放至頁面大小」。