Ctrl K

PCE AP Write API — 介接手冊(外部廠商)

對象:與 NetSuite 介接的外部系統/廠商開發人員
目的:說明如何透過 RESTlet 寫入台灣進項電子發票資料與相關 AP 交易
相關:技術與測試文件 · English · Postman
HTML:HTML 版

1. 快速開始

  1. 向客戶 NetSuite 管理員取得:
    • Account ID(如 TD1234567)
    • RESTlet External URL
    • OAuth 2.0 Integration:Client ID、(M2M 時)Certificate ID/私鑰,或 Authorization Code 用的 Client Secret/Redirect URI
  2. 先取得 OAuth 2.0 access token(Bearer)。
  3. 以 POST + options.validateOnly: true 試跑連線與驗證(不支援 GET)。
  4. 再以 POST + JSON 依業務情境選擇 action 寫入。

1.1 連線方式

項目說明
協定HTTPS
驗證OAuth 2.0(Authorization: Bearer {access_token})
Content-Typeapplication/json(寫入);取 token 時為 application/x-www-form-urlencoded
方法僅 POST(GET 回 PCE_METHOD_NOT_ALLOWED)
不使用 OAuth 1.0a/TBA 逐筆簽名。

External URL 範例(數字 id 以客戶環境為準):

https://{accountId}.restlets.api.netsuite.com/app/site/hosting/restlet.nl?script=xxx&deploy=yyy

Token endpoint:

https://{accountId}.suitetalk.api.netsuite.com/services/rest/auth/oauth2/v1/token
請勿將 Client Secret/私鑰/access token 寫死在公開程式庫。

1.2 OAuth 2.0 取得 Token(廠商建議:M2M)

Client Credentials(Machine-to-Machine) — 適用系統對系統、無使用者登入:

  1. Integration 勾選 Client Credentials (Machine to Machine),Scope 含 RESTlets。
  2. 產生憑證(例 ES256),於 Setup → Integration → OAuth 2.0 Client Credentials (M2M) Setup 上傳公鑰並綁定 Entity/Role/Application,記下 Certificate ID。
  3. 以私鑰簽署 JWT(iss=Client ID,aud=token URL,scope=restlets,header kid=Certificate ID)。
  4. POST token URL:
grant_type=client_credentials
client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
client_assertion={signed_jwt}
  1. 回應之 access_token 放入後續 RESTlet 請求標頭:Authorization: Bearer {access_token}。

輔助腳本:docs/postman/generate-client-assertion.js。

Authorization Code Grant — 適用需使用者登入的互動測試/應用;取得 token 後同樣使用 Bearer。

Postman:匯入 docs/postman/PCE-AP-Write.postman_collection.json → 先跑 0. Auth 取 token → 再打 RESTlet(Collection Auth = Bearer {{accessToken}})。

2. 業務情境(action)

每次 POST 必須帶 action,且只能擇一:

action用途必填不可帶
apInvoiceOnly只建立進項發票(可不掛交易)apInvoices(至少 1 筆)用來「新建」的 transaction(type/fields/行)
transactionOnly只建立或引用交易單transaction(物件或陣列;每筆需有 id 或 type,最多 10 筆)apInvoices
transactionWithApInvoices交易+一至多筆進項(1:N)每筆 transaction(物件或陣列,最多 10 筆)內嵌非空 apInvoices[]top-level apInvoices/invoices/apInvoicesByTransaction

公版只接受上表三種 action。API進項審核與請購單不在這份套件;送出那些 action 會回 INVALID_ACTION。

2.1 支援的交易類型

建立新交易時,transaction.type 限下列字串(大小寫不敏感):

typeNetSuite 交易
vendorbillVendor Bill
expensereportExpense Report
vendorcreditVendor Credit
vendorprepaymentVendor Prepayment

引用既有交易:只傳 transaction.id(內部 ID)即可;可省略 type/fields。

3. GET — 不允許

本 API 不支援 GET。對 External URL 發 GET 時,應收到:

