跳轉到

平台 API 慣例

本頁定義 NextPDF SaaS Foundation 的 API 設計標準。所有基於 NextPDF 構建的 SaaS 平台應遵循這些慣例,確保 API 的一致性、可預測性與安全性。


認證與授權(Auth / RBAC)

認證方式

所有 API 請求必須包含以下其中一種認證標頭:

# Bearer Token(API Key)
Authorization: Bearer npro_sk_live_abc123def456...

# Bearer JWT(短效)
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

API Key 格式規範

格式:{prefix}_{environment}_{random64chars}
範例:
  npro_sk_live_8f4a2b1c...(生產環境,Secret Key)
  npro_sk_test_7e3d9a0f...(測試環境)
  npro_pk_live_1a2b3c4d...(公開金鑰,用於前端)

前綴說明:
  npro_sk_live   生產環境 Secret Key(服務端)
  npro_sk_test   測試環境 Secret Key
  npro_pk_live   生產環境 Publishable Key(客戶端可見)
  npro_wh_live   Webhook 簽名密鑰

RBAC 角色定義

角色 說明 可執行操作
owner 帳號擁有者 所有操作 + 帳單管理 + 成員管理
admin 管理員 所有操作(除帳單)+ 成員管理
developer 開發者 API 操作 + 設定讀取
analyst 分析師 唯讀(文件、報告、指標)
viewer 觀看者 唯讀(指定資源)
service_account 服務帳號 依授予的特定 Scopes

權限 Scope 設計

格式:{resource}:{action}

範例:
  pdf:generate      生成 PDF
  pdf:parse         解析 PDF
  pdf:sign          數位簽章
  pdf:delete        刪除 PDF
  rag:embed         向量索引
  rag:search        語意搜尋
  members:read      讀取成員列表
  members:write     管理成員
  billing:read      查看帳單
  audit:read        查看審計日誌
  settings:write    修改平台設定

RBAC 請求範例

POST /v1/pdf/generate HTTP/1.1
Authorization: Bearer npro_sk_live_...
X-Organization-ID: org-abc123
Content-Type: application/json

# 系統自動驗證:
# 1. Token 有效性
# 2. Token 對應的 tenant_id
# 3. 角色是否具有 pdf:generate 權限
# 4. 是否超過 plan 的使用配額

速率限制

標頭規範

每個 API 回應均包含速率限制標頭:

HTTP/1.1 200 OK
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1740000060
X-RateLimit-Policy: 60;w=60;comment="per-minute"

超過限制回應

HTTP/1.1 429 Too Many Requests
Content-Type: application/problem+json
Retry-After: 30
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1740000090

{
  "type": "https://docs.yourpdf.com/errors/rate-limit-exceeded",
  "title": "Rate Limit Exceeded",
  "status": 429,
  "detail": "You have exceeded 60 requests per minute for operation 'pdf.generate'.",
  "instance": "/v1/pdf/generate",
  "retry_after": 30,
  "limit": 60,
  "window": "1m"
}

各方案速率限制

方案 pdf.generate pdf.parse rag.embed rag.search
Free 10/分鐘 10/分鐘
Pro 300/分鐘 300/分鐘 100/小時 1,000/小時
Enterprise 自定義 自定義 自定義 自定義

冪等性

所有具副作用的 API 端點(POSTDELETE)支援冪等性保護。

使用方式

POST /v1/pdf/generate HTTP/1.1
Authorization: Bearer npro_sk_live_...
Idempotency-Key: idem_550e8400e29b41d4a716446655440000
Content-Type: application/json

{"html": "<h1>Report</h1>"}

規範

  1. Idempotency-Key 必須是唯一字串,建議使用 UUID v4
  2. 相同的 Key 在 24 小時內重複請求將返回快取回應
  3. Key 不可重複使用於不同的請求體
  4. 快取命中時,回應標頭包含 X-Idempotency-Cache: hit
  5. 冪等性不適用於 GETHEAD 請求(這些操作天然冪等)

最佳實踐

// 基於業務邏輯生成確定性 Key(推薦)
$key = hash('sha256', "tenant:{$tenantId}:generate:{$documentId}:attempt:1");

// 而非每次隨機生成(不推薦,失去冪等性保護)
$key = Uuid::uuid4(); // 重試時會是新 Key

Webhook

事件推送設計

Webhook 以 HTTPS POST 推送事件,保證至少一次(At-Least-Once)交付。

請求格式

POST https://your-endpoint.com/webhooks/nextpdf HTTP/1.1
Content-Type: application/json
X-NextPDF-Webhook-ID: wh_550e8400e29b41d4
X-NextPDF-Webhook-Timestamp: 1740000000
X-NextPDF-Webhook-Signature: v1=8f4a2b1c...
X-NextPDF-Webhook-Version: 1

{
  "id": "evt_abc123",
  "type": "pdf.generated",
  "created_at": "2026-03-04T10:30:00Z",
  "tenant_id": "tenant-abc123",
  "data": {
    "document_id": "doc-001",
    "pages": 10,
    "size_bytes": 524288,
    "duration_ms": 1234
  }
}

簽名驗證

