Proposals
The Proposals operations of the Hub REST API (9 operations).
bearerAuthAuthorizationBearer <API key>Pod API key (Bearer) issued via /api/hub/setup/agent or pod admin tooling. Browser/web clients may use the X-Session-Token header instead. See GET /api/hub/auth/status to introspect the calling key.
application/json- body
documentId*stringuserId*stringagentUserId?stringsourceMessageId?stringsessionId?stringproposedContent*stringbaseRevision?integer0 <= valueallowRemovingEmbeds?booleanreasoning?stringCreated proposal
application/json- response
id*stringstatus?string[key: string]?unknowncurl -X POST 'https://pod.example.com/api/hub/documents/proposals' \ -H 'Content-Type: application/json' \ -d '{ "documentId": "string", "userId": "string", "proposedContent": "string"}'{ "id": "string", "status": "string", "property1": null, "property2": null}bearerAuthAuthorizationBearer <API key>Pod API key (Bearer) issued via /api/hub/setup/agent or pod admin tooling. Browser/web clients may use the X-Session-Token header instead. See GET /api/hub/auth/status to introspect the calling key.
userId?stringworkspaceId?stringstatus?stringDefaults to pending. Use all to return every status. auto_approved returns the audit receipts of agent writes that were executed immediately under governance rather than queued for review.
"pending""approved""rejected""auto_approved""reverted""approval_failed""withdrawn""expired""all"view?stringfull (DEFAULT) returns the complete proposal row including the unbounded data payload. basic returns identity + provenance scalars and a capped summary, with NO data — use it to enumerate a queue without paying for every payload.
"full""basic"limit?integerPage size. Defaults to 50, clamped to 200.
1 <= value <= 200offset?|Rows to skip (native SQL OFFSET). Defaults to 0. The response carries total and hasMore, so a caller never has to infer the size of the queue from the size of the page.
0 <= valueProposals — full rows by default, basic rows when view=basic
application/json- response
proposals*array<>|array<>limit*numberEffective page size after clamping.
offset*numberEffective offset after clamping.
hasMore*booleanTrue when at least one row exists past this page — the signal that distinguishes a full page from the end of the queue.
curl -X GET 'https://pod.example.com/api/hub/proposals'{ "proposals": [ { "id": "string", "workspaceId": "string", "targetType": "string", "targetId": "string", "proposalType": "string", "data": { "property1": null, "property2": null }, "status": "pending", "agentUserId": "string", "threadId": "string", "sourceMessageId": "string", "createdBy": "string", "createdAt": "string", "updatedAt": "string", "sessionId": "string", "class": "ephemeral", "lifetimeHours": 0, "setup": { "params": [ { "name": "string", "label": "string", "type": "string", "required": true, "description": "string", "secret": true, "satisfied": true, "ref": "string", "refName": "string", "refService": "string", "refUnresolved": true } ], "connection": { "required": true, "kind": "string", "provider": "string", "state": "string", "property1": null, "property2": null }, "blocking": true, "nextAction": { "kind": "string", "hint": "string", "url": "string", "opensIn": "web", "property1": null, "property2": null } } } ], "limit": 0, "offset": 0, "hasMore": true}bearerAuthAuthorizationBearer <API key>Pod API key (Bearer) issued via /api/hub/setup/agent or pod admin tooling. Browser/web clients may use the X-Session-Token header instead. See GET /api/hub/auth/status to introspect the calling key.
application/json- body
workspaceId?string|nullagentUserId?stringchannelId?stringChannel/thread originating the proposal.
targetType*stringSubject type the proposal mutates (e.g. entity, view).
targetId*stringID of the target subject (existing record or stable temp id).
proposalType*stringSub-action, e.g. entity.create, view.update, vault.request.
data*Free-form proposal payload — shape is targetType-specific.
summary?stringsessionId?stringFocus session ID to link this proposal to.
sourceMessageId?stringMessage that originated the proposal — for event chain causality.
Created proposal
application/json- response
id*stringstatus*"pending""pending"curl -X POST 'https://pod.example.com/api/hub/proposals' \ -H 'Content-Type: application/json' \ -d '{ "targetType": "string", "targetId": "string", "proposalType": "string", "data": { "property1": null, "property2": null }}'{ "id": "string", "status": "pending"}bearerAuthAuthorizationBearer <API key>Pod API key (Bearer) issued via /api/hub/setup/agent or pod admin tooling. Browser/web clients may use the X-Session-Token header instead. See GET /api/hub/auth/status to introspect the calling key.
id*stringThe proposal
application/json- response
id*stringworkspaceId*string|nulltargetType*stringtargetId*stringproposalType*stringdata*status*ProposalRowStatus"pending""approved""rejected""auto_approved""reverted""approval_failed""withdrawn""expired"agentUserId?string|nullthreadId?string|nullsourceMessageId?string|nullcreatedBy?string|nullcreatedAt?string|updatedAt?string|sessionId?string|nullclass*ProposalClassDecision class — derived from proposalType x targetType, not stored.
"ephemeral""curatorial""objectWork""governance""access"lifetimeHours*|Hours this proposal stays answerable once its context is gone. null for every class that never expires; only ephemeral has one.
setup?curl -X GET 'https://pod.example.com/api/hub/proposals/string'{ "id": "string", "workspaceId": "string", "targetType": "string", "targetId": "string", "proposalType": "string", "data": { "property1": null, "property2": null }, "status": "pending", "agentUserId": "string", "threadId": "string", "sourceMessageId": "string", "createdBy": "string", "createdAt": "string", "updatedAt": "string", "sessionId": "string", "class": "ephemeral", "lifetimeHours": 0, "setup": { "params": [ { "name": "string", "label": "string", "type": "string", "required": true, "description": "string", "secret": true, "satisfied": true, "ref": "string", "refName": "string", "refService": "string", "refUnresolved": true } ], "connection": { "required": true, "kind": "string", "provider": "string", "state": "string", "property1": null, "property2": null }, "blocking": true, "nextAction": { "kind": "string", "hint": "string", "url": "string", "opensIn": "web", "property1": null, "property2": null } }}bearerAuthAuthorizationBearer <API key>Pod API key (Bearer) issued via /api/hub/setup/agent or pod admin tooling. Browser/web clients may use the X-Session-Token header instead. See GET /api/hub/auth/status to introspect the calling key.
id*stringapplication/json- body
data*Updated proposal payload (replaces existing data).
summary?stringHuman-readable summary of the revision.
Updated proposal
application/json- response
id*stringworkspaceId*string|nulltargetType*stringtargetId*stringproposalType*stringdata*status*ProposalRowStatus"pending""approved""rejected""auto_approved""reverted""approval_failed""withdrawn""expired"agentUserId?string|nullthreadId?string|nullsourceMessageId?string|nullcreatedBy?string|nullcreatedAt?string|updatedAt?string|sessionId?string|nullclass*ProposalClassDecision class — derived from proposalType x targetType, not stored.
"ephemeral""curatorial""objectWork""governance""access"lifetimeHours*|Hours this proposal stays answerable once its context is gone. null for every class that never expires; only ephemeral has one.
setup?curl -X PATCH 'https://pod.example.com/api/hub/proposals/string' \ -H 'Content-Type: application/json' \ -d '{ "data": { "property1": null, "property2": null }}'{ "id": "string", "workspaceId": "string", "targetType": "string", "targetId": "string", "proposalType": "string", "data": { "property1": null, "property2": null }, "status": "pending", "agentUserId": "string", "threadId": "string", "sourceMessageId": "string", "createdBy": "string", "createdAt": "string", "updatedAt": "string", "sessionId": "string", "class": "ephemeral", "lifetimeHours": 0, "setup": { "params": [ { "name": "string", "label": "string", "type": "string", "required": true, "description": "string", "secret": true, "satisfied": true, "ref": "string", "refName": "string", "refService": "string", "refUnresolved": true } ], "connection": { "required": true, "kind": "string", "provider": "string", "state": "string", "property1": null, "property2": null }, "blocking": true, "nextAction": { "kind": "string", "hint": "string", "url": "string", "opensIn": "web", "property1": null, "property2": null } }}bearerAuthAuthorizationBearer <API key>Pod API key (Bearer) issued via /api/hub/setup/agent or pod admin tooling. Browser/web clients may use the X-Session-Token header instead. See GET /api/hub/auth/status to introspect the calling key.
id*stringapplication/json- body
reason?stringRevert applied
application/json- response
success*booleanreverted*curl -X POST 'https://pod.example.com/api/hub/proposals/string/revert' \ -H 'Content-Type: application/json' \ -d '{}'{ "success": true, "reverted": { "entityIds": [ "string" ], "relationIds": [ "string" ], "documentIds": [ "string" ] }}bearerAuthAuthorizationBearer <API key>Pod API key (Bearer) issued via /api/hub/setup/agent or pod admin tooling. Browser/web clients may use the X-Session-Token header instead. See GET /api/hub/auth/status to introspect the calling key.
id*stringapplication/json- body
identityResolution?Weak same-name choice for a single entity/create. fill_empty, keep_existing, and use_capture require existingEntityId. separate does not. Absent ⇒ today's create.
identityResolutionByRef?Composite per-create choice, keyed by the entity ref dispositions use. One entry is not applied to any other op.
Proposal approved
application/json- response
success*booleanproposalId*stringproposal?primaryId?stringThe row the approval produced or LINKED to, when the executor reports one — e.g. the focus session a focus_session/create approval inserted, or the existing open session it reused.
linked?numberHow many existing rows the approval linked to instead of creating (e.g. 1 when an open session of the same goal and scope already existed).
identity?Set when an identity resolution ran. Not stored on the proposal row — only this response carries it. fill_empty includes filled and conflicts.
identities?array<>Composite: one entry per op that ran a resolution. Singular identity is also set when exactly one op resolved.
curl -X POST 'https://pod.example.com/api/hub/proposals/string/approve' \ -H 'Content-Type: application/json' \ -d '{}'{ "success": true, "proposalId": "string", "proposal": { "id": "string", "workspaceId": "string", "targetType": "string", "targetId": "string", "proposalType": "string", "data": { "property1": null, "property2": null }, "status": "pending", "agentUserId": "string", "threadId": "string", "sourceMessageId": "string", "createdBy": "string", "createdAt": "string", "updatedAt": "string", "sessionId": "string", "class": "ephemeral", "lifetimeHours": 0, "setup": { "params": [ { "name": "string", "label": "string", "type": "string", "required": true, "description": "string", "secret": true, "satisfied": true, "ref": "string", "refName": "string", "refService": "string", "refUnresolved": true } ], "connection": { "required": true, "kind": "string", "provider": "string", "state": "string", "property1": null, "property2": null }, "blocking": true, "nextAction": { "kind": "string", "hint": "string", "url": "string", "opensIn": "web", "property1": null, "property2": null } } }, "primaryId": "string", "linked": 0, "identity": { "verb": "fill_empty", "entityId": "string", "filled": [ "string" ], "conflicts": [ { "key": "string", "kept": null, "incoming": null } ] }, "identities": [ { "ref": "string", "verb": "fill_empty", "entityId": "string", "filled": [ "string" ], "conflicts": [ { "key": "string", "kept": null, "incoming": null } ] } ]}bearerAuthAuthorizationBearer <API key>Pod API key (Bearer) issued via /api/hub/setup/agent or pod admin tooling. Browser/web clients may use the X-Session-Token header instead. See GET /api/hub/auth/status to introspect the calling key.
id*stringapplication/json- body
reason?stringreasonCode?string"wrong_entity""duplicate""wrong_kind_or_facet""wrong_link_type""wrong_workspace""bad_data""not_relevant""other"Proposal rejected
application/json- response
success*booleanproposalId*stringcurl -X POST 'https://pod.example.com/api/hub/proposals/string/reject' \ -H 'Content-Type: application/json' \ -d '{}'{ "success": true, "proposalId": "string"}bearerAuthAuthorizationBearer <API key>Pod API key (Bearer) issued via /api/hub/setup/agent or pod admin tooling. Browser/web clients may use the X-Session-Token header instead. See GET /api/hub/auth/status to introspect the calling key.
application/json- body
type*stringWhich dev-loop gate is being filed.
"dev.plan_approval""dev.deploy_approval"workspaceId?string|nullprojectId?string|nullchannelId?stringsourceMessageId?stringpayload*|The gate payload — shape is determined by type.
The filed gate proposal
application/json- response
id*stringstatus*stringsessionId*stringcurl -X POST 'https://pod.example.com/api/hub/proposals/dev-approval' \ -H 'Content-Type: application/json' \ -d '{ "type": "dev.plan_approval", "payload": { "sessionId": "f6567dd8-e069-418e-8893-7d22fcf12459", "repo": "string", "branch": "string", "planMarkdown": "string", "gateCommand": "string" }}'{ "id": "string", "status": "string", "sessionId": "string"}