Outcome
Store a named HTTPS source in the granted workspace after validating its URL. Registration neither fetches nor imports source content, and every call creates a new record even for a duplicate endpoint.
Before you start
- Verify the authenticated identity, exact environment and pinned approved organization context before preparing an action.
- Development stores content without encryption and uses scoped SHA-256 identifier hashes. Staging and production require envelope encryption and a provisioned application root; missing custody does not permit plaintext.
- The published application permission is feed:write. Discover a granted Feed workspace and bind that exact resource. Supplied identifiers and query selectors do not grant access.
- Authorize the documented mirror, security, external-fetch, reporting, privacy or archival effects before CLI --confirm or MCP confirm:true. A GET request can initialize a local mirror.
Discover the target
topolo whoami --json
topolo actions get app_topolo_feed.sources.create --detail --json
topolo resources topolo-feed --json
topolo workspaces list topolo-feed --json
- Select the exact granted workspace id as FEED_WORKSPACE_ID. Fixture ids authorize no live operation.
Request
POST /api/analytics/sources
Save action input as payload.json. Inspect the plan for the exact path, query and body. Set FEED_WORKSPACE_ID from granted resource discovery.
Inspect and test this action in the signed action console, then perform the verification below.
Input fields
| Field | Required | Type | Constraints |
|---|---|---|---|
name | Required | string | Trimmed source label, 1 to 120 characters; duplicate labels and endpoints do not deduplicate creation.; {"minLength":1,"maxLength":120} |
endpointUrl | Required | string | HTTPS source URL subject to handler URL validation. Registration does not fetch or import content.; {} |
Exact input schema:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 120,
"description": "Trimmed source label, 1 to 120 characters; duplicate labels and endpoints do not deduplicate creation."
},
"endpointUrl": {
"type": "string",
"format": "uri",
"pattern": "^https:\\/\\/.*",
"description": "HTTPS source URL subject to handler URL validation. Registration does not fetch or import content."
}
},
"required": [
"name",
"endpointUrl"
],
"additionalProperties": false
}
Effects
- Resolves the workspace through platform grants and can insert its identity-only local mirror before the route permission check. GET is therefore a mutation for action planning; it does not create a canonical workspace or change its name.
- Encrypts the source name and endpoint URL in staging and production; development stores them without encryption. Persists a new id and returns camelCase endpointUrl/createdAt.
- Requires HTTPS and rejects URL user info, explicit non-default ports and the handler listed local/private address and hostname patterns. This is URL validation, not independent DNS or content safety certification.
Interpret the response
Use response path $.source.id for feed_source. An empty list does not discover a target.
Retain source.id and compare name and endpointUrl. Read sources.list in the same workspace to inspect the registered snake_case record. Before retrying an uncertain creation, discover an exact matching source; repeated calls do not provide idempotency.
The success schema below was checked against captured handler responses. Polymorphic configuration and protected device assignment fields vary; exact envelope and SQL row fields are source-reviewed. Error examples retain their actual refusal shapes.
Success schema:
{
"type": "object",
"properties": {
"source": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"endpointUrl": {
"type": "string"
},
"createdAt": {
"type": "string"
}
},
"required": [
"id",
"name",
"endpointUrl",
"createdAt"
],
"additionalProperties": false
}
},
"required": [
"source"
],
"additionalProperties": false
}
Worked examples
Actual Feed Worker response using synthetic Auth, workspace grants, in-memory D1/KV and simulated source/notification transport. No live provider, encryption audit, device enrollment or external delivery is established. Credentials are excluded or explicitly redacted. SQL result shapes are also reviewed against migrations and handlers; empty captures do not exercise every populated export store. Live publication and read-back are separate environment evidence. Refused examples demonstrate boundaries and must not be executed as successful workflows.
Refused request · HTTP 400
Actual Feed Worker response using synthetic Auth, workspace grants, in-memory D1/KV and simulated source/notification transport. No live provider, encryption audit, device enrollment or external delivery is established. Credentials are excluded or explicitly redacted. Captured scenario: source registry is discoverable, workspace-scoped, SSRF-safe, and records failed syncs.
Input · payload.json:
{
"name": "Metadata",
"endpointUrl": "https://127.0.0.1/latest"
}
CLI:
topolo actions validate app_topolo_feed.sources.create --data @payload.json --json
topolo actions plan app_topolo_feed.sources.create --resource-type workspace --resource-id "$FEED_WORKSPACE_ID" --data @payload.json --json
Captured local response · HTTP 400:
{
"error": "invalid_source_url"
}
HTTP 400. The handler refused this request. Resolve its exact cause before retrying; input validation can reject an invalid fixture before it reaches the handler.
Successful request
Actual Feed Worker response using synthetic Auth, workspace grants, in-memory D1/KV and simulated source/notification transport. No live provider, encryption audit, device enrollment or external delivery is established. Credentials are excluded or explicitly redacted. Captured scenario: source registry is discoverable, workspace-scoped, SSRF-safe, and records failed syncs.
Input · payload.json:
{
"name": "Partner",
"endpointUrl": "https://partner.example/feed.json"
}
CLI:
topolo actions validate app_topolo_feed.sources.create --data @payload.json --json
topolo actions plan app_topolo_feed.sources.create --resource-type workspace --resource-id "$FEED_WORKSPACE_ID" --data @payload.json --json
topolo actions call app_topolo_feed.sources.create --resource-type workspace --resource-id "$FEED_WORKSPACE_ID" --data @payload.json --confirm --json
MCP tool and arguments:
{
"tool": "topolo_call_action",
"arguments": {
"actionId": "app_topolo_feed.sources.create",
"input": {
"name": "Partner",
"endpointUrl": "https://partner.example/feed.json"
},
"resourceType": "workspace",
"resourceId": "<identifier returned by granted resource discovery>",
"confirm": true
}
}
Captured local response · HTTP 201:
{
"source": {
"id": "source_0f815beb-1299-409a-a199-4372e699da4c",
"name": "Partner",
"endpointUrl": "https://partner.example/feed.json",
"createdAt": "2026-10-04T04:12:42.927Z"
}
}
HTTP 201. Retain source.id and compare name and endpointUrl. Read sources.list in the same workspace to inspect the registered snake_case record. Before retrying an uncertain creation, discover an exact matching source; repeated calls do not provide idempotency.
Another supported request
Actual Feed Worker response using synthetic Auth, workspace grants, in-memory D1/KV and simulated source/notification transport. No live provider, encryption audit, device enrollment or external delivery is established. Credentials are excluded or explicitly redacted. Captured scenario: successful source sync consumes content and persists only terminal sync state.
Input · payload.json:
{
"name": "Partner",
"endpointUrl": "https://partner.example/feed.json"
}
CLI:
topolo actions validate app_topolo_feed.sources.create --data @payload.json --json
topolo actions plan app_topolo_feed.sources.create --resource-type workspace --resource-id "$FEED_WORKSPACE_ID" --data @payload.json --json
topolo actions call app_topolo_feed.sources.create --resource-type workspace --resource-id "$FEED_WORKSPACE_ID" --data @payload.json --confirm --json
MCP tool and arguments:
{
"tool": "topolo_call_action",
"arguments": {
"actionId": "app_topolo_feed.sources.create",
"input": {
"name": "Partner",
"endpointUrl": "https://partner.example/feed.json"
},
"resourceType": "workspace",
"resourceId": "<identifier returned by granted resource discovery>",
"confirm": true
}
}
Captured local response · HTTP 201:
{
"source": {
"id": "source_0b15b4ee-87ae-4cbb-abcd-a47e1aebe379",
"name": "Partner",
"endpointUrl": "https://partner.example/feed.json",
"createdAt": "2026-10-04T04:12:42.930Z"
}
}
HTTP 201. Retain source.id and compare name and endpointUrl. Read sources.list in the same workspace to inspect the registered snake_case record. Before retrying an uncertain creation, discover an exact matching source; repeated calls do not provide idempotency.
Verify the result
- Retain source.id and compare name and endpointUrl. Read sources.list in the same workspace to inspect the registered snake_case record.
- Before retrying an uncertain creation, discover an exact matching source; repeated calls do not provide idempotency.
Errors and recovery
invalid_source_url(HTTP 400): Inspect the exact handler refusal and correct the target, window, URL or confirmation before preparing another authorized request.
Auth, action-input validation and platform resource resolution can refuse a request before its handler. Retain the exact error, request id and context; requesting another context is not a legitimate way to bypass a refusal.
Recovery boundary
No narrow source update or deletion action is published. Retain an unwanted source and avoid selecting it; do not use organization erasure as routine compensation.
Related actions
- List registered Feed sources: Read registered sources in the granted workspace, decrypting name and endpoint URL with snake_case status fields. The unpaginated list is ordered by creation and id; the local mirror can be initialized.
- Record Feed source fetch attempt: Fetch a registered workspace HTTPS source without redirects, consume at most 1,048,576 response bytes, discard the body and persist its terminal attempt. HTTP 200 may contain a failed sync; no content is imported.
Evidence
Actual Feed Worker response using synthetic Auth, workspace grants, in-memory D1/KV and simulated source/notification transport. No live provider, encryption audit, device enrollment or external delivery is established. Credentials are excluded or explicitly redacted. SQL result shapes are also reviewed against migrations and handlers; empty captures do not exercise every populated export store. Live publication and read-back are separate environment evidence. Capture digests and test scenarios are retained in the source fixture records.