Skip to content

Notifications

Katara’s notification API provides one personal inbox across account, organization, billing, provider, Cortex, Synapse and Locus events. It uses your verified application session. API keys cannot read the inbox or change a person’s notification preferences.

Delivery providers and their configuration belong to each deployment. An event or channel appearing in the catalog does not mean every related feature or delivery provider is active where you are.

Connected sources report terminal Synapse runs, document ingestion, evaluation outcomes, pending Locus approval stages, account and billing changes, changes to a provider’s on-chain registration, and agent grants, budgets and API keys that end soon. Approval notices are limited to currently eligible reviewers. Two catalog entries have no source yet: cortex.usage_limit and synapse.connection_required.

Evaluation notices distinguish an available uncalibrated judgment (synapse.evaluation_ready), a known failure (synapse.evaluation_failed) and an unresolved call (synapse.evaluation_unknown). A ready notice can include criteria that could not be scored. Open the assessment to inspect the canonical result and run outcome; a notice alone does not establish a pass, calibration or charge outcome. Current source, requester and reviewer authority controls visibility. Losing access can hide a notice without changing the recorded score or charge.

synapse.online_evaluation_skipped goes to the person who turned online evaluation on for an agent, at most once a day for each reason: runs were drawn and not judged because the day’s cap was reached (daily_cap) or the budget could not cover them (budget). The setting stays on.

locus.connection_required reports a committed tool-account revocation or a committed OAuth state requiring reconnection. It belongs to the Locus connections category and requires an in-app notice. Its resource_id identifies the connection; source_operation_id identifies the exact immutable credential version. The event contains no provider account details, tokens or account digest. Open the connection and inspect its current state before reconnecting. Source authority is checked again when reading or delivering the notice; the event does not authorize a retry or provider exchange.

synapse.connection_required describes a run waiting for a connection, and no run waits on one, so nothing sends it. A bounded private collector also reports expired refresh reservations and retired credential or OAuth profiles when they currently require reconnection. It does not finalize or retry a provider exchange. Expired, revoked, superseded and reset versions are evaluated before a notice is made available; a stale notice does not prove that reconnection is still appropriate. Local producer checks do not prove external notification delivery, provider feedback or permission to retry an unknown delivery.

Provider notices come from the on-chain provider directory. When a provider’s entry changes, the account whose wallet registered it is told:

ChangeNotice
The provider is flaggedprovider.health_attention
The provider registers, pauses or resumes, or its wallet, service key or service address changesprovider.registration_changed
The payout address changesprovider.payment_updated

A notice reaches the account only while that account still holds the wallet. The first reading of a chain’s directory is its starting point, so turning this on does not announce providers that already existed.

Agent grants, budgets, API keys and repository approvals each end at a time chosen when they were made. When 80% of that time has passed, Katara sends one reminder, so a 30-day grant is announced on day 24.

What endsNoticeWho is toldWhere it is renewed
An agent grantlocus.grant_expiringThe person who issued it, and the organization’s owners and adminsThe agent’s New Run page, which offers Renew; a grant that does not start runs opens under Budgets & Grants
A budgetlocus.budget_expiringThe person who funded it, and the organization’s owners and adminsBudgets & Grants
An API keyorganization.key_expiringThe person who created itAPI Keys
A repository’s approvalsynapse.repository_approval_expiringThe person who attached the repository, and the organization’s owners and adminsRepositories, which offers Renew

Grants issued together for one agent on one budget, ending at the same moment, send one reminder between them, as when you allow an agent to run. The budget made with them sends none of its own: renewing the agent renews both.

No reminder is sent for anything revoked, closed or already ended, or for anything renewed. A grant counts as renewed when a later grant for the same agent and purpose ends after it. A budget counts as renewed when its payer funded a newer one for the same kind of usage that ends later, and every agent on the old budget already draws on the new one; a budget no agent draws on is always announced. A key counts as renewed when its holder created a newer key with the same name in the same environment that lasts longer. A repository’s approval counts as renewed when someone renewed it; none is sent for a repository that was detached, or whose installation was removed or uninstalled. If any of this happens after the reminder was sent, the reminder leaves the inbox and its queued deliveries are dropped.

The reminders are in the expiry category of Locus, Synapse and Organization, with no required channel, so you can turn each channel off, delay it or batch it like any optional notice. An expiry item also carries subject: the object’s name, its expires_at and the portal path where it is renewed. The subject is read from the source each time you read the notice; nothing in the notice record stores the name. Emails include the same name, end time and link.