{
  "success": false,
  "returnCode": "1014",
  "returnMessage": "PCE_METHOD_NOT_ALLOWED",
  "error": {
    "code": "PCE_METHOD_NOT_ALLOWED",
    "message": "GET is not allowed on PCE AP Write. Use POST with action=apInvoiceOnly|transactionOnly|transactionWithApInvoices.",
    "details": null
  }
}

契約與範例請見本文件與 Postman collection;連線試跑請用 options.validateOnly: true 的 POST。

4. POST — 寫入

4.1 共用結構

{
  "requestId": "a1b2c3d4-e5f6-4789-a012-3456789abcde",
  "action": "apInvoiceOnly | transactionOnly | transactionWithApInvoices",
  "apInvoices": [ { } ],
  "transaction": { },
  "options": {
    "validateOnly": false
  }
}
欄位必填說明
action必填三種之一:apInvoiceOnly/transactionOnly/transactionWithApInvoices(見 §2)
requestId必填冪等鍵。建議 UUID v4;8–64 字元,僅 A–Z a–z 0–9 - _。每一次邏輯寫入用新 key;網路重試必須重用同一把。
apInvoices依 action僅 apInvoiceOnly 必填(至少 1 筆);亦接受別名 invoices。其他 action 不可帶 top-level
transaction依 actiontransactionOnly/transactionWithApInvoices 必填(物件或陣列,最多 10 筆)。後者每筆須內嵌非空 apInvoices[]
options.validateOnly選填true 時只驗證進項(及 shape),不寫入資料(見各 action 差異)。失敗或 validateOnly 回應會附 requestSummary(精簡:index/clientRef/invoiceNo/type/id)
options.echoRequest選填預設不回傳。true 時在任何回應附上完整 request(除錯用;正式環境建議關閉)
clientRef選填放在每個 transaction 與/或每張 apInvoices[] 項目上(字串 1–64),成功回應會原樣回傳以便對帳
冪等:若相同 requestId 先前已成功寫入(非 validateOnly),再次呼叫會回傳上次結果並帶 idempotentReplay: true,不會再建資料。同 key 但 payload 不同 → REQUEST_ID_PAYLOAD_MISMATCH。
破壞性契約:transactionWithApInvoices 的進項必須放在 transaction.apInvoices(或多筆時每筆各自的 apInvoices)。不再接受 top-level apInvoices/apInvoicesByTransaction。

4.2 成功/失敗回應格式

每次回應(含 GET 被拒)頂層皆含 returnCode(4 位字串)與 returnMessage(固定英文短句),供外部系統程式判斷;success 與 error.code 仍保留。

成功碼(000x)

returnCode條件returnMessage
0000一般寫入成功(全部項目成功)OK
0001validateOnly: true 且全部通過VALIDATED
0002idempotentReplay: true(冪等重播,先前全成功)IDEMPOTENT_REPLAY
0003全部成功但有 warnings(稅額容差等)OK_WITH_WARNINGS
0004部分成功:至少一筆已寫入/通過,且至少一筆失敗PARTIAL_SUCCESS
Partial success:success 為 false,partialSuccess 為 true,returnCode 為 0004,但仍回完整 results[](成功項有 id/transactionId,失敗項有 error)。同一 requestId 重送相同 payload 會冪等回傳上次部分結果,不會重複建單;補送失敗項請用新 requestId 且只帶未成功資料。

成功(以 results[] 對應 request;每筆含 returnCode;可選 clientRef 原樣回傳):

{
  "success": true,
  "returnCode": "0000",
  "returnMessage": "OK",
  "action": "apInvoiceOnly",
  "requestId": "a1b2c3d4-e5f6-4789-a012-3456789abcde",
  "results": [
    {
      "index": 0,
      "returnCode": "0000",
      "returnMessage": "OK",
      "id": "1001",
      "invoiceNo": "CA12345678",
      "clientRef": "inv-001"
    }
  ]
}

部分成功(transactionWithApInvoices 多筆發票):

