Outcome
Search authorized draft and published form projections, using returned pagination without assuming bounded backend work.
GET /api/forms/references
Before you start
Use the original authorized organization and discovered canonical Forms workspace, bound separately as a resource. The action needs workspace:read and verified read workspace access; a form/reference id or optional workspaceId input is not a grant.
These authenticated Connected Apps reads include drafts and are distinct from public form access. A returned reference projection, URL or embed URL does not create a placement, join a workspace, grant a recipient access or authorize publication/submission.
All examples are complete source-derived synthetic responses, unrun. Fictional ids and reserved example.test URLs authorize no operation. No real form/subject/placement/Auth/resource/provider/model/notification call or browser navigation was performed. Source declaration provenance, actual serving, domains, protection health and browser rendering remain separate.
Request and response
Action: app_topolo_forms.forms.references.list.
Input supports q,cursor,limit and optional workspaceId. The handler trims/lowercases q, matches title substring or exact case-insensitive id, and keeps listForms order by updated_at descending. It includes drafts; there is no implicit published-only filter.
Response is HTTP200 {items:[projection...],nextCursor:string|null}. Default limit25, maximum100. The source interprets a numeric-string cursor as an offset, slices the matching array and returns the next offset when more matches exist. Reuse the returned cursor unchanged; input schema rejects non-digit tokens and out-of-range limits.
Pagination happens after listForms loads every workspace form, performs a separate submission COUNT per form and decodes protected content. A page limit does not bound the database/decryption work. The offset is not a versioned snapshot and equal updated_at values have no stable tie-breaker; concurrent changes can shift results between pages.
The source first reads full scoped form models through the existing protected content/count path, then projects only id,label,status,updatedAt,publishedAt,workspace,url,embedUrl. Projection does not mean the underlying work is a cheap metadata-only query. Protection, auth or database errors are not an empty result.
Label is stored title with id fallback. Published status plus a nonempty configured public base produces /public/<encoded form id> and /embed/<encoded form id>; otherwise both URLs are null. Drafts remain discoverable with draft status and null URLs. A published record can also have null URLs when no public base is configured.
The projection carries plain form id, not a returned topolo: reference URI. The source canonical format is topolo:<appId>/<workspaceId>/forms.form/<formId> for validated components, but actual placement/reference discovery must use supported credential-scoped Connected Apps actions and resolved identities; never manufacture cross-context ids or invent a placement grant.
Reading these actions performs no form edit, publication, placement mutation, respondent submission or reference notification. Conditional change/removal events occur in separate mutation paths; their source declarations do not prove a consumer received an event or rendered an embed.
Complete worked responses
First reference page
Complete source-derived synthetic, unrun HTTP200. Assumes exactly the published fixture and older draft fixture match, successful original auth/workspace/read checks and readable content. Configured public base is https://forms.example.test, a fictional domain.
Input:
{
"limit": 1
}
Response:
{
"items": [
{
"id": "forms_docs_fixture",
"label": "Fixture feedback",
"status": "published",
"updatedAt": "2026-10-21T01:00:00.000Z",
"publishedAt": "2026-10-02T08:00:00.000Z",
"workspace": "ws_forms_docs_fixture",
"url": "https://forms.example.test/public/forms_docs_fixture",
"embedUrl": "https://forms.example.test/embed/forms_docs_fixture"
}
],
"nextCursor": "1"
}
Verify the actual target and publication/URL semantics below; this fixture creates no reference placement or access.
Continue the same fictional page sequence
Complete source-derived synthetic, unrun HTTP200. Assumes the same unchanged two-record matching order as the first example. Draft is discoverable but its URLs remain null; this is not a public-access grant.
Input:
{
"limit": 1,
"cursor": "1"
}
Response:
{
"items": [
{
"id": "forms_draft_docs_fixture",
"label": "Fixture draft",
"status": "draft",
"updatedAt": "2026-10-20T01:00:00.000Z",
"publishedAt": null,
"workspace": "ws_forms_docs_fixture",
"url": null,
"embedUrl": null
}
],
"nextCursor": null
}
Verify the actual target and publication/URL semantics below; this fixture creates no reference placement or access.
No search matches
Complete source-derived synthetic, unrun HTTP200. Assumes successful underlying reads with no title/id match. This does not represent a suppressed permission or protection failure.
Input:
{
"q": "no-match-docs-fixture"
}
Response:
{
"items": [],
"nextCursor": null
}
Verify the actual target and publication/URL semantics below; this fixture creates no reference placement or access.
Verify and recover
-
Compare every returned workspace with the original authorized resource. Keep ids/status/URLs distinct and stop on an unexpected context.
-
Reuse nextCursor only for the same intended query/resource, stopping at null. Reconcile changes or duplicates under concurrent edits rather than treating offset pages as an immutable inventory.
This read needs no data rollback. On a failure preserve the actual request id and sanitized response for the owner; do not create a workspace, publish a draft, change protection or submit real data as recovery.
Refusals
400 / workspace_required: Resolve the real canonical workspace through supported Auth and bind it separately, without a guessed resource.
403 / forbidden: Retain the original caller/context and actual denial; use the owner for legitimate read access.
400 / invalid_cursor: Use the unchanged returned cursor for the same resource/query; the source also rejects unsafe numeric offsets. Invalid strict-schema input is refused locally before transport.
400 / invalid_limit: Use a current schema-valid integer1..100, default25. Do not imply this bounds underlying collection/count/decryption work.
Shared runtime/Auth/protection errors require their actual carrier evidence; the success schema does not describe every failure.
Related actions
Change log
- 2026-10-21: Added precise reference projection, original workspace/privacy boundaries, draft/URL semantics, source pagination limits and complete illustrative responses. All examples remain synthetic and unrun.