Skip to Content
API 參考公開回呼

公開回呼

先為指定資料表鑄造回呼憑證,再以只顯示一次的密鑰送出外部新增或更新;整合結束後應撤銷該憑證。

請求的 idempotency_key 會記錄在與資料列一起寫入的 durable receipt:在 receipt 視窗(預設 24 小時)內重複送出,會 replay 原本的結果並設 replayed: true;相同 key 搭配不同 body 則是 409 idempotency_key_reuse(詳情)。

同一份憑證也能讀取目標資料表的可寫欄位,讓公開表單自行產生欄位,而不必寫死一組會隨版主改名而失效的名稱。

POST
路由範本/public/module/custom_tables/callback/{token_id}
用途

讓外部系統使用綁定單一資料表的回呼憑證新增或更新資料列。

適用時機

ERP、表單或其他無 TeamSync 帳號的系統需要把事件寫入指定資料表時使用。

實際掛載路徑
  • 完整路由/public/module/custom_tables/callback/{token_id}

範圍

範圍是否提供驗證與權限
完整路由可使用callback token (minted)

參數

欄位位置型別必填說明
token_idpathuuid是鑄造回呼憑證時取得的 token_id;它是 URL 憑證的一半。

請求結構

CallbackRequest

OpenAPI 快照中沒有此模型的頂層元件欄位。

回應結構

CallbackResponse
欄位型別必填說明
okboolean否Always true on a 2xx response (the submission was accepted)
op"create" | "update"是The operation the request asked for
process_idstring | null否ReviewProcess now holding the write (held_for_approval / already_pending)
record_idstring | null否Id of the created/updated record; null when status is held_for_approval or already_pending (no row exists until a reviewer approves)
replayedboolean否True when idempotency_key matched a previous accepted request — no new write or staged change happened. Created/updated and held/already-pending outcomes are replayable for 24 hours.
rule_labelstring | null否Human label of the require_approval rule that held the write — safe to show the submitter (held_for_approval only)
staged_change_idstring | null否Staged change holding the write (held_for_approval / already_pending)
status"created" | "updated" | "held_for_approval" | "already_pending"是Outcome discriminator. created/updated: the write landed and record_id is set. held_for_approval: a require_approval rule matched — the write is staged and now awaits review (process_id/staged_change_id set, record_id null); this is a terminal success, do NOT resubmit. already_pending: an identical submission (same approval match column value) or the target record is already held by the returned process — no second change was staged.

範例

以具冪等鍵的回呼新增訂單

請求
{
  "pathParams": {
    "token_id": "11111111-1111-4111-8111-111111111111"
  },
  "body": {
    "op": "create",
    "data": {
      "訂單編號": "ORD-1042",
      "數量": 3
    },
    "idempotency_key": "event-1042"
  }
}
回應200
{
  "ok": true,
  "op": "create",
  "status": "created",
  "record_id": "22222222-2222-4222-8222-222222222222",
  "process_id": null,
  "staged_change_id": null,
  "rule_label": null,
  "replayed": false
}

在 receipt 視窗內重複送出同一個帶 key 的建立:會回傳原本的結果與 replayed=true,且不會寫入第二列

請求
{
  "pathParams": {
    "token_id": "11111111-1111-4111-8111-111111111111"
  },
  "body": {
    "op": "create",
    "data": {
      "訂單編號": "ORD-1042",
      "數量": 3
    },
    "idempotency_key": "event-1042"
  }
}
回應200
{
  "ok": true,
  "op": "create",
  "status": "created",
  "record_id": "22222222-2222-4222-8222-222222222222",
  "process_id": null,
  "staged_change_id": null,
  "rule_label": null,
  "replayed": true
}

被暫存待核准的 update(2xx,尚未落地)

請求
{
  "pathParams": {
    "token_id": "11111111-1111-4111-8111-111111111111"
  },
  "body": {
    "op": "update",
    "record_id": "22222222-2222-4222-8222-222222222222",
    "data": {
      "數量": 5
    },
    "idempotency_key": "event-1043"
  }
}
回應200
{
  "ok": true,
  "op": "update",
  "status": "held_for_approval",
  "record_id": null,
  "process_id": "33333333-3333-4333-8333-333333333333",
  "staged_change_id": "44444444-4444-4444-8444-444444444444",
  "rule_label": "大量訂單變更",
  "replayed": false
}