{
  "success": false,
  "partialSuccess": true,
  "returnCode": "0004",
  "returnMessage": "PARTIAL_SUCCESS",
  "action": "transactionWithApInvoices",
  "requestId": "a1b2c3d4-e5f6-4789-a012-3456789abcde",
  "error": {
    "code": "PARTIAL_SUCCESS",
    "message": "Partial success: 1 succeeded, 1 failed. Succeeded: [transaction[0].apInvoices[0] clientRef=… invoiceNo=CA12345678 id=1001 returnCode=0000]. Failed: [transaction[0].apInvoices[1] clientRef=… invoiceNo=AA99999999 returnCode=2001 error=PCE_AP_INVOICE_VALIDATION_ERROR].",
    "details": {
      "succeeded": 1,
      "failed": 1,
      "succeededItems": [{ "path": "transaction[0].apInvoices[0]", "clientRef": "…", "invoiceNo": "CA12345678", "id": "1001", "returnCode": "0000" }],
      "failedItems": [{ "path": "transaction[0].apInvoices[1]", "clientRef": "…", "invoiceNo": "AA99999999", "returnCode": "2001", "errorCode": "PCE_AP_INVOICE_VALIDATION_ERROR" }]
    }
  },
  "results": [
    {
      "index": 0,
      "returnCode": "0004",
      "returnMessage": "PARTIAL_SUCCESS",
      "transactionId": "789",
      "transactionType": "vendorbill",
      "transactionCreated": true,
      "apInvoices": [
        {
          "index": 0,
          "returnCode": "0000",
          "returnMessage": "OK",
          "id": "1001",
          "invoiceNo": "CA12345678"
        },
        {
          "index": 1,
          "returnCode": "2001",
          "returnMessage": "AP_INVOICE_VALIDATION_FAILED",
          "invoiceNo": "AA99999999",
          "error": {
            "code": "PCE_AP_INVOICE_VALIDATION_ERROR",
            "message": "…",
            "details": {}
          }
        }
      ]
    }
  ],
  "requestSummary": { }
}

失敗(單筆驗證失敗仍回 results[];多筆全失敗頂層常為 2100):

{
  "success": false,
  "returnCode": "2001",
  "returnMessage": "AP_INVOICE_VALIDATION_FAILED",
  "error": {
    "code": "PCE_AP_INVOICE_VALIDATION_ERROR",
    "message": "人類可讀說明",
    "details": null
  },
  "results": [
    {
      "index": 0,
      "returnCode": "2001",
      "returnMessage": "AP_INVOICE_VALIDATION_FAILED",
      "invoiceNo": "CA12345678",
      "error": {
        "code": "PCE_AP_INVOICE_VALIDATION_ERROR",
        "message": "人類可讀說明",
        "details": null
      }
    }
  ]
}
HTTP 與 returnCode:NetSuite RESTlet 業務失敗時 HTTP 仍常為 200;請以 body 的 returnCode/success 為準。OAuth 401/403 屬 token/角色問題,body 可能無 JSON。

進項驗證失敗時,error.code 常為 PCE_AP_INVOICE_VALIDATION_ERROR,details 為依欄位分組的錯誤明細。

warnings:仍判定成功,但有提示(例如稅額與 5% 計算差在容許範圍內)。請記錄並視需要人工覆核。

5. 進項發票欄位(apInvoices[])

建議使用 友善別名(camelCase)。亦可直接傳 NetSuite field id(custrecord_pce_ap_*)。

5.1 建議別名對照

建議別名中文必填備註
docFormatCode憑證格式代碼必填如 "21"~"29";亦可用 docType/formatCode
invCatCode發票類別代號條件必填格式 21:01/05;格式 25:06/07;亦可用 invoiceCategoryCode
docFormatName憑證格式名稱選填完整 Name(如 21-三聯式統一發票);可取代 invCatCode 消歧
docDate憑證開立日期必填YYYY/MM/DD 或 YYYY-MM-DD,如 2026/08/01
docPeriod資料所屬年月必填民國五碼 YYYMM,如 11508(可自 docDate 推算)
filingPeriod申報期別必填民國五碼 YYYMM
deductionCode進項扣抵代號必填1 進項可扣抵之進貨及費用/2 進項可扣抵之固定資產/3 進項不可扣抵之進貨及費用/4 進項不可扣抵之固定資產
invoiceNo發票號碼條件必填依格式/路徑;亦可用 invoiceNumber
otherDocNo其他憑證號碼條件必填依格式/彙加路徑
customsAuthCode海關代徵認證碼條件必填格式 28/29
utilityCarrierSn公用事業載具流水號條件必填格式 25
buyerTaxId買受人統一編號必填8 碼,含檢查碼
sellerTaxId銷售人統編條件必填依格式/彙加可能必填或禁填
taxType課稅別必填1 應稅/2 零稅率/3 免稅/F 作廢/D 空白未使用
salesAmount銷售金額條件必填亦可用 salesAmt;部分規則必填
taxAmount稅額條件必填亦可用 taxAmt;依課稅別/格式檢核
totalAmount總計選填亦可用 totalAmt
summaryMark彙加/分攤註記條件必填A 彙加/B 分攤;部分格式必填
summaryQty彙總數量條件必填彙加等情境
fileBizTax申報營業稅選填true/false 或 T/F
clientRef客戶對帳鍵選填字串 1–64;回應原樣回傳
transaction來源交易選填既有交易 internal id(掛 parent;CSV 亦可用 transactionId)