Use listNotifications / list_notifications without filters for your cross-product inbox. Filter by organization, environment, product or state. An environment filter must include its organization. States are unread, read and archived.

Pages contain up to 100 items. Follow next_cursor when present, even if a page contains no visible items. Access can change while paging; the service checks current resource authority before returning a notice.

getNotificationCount returns unread_count and has_more. When has_more is true, display the count as a lower bound, such as 1,000+, rather than an exact total. The count can be filtered by organization, environment and product.

The title and body use fixed notification text. Customer prompts, model replies and tool arguments are not included. Open the authenticated deep_link to inspect the current resource. Receiving a notification does not grant access to that resource or approve an action.

Fetch the current item, then call setNotificationState with its ID, desired state and current version. Use set_notification_state in Python. A stale version receives a conflict; reload before deciding whether to repeat the change. After a lost response, read the item to find out whether the update committed.

Archiving a notice does not cancel a run, reject an approval or stop another delivery channel. An approval notification leads to the exact action review in Locus; the notification itself has no approve button in its payload.

getNotificationCatalog lists valid product/category pairs and required channels. listNotificationPreferences returns saved preferences for the selected account, organization or environment scope. More specific optional preferences take precedence over broader ones.

A preference names its product, category, channel, enabled state, IANA time zone and delivery interval. Supported intervals are immediate, hourly and daily. Quiet-hour start and end values are minutes after local midnight, from 0 to 1,439; provide both values, and keep them different. A snooze can extend at most 30 days into the future.

Use version zero when creating a preference. Use the returned current version when updating it. Required notices override optional preferences for the channels listed in the catalog. Required security notifications cannot be disabled, delayed or snoozed through these settings.

The schema includes in-app, email, webhook, push and SMS channel preferences. Saving a preference does not configure a delivery destination or activate a provider. Optional hourly and daily deliveries can combine due notices into a digest. Each notice retains its own delivery record, and grouped records expose the same batch_id. Current access and preferences are checked again before sending.

listNotificationDeliveries returns channel, state, attempt count, next attempt time and a bounded result code. It does not expose recipient addresses or delivery credentials.

StateMeaning
pending, sendingDelivery is queued or in progress
acceptedA provider accepted the message; recipient delivery is not yet confirmed
deliveredDelivery was confirmed; it does not mean the recipient read it
failedA temporary failure may be retried within the delivery limit
dead_letterDelivery needs attention, including unavailable channels or exhausted attempts
unknownThe send outcome is uncertain; the system does not assume it is safe to resend
suppressedCurrent access, preferences or recipient state prevented delivery
interceptedA Test-environment external delivery was captured instead of being sent

Test interception applies to external deliveries for Test events. In-app notices remain available for inspection. Use delivery records to verify Test behavior without assuming an email, webhook, push message or SMS reached an external recipient.

The email provider reports what happened to each message it accepted, and the delivery record follows:

  • Delivered. The delivery becomes delivered.
  • Bounced for good, or refused because the provider already knows the address fails. The delivery becomes dead_letter and email to you stops until you confirm a different address. A temporary bounce changes nothing, because the provider is still trying.
  • Reported as spam. Email to you stops until you turn an email preference back on.
  • Failed. The provider gave up on that one message. The delivery becomes dead_letter; later email is unaffected.

Each report is recorded once, however often the provider sends it.

A text goes only to a phone number you confirmed, and only after you turn SMS on for yourself. Installations send texts through Amazon SNS. SNS reports delivery to the installation’s own logs rather than back to Katara, so an accepted text stays accepted.

Katara sends one person at most 20 messages a minute on each channel. A single producer fans out at most 1,000 notices a minute in one environment, or 10,000 a minute across account notices. A notice over a limit waits for the next minute; none are dropped.

A webhook belongs to one signed-in organization administrator and one environment. Create it with an HTTPS destination you control and an explicit list of event types. The API family is /katara/v1/notification-webhooks; the SDK exposes createNotificationWebhook / create_notification_webhook and related methods.

  1. Generate an ID and preserve the exact creation body after an uncertain response. Setup returns the ownership document, verification URL, challenge expiry and a one-time signing secret. Store the secret in your receiving service; the API will not reveal it again on a retry.
  2. Serve the returned ownership document at the exact verification URL. Select Verify to request an ownership check. This reads the document; it does not send a notification.
  3. Review the destination, environment and event types. Submit the returned current version and review_digest to activate that exact configuration.
  4. Verify signatures in your receiving service before accepting a payload. Keep the ownership document available: delivery checks continued control of the endpoint.