錯誤

驗證錯誤範例列出識別欄位;部署中的驗證器也可能回傳 input 與 ctx。錯誤訊息 URL 的版本由建置決定,因此使用 pydantic-version 佔位符。

狀態發生條件錯誤本文
403資料表的 `write_policy` 是 `commands_only`:任何不在 Command 之內的主體所做的資料列寫入,都會在任何東西被暫存、排入佇列或 commit 之前,以 typed 的 `governed_context_required` 被拒絕(不會產生版本、history、receipt、token 或 Review process)。`operation` 指出是哪種寫入,若該通道有名稱則以 `surface` 指出;請改用被允許寫入該資料表的 Command。讀取不受影響。
{
  "detail": {
    "error": "governed_context_required",
    "message": "This table accepts record writes only through Commands (write_policy: commands_only). Run a Command that is allowed to write it instead.",
    "table_id": "22222222-2222-4222-8222-222222222222",
    "operation": "create",
    "surface": "callback"
  }
}
409`date_interval_exclusion` 規則拒絕此次寫入:`date_interval_exclusion_invalid_period`(建立時省略 end key、結束日為空字串或不晚於起始日,或 scope link 沒有恰好一個目標)、`date_interval_exclusion_overlap`(另一筆 live 資料列涵蓋了這段期間的一部分),或 `date_interval_exclusion_retry`(寫入等待期間資料表的規則被改變;沒有寫入任何東西,請重送)。body 是固定訊息,絕不會指出資料列、日期或 scope 值。
{
  "detail": {
    "error": "date_interval_exclusion_overlap",
    "message": "Date period overlaps another period in this partition."
  }
}
409排除送審者(`exclude_requester`)之後,某個必要的審批 gate 沒有任何可核准者。送出會在任何 review process 出現之前就被拒絕;`gate_order` 指出該 gate。對於不管理每一張被引用資料表的 `authority: definition` command 呼叫者,只會回傳安全的 key,所以沒有 `gate_order`。
{
  "detail": {
    "error": "no_eligible_approver",
    "message": "Excluding the requester leaves a required review gate with no eligible approver",
    "gate_order": 1
  }
}
409這筆寫入需要排除送審者,但呼叫的主體沒有已驗證的人類身分(例如 service account),無法歸屬。不會暫存任何東西。
{
  "detail": {
    "error": "requester_unattributable",
    "message": "This review requires the requester to be excluded, but the submitting principal has no verified human identity"
  }
}
400請求格式、允許操作、資料規則或欄位內容不合法。
{
  "detail": "op 'update' requires record_id"
}
400Body 的 `op` 不在 token 的 `allowed_ops` 內(用只能 create 的 token 做 update)。
{
  "detail": "op 'update' is not allowed by this token (allowed: create)"
}
400Update 指定的欄位 key 既不是綁定資料表已知的顯示名稱,也不是內部 `col_<hex>` 鍵。(Create 則會靜默略過未知的 key。)
{
  "detail": "Column '庫存量' does not exist in table schema"
}
403綁定的資料表帶有 enforcing 的 `channel` 規則,而 callback(沒有 acting chatroom)永遠無法滿足它;違反 invariant 會以同樣方式回 `scp_invariant_violation`。Minting 使用者無法讀取的 link 目標是 `404 linked record not found`,不是 403。
{
  "detail": {
    "error": "scp_out_of_scope",
    "message": "channel-scoped tables are not writable from callback",
    "table_id": "55555555-5555-4555-8555-555555555555",
    "rule_id": "rule_3f9a1c2b7d4e"
  }
}
404token 不存在、已撤銷、已過期,或所提供的密鑰驗證失敗。
{
  "detail": "Not found"
}
404Update 目標不存在、在垃圾桶中,或屬於其他資料表。只有 `Not found` 才是 token/auth 的一致回應。
{
  "detail": "Record not found"
}
404綁定的資料表在垃圾桶中。資料表丟進垃圾桶時會保留它的 token(永久清除才會刪除),查找垃圾桶中的資料表會回這個 body,而不是統一的 `Not found`;還原資料表即可恢復。
{
  "detail": "CustomTable Not found"
}
409使用這個 idempotency_key 的第一個請求仍在執行,或它的 receipt 尚未定案;稍候後用同一個 key 重試。
{
  "detail": "a request with this idempotency_key is in progress"
}
409在 receipt 視窗內,相同的 idempotency_key 搭配不同的 op、record_id 或 data。不寫入任何東西;一個事件請用一個 key。
{
  "detail": {
    "error": "idempotency_key_reuse"
  }
}
409寫入在 `unique_tuple` 規則下碰撞(body 只點名約束與欄位,不含任何值;呼叫者讀不到某個 component 時,只列出讀得到的欄位、以不透明的 `rule_<hex>` id 稱呼規則,並加上 `message`)。舊式 `unique` 衝突只有在該列與整個鍵都讀得到時才帶 `conflicting_record_id` 與 `key_tuple`,違反 `same_dimension_reference` 則回 `same_dimension_reference_violation`,`date_interval_exclusion` 拒絕則回 `date_interval_exclusion_invalid_period`、`date_interval_exclusion_overlap` 或 `date_interval_exclusion_retry`。
{
  "detail": {
    "error": "unique_tuple_conflict",
    "constraint": "訂單編號不可重複",
    "columns": [
      "訂單編號"
    ]
  }
}
413原始請求本文超過 64 KB。
{
  "detail": "body exceeds 65536 bytes"
}
423資料表正被遷移鎖定。
{
  "detail": "Table is currently locked for a migration"
}
429單一 token 超過每分鐘 60 次,或待覆核暫存變更已達上限。
{
  "detail": "rate limit exceeded (60/min per token)"
}
429待核准的暫存額度已滿:這個 token 在該表已有 500 筆待審變更(`scope: "actor"`),或該表已有 50 筆待審的新增(`scope: "table"`、`limit: 50`)。請暫停 producer,等 reviewer 消化佇列。
{
  "detail": {
    "error": "staged_cap_exceeded",
    "scope": "actor",
    "limit": 500,
    "message": "form temporarily saturated — too many submissions from this form are awaiting approval; they clear as reviewers work the queue. Retry later; do not resubmit in a loop."
  }
}
GET
路由範本/public/module/custom_tables/callback/{token_id}/form-schema
用途