Lookup 類欄位可傳 業務代碼(建議)或 NetSuite internal id。

5.1.1 格式 21/25 與 ERP 欄位映射(invCatCode)

當 ERP 只傳營業稅代號 docFormatCode: "21" 或 "25" 時,須再帶 invCatCode(或 docFormatName/lookup internal id)消歧:

docFormatCodeinvCatCodeNetSuite Name(docFormatName)常見 ERP 憑證類型關鍵字
210121-三聯式統一發票三聯式、手開三聯式
210521-電子計算機統一發票電子計算機、電算機
250625-進項三聯式收銀機統一發票(…)三聯式收銀機、POS 三聯式
250725-進項一般稅額計算之電子發票(…)一般稅額電子發票、B2B 電子發票

完整映射表(含備註):docs/samples/ap-invCatCode-erp-mapping.csv

虛擬碼(ERP 對照邏輯):

若 docFormatCode = "21":
  若 憑證類型 含「電子計算機」或「電算機」→ invCatCode = "05"
  否若 含「三聯式」→ invCatCode = "01"
若 docFormatCode = "25":
  若 憑證類型 含「三聯式收銀機」或「收銀機(三聯)」→ invCatCode = "06"
  否若 含「電子發票」或「一般稅額」→ invCatCode = "07"
否則 → 改傳 docFormatName 或 lookup internal id

JSON 範例(格式 25):

{
  "docFormatCode": "25",
  "invCatCode": "07",
  "docDate": "2026/08/01",
  "docPeriod": "11508",
  "filingPeriod": "11508",
  "deductionCode": "1",
  "invoiceNo": "CA12345680",
  "buyerTaxId": "24536806",
  "sellerTaxId": "24536806",
  "taxType": "1",
  "salesAmount": 1000,
  "taxAmount": 50,
  "totalAmount": 1050,
  "fileBizTax": true
}
條件必填:哪一欄必填、禁填、擇一,以及稅額、字軌、期別,見 進項憑證檢核規則。上線前仍請用 options.validateOnly: true 對真實樣本試跑。

5.2 範例:只寫進項

{
  "requestId": "a1b2c3d4-e5f6-4789-a012-3456789abcde",
  "action": "apInvoiceOnly",
  "apInvoices": [
    {
      "docFormatCode": "21",
      "invCatCode": "01",
      "docDate": "2026/08/01",
      "docPeriod": "11508",
      "filingPeriod": "11508",
      "deductionCode": "1",
      "invoiceNo": "CA12345678",
      "buyerTaxId": "24536806",
      "sellerTaxId": "24536806",
      "taxType": "1",
      "salesAmount": 1000,
      "taxAmount": 50,
      "totalAmount": 1050,
      "fileBizTax": true
    }
  ]
}

成功回應示例:

{
  "success": true,
  "returnCode": "0000",
  "returnMessage": "OK",
  "action": "apInvoiceOnly",
  "validateOnly": false,
  "requestId": "a1b2c3d4-e5f6-4789-a012-3456789abcde",
  "results": [
    {
      "index": 0,
      "id": "1001",
      "invoiceNo": "CA12345678",
      "clientRef": "inv-001"
    }
  ]
}