function verifyWebhookSignature(
    string $payload,
    string $timestamp,
    string $signature,
    string $secret,
): bool {
    // 防重放攻擊:拒絕超過 5 分鐘的請求
    if (abs(time() - (int)$timestamp) > 300) {
        return false;
    }

    $expectedSignature = 'v1=' . hash_hmac(
        'sha256',
        "{$timestamp}.{$payload}",
        $secret
    );

    return hash_equals($expectedSignature, $signature);
}

重試策略

重試次數 等待時間
第 1 次 立即
第 2 次 5 分鐘後
第 3 次 30 分鐘後
第 4 次 2 小時後
第 5 次 12 小時後
放棄 72 小時後

事件類型清單

事件類型 說明
pdf.generated PDF 生成完成
pdf.generation_failed PDF 生成失敗
pdf.signed 數位簽章完成
batch.completed 批次任務完成
rag.index_completed 向量索引完成
tenant.quota_warning 配額使用達 80%
tenant.quota_exceeded 配額已用盡
data_purge.completed GDPR 資料清除完成

審計事件

所有操作均產生不可變的審計事件(詳見 合規套件)。

查詢審計日誌

GET /v1/audit-log HTTP/1.1
Authorization: Bearer npro_sk_live_...

# 查詢參數
?tenant_id=tenant-abc123           # 必填(admin 以上才能跨租戶查詢)
&operation=pdf.sign                # 可選:按操作類型過濾
&user_id=user-456                  # 可選:按使用者過濾
&from=2026-01-01T00:00:00Z         # 可選:起始時間(ISO 8601)
&to=2026-03-31T23:59:59Z           # 可選:結束時間
&cursor=evt_abc123                 # 可選:游標分頁
&per_page=50                       # 可選:每頁筆數(max: 100)

RFC 9457 錯誤格式

所有 API 錯誤均遵循 RFC 9457(Problem Details for HTTP APIs) 格式。

標準錯誤格式

{
  "type": "https://docs.yourpdf.com/errors/{error-slug}",
  "title": "Human-readable error title",
  "status": 422,
  "detail": "Detailed explanation of what went wrong.",
  "instance": "/v1/pdf/generate/req-abc123",
  "request_id": "550e8400-e29b-41d4-a716-446655440000",
  "documentation_url": "https://docs.yourpdf.com/errors/{error-slug}"
}

標準錯誤代碼

HTTP 狀態 錯誤 Slug 說明
400 bad-request 請求格式錯誤
401 authentication-required 未提供認證憑據
401 invalid-credentials 認證失敗
403 insufficient-permissions 無操作權限
404 resource-not-found 資源不存在
409 conflict 資源衝突(如重複建立)
413 payload-too-large 請求體超過限制
422 invalid-pdf PDF 格式無效
422 malicious-content 偵測到惡意內容
429 rate-limit-exceeded 超過速率限制
503 service-unavailable 服務暫時不可用

驗證錯誤格式(含欄位詳情)

{
  "type": "https://docs.yourpdf.com/errors/validation-error",
  "title": "Validation Error",
  "status": 422,
  "detail": "The request contains invalid fields.",
  "instance": "/v1/pdf/generate",
  "errors": [
    {
      "field": "options.page_size",
      "message": "Must be one of: A4, A3, Letter, Legal",
      "value": "A0",
      "code": "invalid_enum_value"
    },
    {
      "field": "html",
      "message": "Cannot be empty",
      "code": "required"
    }
  ]
}

資料生命週期

資源狀態轉換

pending → processing → completed
                     ↘ failed → archived
completed → archived → deleted

軟刪除設計

所有資源採用軟刪除,提供 30 天的誤刪恢復視窗:

# 刪除(軟刪除,30 天內可恢復)
DELETE /v1/documents/{id}
→ 202 Accepted, {deleted_at: "...", purge_at: "...+30days"}

# 恢復(30 天內)
POST /v1/documents/{id}/restore
→ 200 OK

# 永久刪除(立即,30 天後自動觸發)
DELETE /v1/documents/{id}?permanent=true
→ 202 Accepted

分頁

所有列表端點使用游標分頁(Cursor-Based Pagination),不使用頁碼分頁(避免大資料集的 OFFSET 效能問題):

回應格式

{
  "data": [...],
  "pagination": {
    "has_more": true,
    "next_cursor": "eyJpZCI6ImRvYy0wMDUwIiwiY3JlYXRlZF9hdCI6MTc0MDAwMDAwMH0",
    "prev_cursor": "eyJpZCI6ImRvYy0wMDAxIiwiY3JlYXRlZF9hdCI6MTczOTk5OTkwMH0",
    "per_page": 20,
    "total_estimate": 342
  },
  "meta": {
    "request_id": "550e8400-...",
    "duration_ms": 45
  }
}

分頁請求

GET /v1/documents?per_page=20&cursor={next_cursor}&sort=created_at&order=desc

API 版本控制

URL 路徑版本控制:/v1/、/v2/

版本生命週期:
  - 新版本釋出後,舊版本至少維護 12 個月
  - 棄用通知:棄用標頭 + 電子郵件通知
  - 棄用標頭:Deprecation: "2027-03-01"; Sunset: "2027-09-01"

參見