Tham chiếu API
Danh mục đầy đủ các endpoint của API công khai, dựng từ tài liệu OpenAPI.
Submits the uploaded package as a version of its app.
The upload runs before the submission's transaction, so a refused submission still leaves the organization's own upload row, as `POST /app-packages` would have stored it. It writes no submission.
One of the organization's submissions.
Withdraws a version the organization published. New installs stop seeing it; installations that hold it keep it. Withdrawing twice answers the same.
The organization's deployments, waiting ones first.
Request the install or upgrade of an uploaded release. Install or upgrade is decided now from what the organization has; a release already installed answers `installed` at once and leaves a waiting deployment alone, and any other request supersedes the package's waiting one.
One deployment, with the release it deploys.
Approve a deployment: plan it again as the person approving, and install it when the plan is the one they were shown. The install is activated by a worker; read the deployment for where it is.
Withdraw a deployment still awaiting approval.
Plan a deployment as the person asking, with their answers over the stored ones. The answers are kept on the deployment and written into the setup that carries it, which is what is planned; nothing else is kept.
Turn an installed app's triggers on, all at once. Without `only`, every trigger that is off and whose feature is on; with it, exactly the keys it names. One trigger that cannot run refuses the whole arm and nothing is armed.
The objects an installed app may address, the values of its parameters, and the revision they were read at, as the app itself reads them.
Upload a sealed package. It is stored as a release of the organization once it verifies as intact and sealed, the platform supports it and lint finds nothing. No key or enrolment is needed: the admin's approval of the install is the gate.
Lint a package against this deployment, storing nothing. The answer is `200` whether or not there are problems; a body that is no package archive is refused.
List_app_objects
Upload_attachment
Get_attachment
Through an installed app, a file is told of only when the app may read every owner it has and it has one. A file a run produced or holds, and a file nobody owns, answer `404`.
Download_attachment
Through an installed app, a file is told of only when the app may read every owner it has and it has one. A file a run produced or holds, and a file nobody owns, answer `404`.
Get_caller
List_dashboards
Get_dashboard
Compute_dashboard
List_entities
Get_entity
Get_entity_create_form
The records of an entity that someone has open.
List_records
Create one record through the entity's configured create form. The submitted payload is validated against the form schema (defaults + computed applied, like the human-task submit path), then the command maps it onto entity fields and writes it via the standard create pipeline. The echoed record has sensitive fields redacted for readers no profile grants.
Launch_batch_run
Get_batch_run
List_batch_run_members
The resolved size of a filter — the bulk bar's “all matching filter” badge. Same authz / base-filter / sensitive-field discipline as `query`; returns only a number (no record bodies, so redaction is moot for the count itself, but filtering on an unreadable sensitive field is still rejected).
Query_records
Get_record
Change individual fields of one record, keyed by entity field key. Backs inline editing on the record page, where the detail layout is the editing surface — so unlike the form-driven PUT there is no form to map through, and the semantics are merge-patch rather than replace-the-bound-set.
Values are validated against a schema synthesized from the live entity (`entity_patch_schema`), which routes them through the same type/option/ format assertions a bound form gets. Authorization is the same three tiers as the PUT: coarse `entity.write`/`entity.read`, object-level `authorize_entity_mutation`, and the command's record-level `guard_record_mutate`.
Delete_record
Edit one record through the entity's configured edit form (bound-only). The submitted payload is validated against the form schema, then the command maps it onto entity fields and writes it via the standard CAS update pipeline (`record.updated` + formula/ref/key re-sync). Three-tier authorization: coarse `entity.write`/`entity.read`, object-level `authorize_entity_mutation`, and the command's record-level `guard_record_mutate`. The echoed record has sensitive fields redacted for readers no profile grants.
The record's comments, oldest first.
With no cursor the page holds the newest comments; `prev_cursor`, sent as `before`, reaches older ones. Each body is rendered for the caller.
Write a comment on the record.
Anyone who can read the record may comment while the entity takes comments and the record's are open. A person mentioned who cannot read the record is kept in the text, told nothing, and listed in `unnotified`.
Edit a comment: its text, its files, or both. Only its author edits it.
Delete a comment, and its files with it.
Its author deletes it, and so does anyone who may update the record.
Change items of one `list` field by item operations. Unlike a patch it carries no version token: the server locks the record, applies the ops to the list as it stands and writes under that lock, so two people changing different items both succeed. The write runs the patch pipeline: rules, stage gates, field access and events behave as for an inline edit.
The records that mention this record, newest mention first, one row each.
A source is listed only if the caller may read it: one the caller may not read leaves no row and no count. Where it mentions (its comments, or a field) lists only the fields the caller may read, and the author is named only to a caller who is told people's names. A source's comments are not listed while its entity takes no comments. A page can hold fewer than `limit` while `next_cursor` is set, when many of the next sources are not the caller's to read; the cursor is opaque and sealed. Through an installed app, a record that mentions is listed only while the ceiling lets the app read it, a field place only while the app may read that field, and a comment place whenever the entity takes comments and the app may read the source, and the author is named only while the package lists the `user` entity's `name`; otherwise `last_author` is null.
Say the caller has the record open.
Send every 20 seconds while it is open; the caller stops being a viewer 45 seconds after the last.
Say the caller has closed the record.
The caller stops being a viewer at once rather than 45 seconds after their last heartbeat. Leaving a record the caller is not viewing changes nothing.
Get_record_step
Through an installed app, the step's name and description are the workflow's static names and never text rendered from the run. Its form and the values stored under it are cut to the fields the ceiling lets the app read, it lists no signed documents, and a step whose draft, prefill, selection or agent calls cannot be tied to such a field is refused (`APP_CEILING_DENIED`) rather than returned raw. Files a run produced answer `404`.
Submit_record_step
Through an installed app, the returned panel carries the workflow's static names. Its form and values are cut to fields the app may read; opaque content and signed documents are omitted from this write response. Files a run produced answer `404`.
Name who may claim the work.
Replaces the work's candidates, and needs an Assign scope that reaches the record. An assignee may read a field of the record only where a routing rule may: never a secured one. The operation declares no idempotency key: a repeated call emits its `work.assigned` event and notifies again, so re-read the record before retrying.
Claim a work record's work.
A candidate — named, or in a group or unit pool the work targets — takes live, unclaimed work. On an entity whose claim setting is `readers`, so may anyone whose Read scope reaches the record. Whether the caller may read the record is decided first, so a caller who may not learns nothing about it.
Hand the work to another person.
The holder may hand it on; so may anyone whose grants let them assign the record's work. The new holder holds it at once. The operation declares no idempotency key: a repeated call emits its `work.reassigned` event and notifies again, so re-read the record before retrying.
Release a work record's work.
The holder releases their own work; releasing work someone else holds needs an Assign scope that reaches the record. Nobody holds the work afterwards, and its candidates may claim it again.
Events after a position.
Catches up on the event stream: the same events, in the same envelope, that the caller would have received on it.
Follow events as they happen.
The same events, in the same envelope, as webhooks and `GET /events`, limited to what the caller may see when each is sent. Resume with `Last-Event-ID` or `after` within the resume window; otherwise the stream sends `refetch` and continues from now. Delivery is at least once from a position: de-duplicate by position.
List_groups
Get_group
Resolve_identities
List_instances
Get_instance
Through an installed app, a run is told only while it holds nothing: once a step has taken in or given out any input, output, variable, failure text or agent call the run has progressed, and its detail is refused (`APP_CEILING_DENIED`) rather than returned raw. What is told of a run that holds none has no frozen graph, forms, entity schemas, context, output or error, and its active tasks carry the workflow's static names. Files a run produced answer `404`.
Cancel a run AND every live run it spawned.
ForEach fan-out children and sub-workflow calls are independent runs; the cancel walks down to all of them and terminalizes the whole lineage in one transaction, so no surviving parent is ever left waiting on a cancelled child. Runs already terminal are counted, not touched.
Pause a run AND every live run it spawned, reversibly.
The lineage-wide counterpart of cancel, without the finality. Every path that would enqueue a `workflow.tick` is refused for the duration, so no child spawns and nothing advances. **It does not recall work already queued.** A model call, an email or a document parse already sitting on the queue for a node parked before the pause still runs — one per already-parked node, never a fan-out. Spend therefore ticks up briefly after a pause; that is the boundary, not a bug.
Release an operator pause, or recheck and release an app hold over the live lineage.
Only the run the operator paused may be resumed: a member of a paused lineage is released through its root, or releasing it alone would put it back to work under an ancestor still held. A member that finished, failed or was cancelled while held keeps its terminal status — resume releases a hold, it never resurrects a run. An app-held target must still be live; a terminal app-held root cannot release its descendants. Operator-owned terminal-root release is preserved.
Retry a `failed` run **and every failed run beneath it**: flip the whole failed sub-tree back to `running` and tick the frontier. The engine's recovery seed re-attempts every failed node (minting a fresh node_run; the failed rows stay as history) and never re-runs a completed node — so no duplicate human tasks or re-generated documents. We deliberately do NOT touch node_runs here: flipping the (possibly several) failed rows of one node to `waiting` would collide on the one-active-row-per-node index and clobber the attempt history.
The cascade is not optional and has no flag, because retrying the root ALONE could never work: a `call_workflow` re-tick fail-fasts on its terminal child and a ForEach settle re-aggregates terminal children to the same verdict, both while answering `200`. Where a run has no failed descendants this behaves exactly as it always did. Because instances run on an immutable snapshot, this only makes forward progress when the original failure was transient (an external dependency that has since recovered); a config bug needs a re-publish and a fresh instance.
The `@` menu while writing about a record: records the caller mentioned recently when nothing is typed; otherwise the people who can read the record, then one group per entity with hits, best hit first.
A record is offered only if the caller may list and read it, and through an installed app only from an entity its ceiling covers. People are offered only if they can read the record (on a create form, its parent), and through an installed app only while its package requires the `user` entity and lists its `name`. Built-in directories are never record groups.
The people who can read a record, for the `@` menu of a comment or note.
Only a person who can read the record is offered, so a mention never names someone the record is hidden from. Blank `q` offers the first people by name.
List_notifications
Mark_all_notifications_read
Count_unread_notifications
Mark_notification_read
What this deployment reads: the newest platform month and the package format versions it verifies.
The organization's sandboxes that are not yet deleted or expired.
Create a sandbox: an organization under the caller's, with the cast the body's `spec` describes. The answer carries every secret, once: the deploy key and each person's token.
One sandbox of the organization, also after it is deleted or purged.
Delete a sandbox: every way into it closes at once and its data is purged later. Answers `204` whatever its state, so a retry after an ambiguous answer, or after it expired, succeeds. The parent's key may delete any of its sandboxes; a sandbox's owner may delete that sandbox, once, because the deletion revokes the owner's token.
A one-time browser sign-in link for one of the sandbox's people. The link is good once, for five minutes.
Search_content
List_units
Get_unit
List_users
Get_user
The event types a subscription may choose. Needs no permission beyond authentication.
The organization's webhook subscriptions.
Create a subscription. The secret is returned only here and on rotation.
One subscription.
Change a subscription. Changing `url`, `event_types` or `include_child_runs` redirects the principal's events and follows the rule for naming it; changing only `description` needs `webhook.manage`.
Delete a subscription. Its secrets and deliveries go with it; its history stays.
A subscription's deliveries, newest first.
One delivery, with every attempt.
Send the same event again. The new delivery carries the same `webhook-id` and is re-authorized before its first attempt.
A subscription's history, newest first, including every expiry of held deliveries.
Pause a subscription. Matching events still arrive, as held deliveries. Pausing a paused subscription answers it as it is.
Resume a subscription. Held deliveries return to pending and are sent oldest first. Resuming an active subscription answers it as it is.
Rotate the signing secret. Every superseded secret keeps signing until the end of the overlap it was promised, unless `revoke_previous` is true.
The caller's work records in one list.
Live work they hold or could claim, and work they finished in the last thirty days, under one cursor. A work record is listed only from an entity that follows Work surface and whose records the caller may read. A line a workflow step holds carries the step. Through an installed app, a Workflow task is listed only where the ceiling covers the workflow that opened it, titled by its step, and its subject is told as far as the app may read the subject's entity. Through an installed app, a record is listed only for an entity the ceiling lets the app read and list, and only while the app may read everything its row is made of: the status (`work_state`), the priority field and each clock's state, outcome and due time. A required entity therefore lists no work unless the package lists all of them.
Get_start_form
Through an installed app, the form offers only the properties the ceiling lets the app set.
The runtime start catalog. Session-gated with authorization **in the result set**, the same model as `startable-ids`: a workflow the caller cannot start is absent rather than present-and-disabled, so the response never discloses the names of workflows they have no access to.
Deliberately not `/admin/workflows`. That route answers a different question — it ships the full design-time projection (description, group, active-instance count, MCP flag, author, timestamps, drafts) behind the designer's search/status/paging surface. Serving both from one endpoint is what made every org member able to enumerate the whole catalog.
The CURRENT published input contract of a workflow, flattened for the designer's action editor / input-map builder and the list surfaces' revalidation (an action whose bound workflow was republished to an incompatible contract is hidden or disabled client-side).
Start_instance
Through an installed app, the run that starts is told as a run just started, holding no input, output or context.