Setup changes require a person’s signed-in session and current organization administrator access. API keys cannot administer a person’s webhook. Test events are intercepted rather than sent to the endpoint.

Verification, review, revocation and signing-key rotation use the current subscription version. Reload after a conflict. After an uncertain rotation, fetch current metadata rather than repeating the rotation automatically; a lost new secret requires another explicitly reviewed rotation. Existing delivery attempts keep their original signing-key version.

The TypeScript and Python SDKs snapshot webhook creation, webhook review and preference updates before resolving session credentials. The transmitted body keeps the reviewed destination, event list, scope, digest and version even if the caller’s object changes while authentication is pending. These operations do not use a caller idempotency header, and neither SDK retries them automatically.

After a lost preference response, reload preferences in the original scope and compare the saved version and settings before reviewing another update. After a lost webhook review response, inspect that exact subscription before deciding whether a new review is needed. Do not substitute a newer version or digest into an uncertain request. Recovery metadata must exclude the one-time signing secret; keep that secret only in the receiving service’s protected configuration.

The signing secret is an unpadded URL-safe base64 encoding of 32 bytes. Decode it before computing HMAC-SHA256. The signed bytes are the ASCII Unix timestamp, a dot, the delivery ID, another dot, and the exact raw JSON request body. Katara-Signature contains t=<timestamp>,v1=<lowercase hex>. Katara-Key-Id selects the key; Katara-Delivery-Id and Idempotency-Key contain the delivery ID. Compare signatures in constant time, reject timestamps older than five minutes or more than 30 seconds ahead, and deduplicate the delivery ID before applying an effect.

Return HTTP 200 or 202 with JSON {"delivery_id":"<received UUID>","status":"accepted"} after accepting the delivery. This confirms receipt, not completion of your downstream work. HTTP 429 or 503 with the same ID and "status":"retry" asserts that no effect occurred and permits a bounded retry. HTTP 400, 401, 403 or 410 with the same ID and "status":"rejected" is permanent.

An uncertain send after bytes may have reached the receiver is recorded as unknown and is not automatically resent. Arbitrary error replies and invalid acknowledgements also leave the outcome unknown.

Delivery recovery requires a separate, scoped operator enrollment provisioned by a trusted administrator of the installation. Organization ownership does not grant this permission. Enrollments identify one human account, an exact environment and reset generation, a fixed version, and an explicit expiry. Revocation is one-way. The provisioner’s database identity and server time are recorded privately.

A signed-in operator can review a delivery with its enrollment ID and version. The service checks current organization membership, recipient and source access while producing the review. Only a dead-letter delivery, or the leader of its frozen digest, can be explicitly queued again. Unknown sends remain ineligible. Test external delivery stays intercepted.

client.notificationRecovery.deliveries(scope, enrollmentID, version) lists the dead-lettered deliveries in the environment, newest first, up to 25 a page. Each is checked as its review would be, and one whose recipient may no longer receive the event is left out, so a page can be short while next_cursor is present. Use client.notificationRecovery.review(scope, deliveryID, enrollmentID, version) in TypeScript, then explicitly call redeliver(scope, review, operationUUID) after reviewing the returned metadata. Python exposes client.notification_recovery. The operation UUID is the request’s idempotency key. Preserve it and the exact review after an uncertain reply. Use receipt(scope, operationUUID, review) to inspect completion before an explicit same-request retry. Changed delivery, enrollment, scope or reset pins cannot reuse that operation.

The portal’s Notification Recovery page stores only the reviewed identifiers, versions, states and timestamps in tab storage, scoped to the signed-in account and environment. It never retries automatically. A historical receipt records a queue transition; it does not prove current delivery or current operator access. Reading it still requires current account and tenant visibility. New recovery must remain authorized through transaction completion, including time spent waiting for conflicting requests.

A recovery operator works in one environment. A notice to your own account belongs to no organization, and a notice whose fan-out ran out of attempts reached nobody, so neither has an operator of its own. Katara support resends those under a support access grant for your environment or your account: the grant names the reason and a deadline, and each look at the dead letters and each resend is on its record. A resent delivery goes back into its channel’s queue, where access, preferences and suppressions are checked again before anything is sent. A resent push goes to the devices you have now, not the ones the first attempt found.