6. 交易物件(transaction)

{
  "id": "456",
  "type": "vendorbill",
  "fields": {
    "entity": "123",
    "subsidiary": "1",
    "account": "220",
    "memo": "from external system"
  },
  "expenseLines": [
    { "account": "610", "amount": 1050 }
  ],
  "itemLines": []
}
欄位必填說明
id選填既有交易 internal id;有值則不新建(與 purchaseOrderId 互斥)
type條件必填新建時必填(見 §2.1);僅引用既有 id 時可省略
purchaseOrderId選填僅 vendorbill:從既有 Purchase Order transform 建立 VB(見 §6.2);不可與 id 同時出現
fields選填表頭欄位 → NetSuite field id → value(無白名單,見 §6.0)。實際 NetSuite 表單必填依客戶設定
expenseLines選填expense 子清單列(欄位同樣透傳)
itemLines條件必填一般選填;有 purchaseOrderId 時必填非空(見 §6.2)
apInvoices條件必填僅 transactionWithApInvoices:每筆交易內必填非空陣列
clientRef選填字串 1–64;回應原樣回傳

fields/行項目在 NetSuite 端的必填與合法值依客戶設定而定(廠商/科目/子公司等請向客戶索取對照表)。

6.0 客製化欄位(允許透傳)

現階段設計允許透過 API 寫入 Vendor Bill/Expense Report/Vendor Credit/Vendor Prepayment 的客製欄位。

  • transaction.fields 的 key 會直接作為 NetSuite 表頭 fieldId 呼叫 setValue(例如 custbody_xxx)。
  • expenseLines/itemLines 的 key 會直接作為子清單 fieldId 呼叫 setCurrentSublistValue(例如 custcol_yyy)。
  • Payload 契約沒有欄位白名單;PCE 不會驗證這些交易/客製欄內容,成敗由 NetSuite 欄位設定、表單、權限與值型別決定。
{
  "requestId": "a1b2c3d4-e5f6-4789-a012-3456789abcde",
  "action": "transactionOnly",
  "transaction": {
    "type": "vendorbill",
    "fields": {
      "entity": "123",
      "subsidiary": "1",
      "memo": "AP Write",
      "custbody_xxx": "自訂表頭值"
    },
    "expenseLines": [
      {
        "account": "610",
        "amount": 1050,
        "custcol_yyy": "自訂行值"
      }
    ]
  }
}

注意:

  1. Field ID 必須正確,且該交易類型/表單上確實有該欄。
  2. 值型別須符合欄位(select 傳 internal id、日期格式等依客戶環境)。
  3. Integration/Role 需具備寫入該欄的權限。
  4. 標準欄有寫入順序偏好(entity/subsidiary 等較早;account/payment 最後)。客製欄通常排在多數標準欄之後;若客製欄依賴 sourcing,請與客戶一併驗證。

6.1 範例:只建交易

{
  "requestId": "a1b2c3d4-e5f6-4789-a012-3456789abcde",
  "action": "transactionOnly",
  "transaction": {
    "type": "vendorbill",
    "fields": {
      "entity": "123",
      "subsidiary": "1",
      "account": "220",
      "memo": "AP Write"
    },
    "expenseLines": [
      { "account": "610", "amount": 1050 }
    ]
  }
}

6.2 從 Purchase Order 建立 Vendor Bill

當 type 為 vendorbill 且帶 purchaseOrderId(PO 內部 id)時,API 會以 NetSuite transform(PO → Vendor Bill)建立帳單,並依 request 的 itemLines 覆寫數量(支援部分開帳)。

規則:

項目說明
適用僅 vendorbill;其他 type 帶 purchaseOrderId → PURCHASE_ORDER_NOT_ALLOWED
與 id不可同時出現 → PURCHASE_ORDER_WITH_EXISTING_ID
itemLines必填非空陣列;每筆必有 orderline(或別名 line)與 quantity(≥0 數字)
數量以 request 的 quantity 為準;未出現在 request 的 PO 行會設為 quantity=0(不開帳)
找不到行request 的 orderline 在 transform 後的 VB 上不存在 → PO_ORDERLINE_NOT_FOUND
其他欄fields/itemLines 其餘 key 仍可透傳(如 rate、custcol_*);可另帶 expenseLines 追加費用列