回傳目標資料表的顯示名稱與可寫欄位(名稱與型別),讓外部表單在送出回呼寫入前先自行產生欄位。

適用時機

當公開表單應該依資料表動態產生欄位,而不是寫死一組會隨版主改名而失效的欄位名稱時使用。

實際掛載路徑
  • 完整路由/public/module/custom_tables/callback/{token_id}/form-schema

範圍

範圍是否提供驗證與權限
完整路由可使用callback token (Bearer secret or HMAC signature — same credential as the write route)

參數

欄位位置型別必填說明
token_idpathuuid是回呼(寫入)token 的 token_id——與你送出寫入請求時使用的網址是同一半憑證。

回應結構

CallbackFormSchemaResponse
欄位型別必填說明
columnsPublicColumnInfo[]是Writable columns (name + type). Computed columns omitted.
table_namestring是Display name of the target table.

範例

依 token 的目標資料表產生表單

請求
{
  "pathParams": {
    "token_id": "11111111-1111-4111-8111-111111111111"
  }
}
回應200
{
  "table_name": "訂單回報",
  "columns": [
    {
      "name": "訂單編號",
      "type": "string"
    },
    {
      "name": "數量",
      "type": "integer"
    },
    {
      "name": "狀態",
      "type": "select"
    },
    {
      "name": "備註",
      "type": "text"
    },
    {
      "name": "回報時間",
      "type": "datetime"
    }
  ]
}

錯誤

驗證錯誤範例列出識別欄位;部署中的驗證器也可能回傳 input 與 ctx。錯誤訊息 URL 的版本由建置決定,因此使用 pydantic-version 佔位符。

狀態發生條件錯誤本文
404token 不存在、已撤銷、已過期,憑證驗證失敗,資料表已被永久清除(token 會一併刪除),或 sandbox run token 的使用者已不存在——這些都回傳完全相同的 404。綁定的資料表在垃圾桶中時則改回 `CustomTable Not found`。
{
  "detail": "Not found"
}
404綁定的資料表在垃圾桶中。資料表丟進垃圾桶時會保留它的 token(永久清除才會刪除),查找垃圾桶中的資料表會回這個 body,而不是統一的 `Not found`;還原資料表即可恢復。
{
  "detail": "CustomTable Not found"
}
Last updated on