Signed event sources
An event source binds a public signing key, input rules and an exact agent run request. Publication records an immutable version. It does not activate the source or start a run. Read execution_ready before enabling: false means the event admission worker is unavailable. A true value does not prove that an event has produced a run.
Open Synapse → Event Sources to inspect the bounded directory, publish a new source or revision, and review enable, pause or retirement separately. The page uses the same exact agent, input, grants, budget and output selection as an ordinary run. Preparing that selection does not submit a run.
Publish public metadata
Section titled “Publish public metadata”Create and retain the Ed25519 signing private key in the external source’s secret store. Send only its 32-byte public key, encoded as canonical padded base64, with an explicit signing key UUID. The portal and SDK do not generate or persist the private key. Publishing a new key requires a new immutable source revision and separate activation.
Choose an input mode:
fixeduses the exact prepared run input reference. Event input overrides are refused. Each run reads that input as the person who enabled the source, while they can still read it, so the agent needs no share or grant for it.event_referencerequires each signed event to identify current approved JSON content through an exact reference. Raw event bodies do not become run input. The prepared run’s input remains an explicit publication validation pin. The agent reads an event’s input with its own access, so share each such document with it and name it in a content grant.
Set max_event_age_seconds from 10 through 86,400 and max_pending_events from 1 through 10,000. These bounds do not extend content, grants, consent or budget lifetimes. Each event must still pass current authority and funding checks.
An event’s run pays the way its budget pays: credits, or the wallet a budget is paid from, checked for each event as for a run started by hand. An event source cannot pay its runs with x402, and cannot use a budget paid per run.
Read the current environment and include expected_environment_epoch and expected_reset_generation. Choose a source UUID and expected_revision: 0 for its first publication. Later publications use the current head revision. An active version can differ from that head.
const scope = { org_id, environment_id };const operation = await client.eventSources.publish(scope, { source_id, expected_revision: 0, expected_environment_epoch: environment.authority_epoch, expected_reset_generation: environment.reset_generation, configuration: { name: "Reviewed source events", signing_key: { id: signing_key_id, public_key }, input_mode: "fixed", max_event_age_seconds: 300, max_pending_events: 100, run, },}, publicationKey);const record = await client.eventSources.getVersion(scope, operation.resource_id);Python exposes client.event_sources with publish, get, get_version, list, set_enabled and retire. TypeScript uses getVersion and setEnabled. Publication and reads accept current human sessions or appropriately scoped keys with synapse:event_sources:write. Workload credentials cannot author sources.
Review activation separately
Section titled “Review activation separately”Enable, pause and retirement require a human session. Enabling also requires an available event admission worker. Submit the exact version reference, observed expected_generation, both environment preconditions, and an explicit enabled boolean. Use generation zero if no activation exists.
When pausing, inspect activation.version: it may be older than the publication head. Retirement uses the same exact version and generation preconditions without enabled. It is terminal for that source identity. Publication does not revive a retired source.
Test simulation, paid Test Compute and Live retain their separate current permissions and funding requirements. An event signature does not grant additional run authority or transfer consent across environments.
Inspect and recover
Section titled “Inspect and recover”list accepts limit from 1–50, after and include_retired; its default limit is 25. Continue explicitly with next_cursor. Use get for the current head and getVersion for a specific immutable version.
Keep the exact request and caller-selected idempotency key after an unknown mutation outcome. The portal retains only the operation kind, identifiers, versions, environment pins, key and request digest in account-scoped tab storage. Reconstruct the exact reviewed configuration after reload. Changed configuration cannot replace the original request or key. Recheck current access and retry only through explicit review and acknowledgment; the SDK does not retry automatically.
An operation receipt confirms its historical mutation, not current execution or authority. Reset and revocation may refuse recovery while the original uncertain metadata remains retained. No simulated event preview is provided.
Inspect signed-event receipts
Section titled “Inspect signed-event receipts”Use client.eventSources.listReceipts(scope, source_id, { limit: 25 }) and continue
with next_after supplied as after. getReceipt(scope, receipt_id) reads an
exact receipt. Python provides list_receipts and get_receipt. These reads use
current synapse:event_sources:write authority and any exact source-resource
restriction on the credential.
The portal reads receipts only after Inspect Signed Event Receipts or an
explicit exact receipt lookup. It shows the event ID, immutable source version,
activation generation, received and expiry times, and recorded state. pending
means admission remains pending; denied and expired do not authorize a run.
Only admitted includes a canonical run ID, which links to run inspection. It does
not mean executing or completed. A receipt can refer to an older activation
generation while remaining visible within the current environment reset.
Private actor, run template, signature time and worker lease fields are excluded.
Input content is never fetched by receipt inspection.
Sign at the external source
Section titled “Sign at the external source”The producer sends a raw JSON envelope, at most 16,384 bytes, to
POST /katara/v1/orgs/{org_id}/environments/{environment_id}/event-sources/{source_id}/events.
Use Content-Type: application/json and X-Katara-Event-Signature. Do not attach
API credentials, session authorization, cookies, browser Origin, Idempotency-Key or Content-Encoding. Query parameters are refused. The public key comes from the
exact activated source version; signing does not replace its current authority.
The flat envelope contains org_id, environment_id, schema_version: 1,
source_id, exact source_version, activation_generation, mode,
reset_generation, event_id, occurred_at, optional input_ref, and
signed_at. Both timestamps must be UTC whole seconds ending in Z.
occurred_at cannot follow signed_at. The signature time must be newer than five
minutes ago and no more than thirty seconds in the future. The source’s event-age
bound applies to new admission.
Sign these bytes with Ed25519, without hashing them again through a separate prehash signature mode:
UTF8("katara.synapse.event.v1") || 0x00 || UTF8(signing_key_id) || 0x00 || UTF8("sha256:") || ASCII(lowercase_hex(SHA256(exact_body_bytes)))Encode the 64-byte signature as canonical padded standard base64 in the signature header. Preserve the exact signed body bytes during transmission; reserializing JSON can change its hash. Duplicate, unknown or incorrectly cased fields are refused. A persisted receipt returns HTTP 202. Invalid signature and unavailable source authority are not distinguished by the HTTP 403 response.
A fresh signature can repeat the same semantic event ID and metadata after an
uncertain response, subject to current source authority. Changing the source
version, activation, reset, mode, input reference or other semantic event fields
cannot reuse that receipt identity. signed_at is excluded from the semantic
event digest, allowing a fresh signature over the same event. Source changes can
refuse renewed ingress; authorized receipt inspection remains the separate
metadata recovery path. The portal never sends producer events or handles the
signing private key.