itemLines[](有 purchaseOrderId 時):

欄位必填說明
orderline(或 line)必填對應 PO item 子清單行號
quantity必填≥0 數字;以此覆寫開帳數量
其餘 key(如 rate、custcol_*)選填透傳覆寫;quantity 仍以 request 為準
{
  "requestId": "a1b2c3d4-e5f6-4789-a012-3456789abcde",
  "action": "transactionOnly",
  "transaction": {
    "type": "vendorbill",
    "purchaseOrderId": "12345",
    "fields": {
      "memo": "bill from PO"
    },
    "itemLines": [
      { "orderline": "1", "quantity": 2 },
      { "orderline": "3", "quantity": 1, "rate": 100 }
    ]
  }
}

成功時 results[] 會含 transactionId、transactionCreated: true,以及原樣回傳的 purchaseOrderId。

6.3 範例:交易+多筆進項

{
  "requestId": "a1b2c3d4-e5f6-4789-a012-3456789abcde",
  "action": "transactionWithApInvoices",
  "transaction": {
    "clientRef": "vb-001",
    "type": "vendorbill",
    "fields": {
      "entity": "123",
      "subsidiary": "1",
      "account": "220"
    },
    "expenseLines": [
      { "account": "610", "amount": 2100 }
    ],
    "apInvoices": [
      {
        "clientRef": "inv-001",
        "docFormatCode": "21",
        "invCatCode": "01",
        "docDate": "2026/08/01",
        "docPeriod": "11508",
        "filingPeriod": "11508",
        "deductionCode": "1",
        "invoiceNo": "CA12345678",
        "buyerTaxId": "24536806",
        "sellerTaxId": "24536806",
        "taxType": "1",
        "salesAmount": 1000,
        "taxAmount": 50,
        "totalAmount": 1050,
        "fileBizTax": true
      },
      {
        "clientRef": "inv-002",
        "docFormatCode": "21",
        "invCatCode": "05",
        "docDate": "2026/08/02",
        "docPeriod": "11508",
        "filingPeriod": "11508",
        "deductionCode": "1",
        "invoiceNo": "CA12345679",
        "buyerTaxId": "24536806",
        "sellerTaxId": "24536806",
        "taxType": "1",
        "salesAmount": 1000,
        "taxAmount": 50,
        "totalAmount": 1050,
        "fileBizTax": true
      }
    ]
  },
  "options": {
    "validateOnly": false
  }
}

成功回應示例:

{
  "success": true,
  "action": "transactionWithApInvoices",
  "requestId": "a1b2c3d4-e5f6-4789-a012-3456789abcde",
  "results": [
    {
      "index": 0,
      "clientRef": "vb-001",
      "transactionId": "789",
      "transactionType": "vendorbill",
      "transactionCreated": true,
      "apInvoices": [
        {
          "index": 0,
          "id": "1001",
          "invoiceNo": "CA12345678",
          "clientRef": "inv-001"
        },
        {
          "index": 1,
          "id": "1002",
          "invoiceNo": "CA12345679",
          "clientRef": "inv-002"
        }
      ]
    }
  ]
}

掛到既有交易:

{
  "requestId": "a1b2c3d4-e5f6-4789-a012-3456789abcde",
  "action": "transactionWithApInvoices",
  "transaction": {
    "id": "789",
    "apInvoices": [ { "...": "..." } ]
  }
}

7. CSV 匯入進項(Suitelet)

除 RESTlet 外,亦可在 NetSuite 內以 Suitelet 上傳 CSV 建立進項(內部仍呼叫同一支 AP Write:action=apInvoiceOnly)。

項目說明
Scriptcustomscript_pce_sl_ap_csv_import/customdeploy_pce_sl_ap_csv_import
開啟Customization → Scripting → Script Deployments → PCE SL AP CSV Import
編碼Excel 另存 CSV(建議「CSV UTF-8」);若中文亂碼請確認為 UTF-8
上限單次 100 列資料(不含表頭)
欄位標頭與 §5.1 API 別名相同(大小寫不敏感);亦可 custrecord_pce_ap_*
掛交易可選欄 transaction 或 transactionId=既有交易 internal id
驗證勾選「只驗證不寫入」=options.validateOnly: true
對帳每次匯入產生 requestId(csv-…),並寫入 PCE AP Write 呼叫紀錄
POST 後導向PRG:POST 完成後 https.redirect 至 GET ?action=result&writeLogId={id};重新整理不會重送 CSV/API
結果還原GET 結果頁自 PCE AP Write 呼叫紀錄 讀取 response JSON,並自 _csvUi 快照還原表頭/validateOnly/列數(PCE_LIB_AP_CsvImportReplay.js)
結果畫面本頁 Bootstrap 自訂介面:中文總結(成功/失敗筆數);失敗列優先並列出中文原因;成功列可開進項紀錄
失敗重試有失敗時可 下載失敗列 CSV(表頭與原檔相同),修正後再上傳
範本下載頁面提供 下載 CSV 範本(action=template)與 下載欄位說明(action=guide)

範本:docs/samples/ap-invoice-import-sample.csv(含 21/25 各 invCatCode 範例列)/欄位說明:docs/samples/ap-invoice-import-field-guide.csv/ERP 映射:docs/samples/ap-invCatCode-erp-mapping.csv

與原生 NetSuite CSV Import 不同:此 Suitelet 支援 API 別名/業務代碼、逐列結果、呼叫紀錄與 partial success,契約與 RESTlet 一致。技術欄位(returnCode、完整 JSON)摺在「進階資訊」。

8. 僅驗證(validateOnly)

{
  "requestId": "a1b2c3d4-e5f6-4789-a012-3456789abcde",
  "action": "apInvoiceOnly",
  "options": { "validateOnly": true },
  "apInvoices": [ { "...": "..." } ]
}
actionvalidateOnly 行為
apInvoiceOnly跑進項驗證,不 create
transactionWithApInvoices驗證進項(若有 transaction.id 會帶入關聯);不 create 交易/發票
transactionOnly只確認 JSON 結構合法,不驗證交易內容、不存檔

上線前請務必先用 validateOnly: true 對真實樣本資料試跑。

9. 錯誤碼一覽(介接端)

8.1 returnCode(建議程式判斷用)

returnCode語意success
0000–0099成功/部分成功(見 §4.2;0004=partial)true(0004 時為 false)
1000–1999Request/Payload shapefalse
2000–2999進項業務驗證false
3000–3999Lookup/主檔解析false
4000–4999NetSuite 執行期(權限、save 失敗等)false
9000–9999未預期錯誤false

8.2 error.code 對照

codereturnCode意涵建議處理
INVALID_BODY1001body 不是 JSON 物件檢查序列化
INVALID_ACTION1002action 拼錯使用三種合法值之一
REQUEST_ID_REQUIRED1003缺少 requestId補上冪等鍵(建議 UUID v4)
REQUEST_ID_INVALID1004requestId 格式不合8–64 字元,僅 A–Z a–z 0–9 - _
REQUEST_ID_PAYLOAD_MISMATCH1005同 requestId 但 payload 不同換新 requestId,或重送完全相同的 body
AP_INVOICES_REQUIRED1006缺少進項陣列apInvoiceOnly 補 top-level apInvoices;transactionWithApInvoices 補每筆 transaction.apInvoices
AP_INVOICES_TOP_LEVEL_NOT_ALLOWED1008transactionWithApInvoices 不可用 top-level 發票欄位改為巢狀在每個 transaction 內
CLIENT_REF_INVALID1013clientRef 格式不合使用 1–64 字元字串
AP_INVOICES_NOT_ALLOWED1007transactionOnly 不應帶發票(top-level 或巢狀)改 action 或拿掉陣列
TRANSACTION_REQUIRED1009缺少交易補 id 或 type
TRANSACTION_NOT_ALLOWED1010apInvoiceOnly 不可新建交易改用 transactionWithApInvoices
INVALID_TRANSACTION_TYPE1011type 不支援改為 §2.1 列表
TRANSACTION_LIMIT_EXCEEDED1012一次超過 10 筆交易分批呼叫
PCE_METHOD_NOT_ALLOWED1014不支援的 HTTP 方法(如 GET)改用 POST
PURCHASE_ORDER_NOT_ALLOWED1015非 vendorbill 卻帶 purchaseOrderId改 type 或拿掉欄位
PURCHASE_ORDER_WITH_EXISTING_ID1016同時帶 id 與 purchaseOrderId擇一:引用既有 VB,或從 PO 新建
PO_ITEM_LINES_REQUIRED1017從 PO 建立時缺 itemLines補上含 orderline/quantity 的列
PO_ORDERLINE_REQUIRED1018item 列缺 orderline/line對應 PO 行號
PO_QUANTITY_REQUIRED1019item 列缺合法 quantity填 ≥0 數字
PCE_AP_INVOICE_VALIDATION_ERROR2001進項業務規則失敗讀 results[i].error/message/details 修正欄位
BATCH_FAILED2100批次內全部項目失敗逐筆看 results[]
PARTIAL_SUCCESS0004部分成功依 results[] 保留成功項,失敗項換新 requestId 重送
PCE_LOOKUP_RESOLVE_ERROR3001代碼無法對應主檔向客戶確認 lookup/代碼表
PCE_INVALID_TRANSACTION_TYPE3002執行期 type 無法對應 record改為 §2.1 列表
SKIPPED_PARENT_FAILED4001父交易失敗,巢狀發票未處理先修好交易再重送
PO_ORDERLINE_NOT_FOUND4002request 的 orderline 不在 PO/transform 結果核對 PO 行號
PO_TRANSFORM_FAILED4003PO→VB transform 失敗查 PO 狀態/權限/可開帳量
其他 NetSuite 錯誤4000權限、必填、系統錯誤聯絡客戶 NetSuite 管理員
UNEXPECTED_ERROR9999未預期例外附完整 response 聯絡技術窗口

HTTP 層面的 401/403 屬 OAuth 2.0 token/角色問題,與 JSON returnCode/success: false 不同。

10. 呼叫範例(概念)

# 1) 取得 access token(M2M;client_assertion 為已簽署 JWT)
curl -X POST "$TOKEN_URL" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer" \
  -d "client_assertion=$CLIENT_ASSERTION"

# 2) GET is not allowed (expect PCE_METHOD_NOT_ALLOWED)
curl -X GET "$RESTLET_URL" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json"

# 3) POST write
curl -X POST "$RESTLET_URL" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d @payload.json

JWT 產生可參考 docs/postman/generate-client-assertion.js。access token 有時效,過期需重新向 token endpoint 換發。

11. 介接注意事項

  1. 一筆交易可對多筆進項;請用 transactionWithApInvoices 一次送齊,或先建交易再用 transaction.id 分批掛發票。
  2. 每次邏輯寫入必須帶唯一 requestId(建議 UUID v4);網路逾時重試請重用同一把,避免重複建單。
  3. 發票號碼重複會被驗證擋下。比對正式 PCE 進項資料(同一憑證格式)。若帳上有 API進項資料,待審與轉入失敗也列入;退回與已轉入不列入。公版套件不含 API進項資料。
  4. 目前僅支援新建進項,不支援透過本 API 更新/刪除既有進項。
  5. 統編、字軌、申報期、稅額等規則見 進項憑證檢核規則。字軌表依帳上財政部字軌主檔,測試帳與正式帳可能不同。
  6. 成功回應以 results[] 對應 request(含 index/可選 clientRef/invoiceNo/transactionId/apInvoices[].id);請由貴系統保存,作為對帳與除錯依據。
  7. 若同時需要 UI 與 API 寫入,兩邊共用同一套驗證規則,行為應一致。

12. 聯絡與變更

  • 介面變更(action、必填、錯誤碼)應由客戶專案組提前書面通知。
  • 技術爭議或驗證規則疑問,請透過客戶指定之顧問/技術窗口,並附上:Account ID、request(可遮罩敏感資料)、完整 error JSON、時間(含時區)。

文件版本:對應 SuiteApp com.netsuite.pceguitw — PCE RL AP Write(customscript_pce_rl_ap_write)。