TeamcenterKnowledge

Skills

TC Subscriptions

Skill tc-subscriptions. Set up and troubleshoot Teamcenter subscriptions (subscribe/notify/unsubscribe) over SOA, and keep the delivery daemons running. Covers the notification pipeline (event -> queue -> subscriptionmgrd -> email/news feed), the "Event Table renders blank until you press Find" trap that looks exactly like a broken daemon, making subscriptionmgrd/actionmgrd survive a reboot with a scheduled task, and the verified SOA operation set including the real unsubscribe call. Use for any "why didn't I get notified" investigation, or for authoring/reading subscriptions programmatically.

Verified live against the Saber 2.0 tier (TC 2506, server 25060.0004.0000.2025100200) over the JSON REST SOA binding. Source docs: plm00035 Subscription Management and my_teamcenter Teamcenter Basics on the local Help Server.

What a subscription is

A user request to be notified when an event happens on an object (object based) or on any object of a type (class based). The object is ImanSubscription, carrying a target, subscriber, ImanEventType, and an ordered list of ImanActionHandler. Class-based subscriptions target an ImanType and can be filtered by attribute criteria or a Condition — not both.

How delivery ACTUALLY works

There is no push endpoint. No webhook, no callback, no socket. The chain is:

event on a subscribed object
  -> TcEvent row written to a queue table
  -> subscriptionmgrd daemon sweeps (TC_subscriptionmgrd_sleep_minutes, doc default 10)
  -> delivers per SCM_notification_mode
       1 = email (IMAN_Smtp_Mail_Notify handler)
       2 = news feed (an Fnd0Message in the user's feed)
       3 = both

SCM_notification_mode is the single most important preference to check before promising anyone they will be notified. On Saber 2.0 it is 2, so no email is ever sent there even though IMAN_Smtp_Mail_Notify is the only registered handler. actionmgrd handles delayed executions and handler retries.

Troubleshooting "I get no notifications"

Three causes look identical from the outside. Separate them with evidence:

Cause How to prove it
The event never happened verify the state actually changed, e.g. checked_out really flipped
Event happened, nothing dispatched it the audit log has the event but no notification arrives
Dispatched, you read the wrong place check the other read path (news feed vs. email vs. getUnreadMessages)

The audit log is the key instrument. Teamcenter audits an event whether or not the subscription machinery does anything with it. Query the OOTB saved query Audit - General Logs with entries ["Name"], then read fnd0EventTypeName / fnd0PrimaryObjectID.

★★★ The trap that cost hours: the Event Table renders blank until you press Find

Subscription Administration > Event Table looks empty on open. It is not queried until you press Find. Two independent investigations concluded twice that event posting was broken because the table looked empty on load. Pressing Find revealed 20 backed-up TcEvent objects going back over a day, against a 1-minute sleep interval. Event posting had been fine the whole time — only consumption was dead, because subscriptionmgrd was not running.

Decision rule once the audit log confirms the event is real:

  • Event Table has rows (after pressing Find) → daemon not consuming → start it (see below).
  • Event Table genuinely empty after pressing Find → events not posted for this subscription → a server-side feature is likely missing (TEM: Server Enhancements > Subscription Manager Service + Action Manager Service; Active Workspace > Server Extensions > Subscription).

Starting the daemons, and making them survive a reboot

Binaries live in %TC_ROOT%\bin — they exist even on a 4-tier app host. Start manually:

call %TC_DATA%\tc_profilevars.bat
subscriptionmgrd -u=infodba -g=dba -pf=%TC_ROOT%\security\config1_infodba.pwf
actionmgrd       -u=infodba -g=dba -pf=%TC_ROOT%\security\config1_infodba.pwf

Use -pf with the existing encrypted password file, never -p — a plaintext -p puts the password on the command line and in shell history.

Reboot survival. These are plain console executables — they don't implement the Service Control Manager interface, so sc create can't register them (fails with error 1053). There is no general-purpose service wrapper in the install, and none of nssm/srvany/winsw was installed. The working route with no extra software is a scheduled task with a boot trigger running as SYSTEM:

$A = New-ScheduledTaskAction -Execute 'C:\Apps\Siemens\Teamcenter2506\daemons\run_subscriptionmgrd.bat'
$T = New-ScheduledTaskTrigger -AtStartup
$P = New-ScheduledTaskPrincipal -UserId 'SYSTEM' -LogonType ServiceAccount -RunLevel Highest
$S = New-ScheduledTaskSettingsSet -ExecutionTimeLimit ([TimeSpan]::Zero) -MultipleInstances IgnoreNew -RestartCount 3 -RestartInterval (New-TimeSpan -Minutes 1)
Register-ScheduledTask -TaskName 'Teamcenter Subscription Manager Daemon' -Action $A -Trigger $T -Principal $P -Settings $S -Force

Two gotchas:

  • Register via PowerShell, not schtasks. schtasks defaults ExecutionTimeLimit to 72 hours and would silently kill a long-running daemon after three days. PT0S (via [TimeSpan]::Zero) means unlimited.
  • SYSTEM is what makes it password-free. -LogonType ServiceAccount stores no credential, and TC_ROOT/TC_DATA are machine-level env vars, so a SYSTEM process inherits them. Point each task at a small wrapper .bat that calls tc_profilevars.bat then the daemon, so the environment is guaranteed.

Verify:

Get-ScheduledTask 'Teamcenter *Daemon' | Select TaskName,State
# should show Running, trigger MSFT_TaskBootTrigger, principal SYSTEM / ServiceAccount, ExecutionTimeLimit PT0S

Get-WmiObject Win32_Process -Filter "Name='subscriptionmgrd.exe' or Name='actionmgrd.exe'" |
  ForEach-Object { '{0} pid={1} owner={2}' -f $_.Name,$_.ProcessId,$_.GetOwner().User }

Measured result after applying this fix: 20 queued events drained within seconds and every notification arrived.

The SOA API — verified live

Task Operation
List subscribable types (5,467 on this tier) Internal-Notification-2015-03-SubscriptionManagement/getSubscribableTypes {"childTypeOption":"subtypes"}
Valid events + handlers for a target Internal-Notification-2015-03-SubscriptionManagement/getSubscriptionInput
Subscribe Notification-2014-10-SubscriptionManagement/createSubscriptions
Read my subscriptions Notification-2014-10-SubscriptionManagement/getSubscriptions
Modify Notification-2014-10-SubscriptionManagement/modifySubscriptions
Unsubscribe Core-2006-03-DataManagement/deleteObjects
News feed Query-2006-03-SavedQuery/executeSavedQuery over OOTB __Subscription - Messages for User
Unread messages Internal-Notification-2015-10-MessageManagement/getUnreadMessages
Site settings Administration-2012-09-PreferenceManagement/getPreferences

Traps that each cost real time

  • Internal-Notification-2015-10-SubscriptionManagement/unsubscribe is NOT the unsubscribe call. On a subscription the caller owns, it returns a partial error and leaves the subscription in place. Use deleteObjects instead.
  • getSubscriptions rejects JSON null. Optional model-object and date members need the NULLTAG uid AAAAAAAAAAAAAA and a NULLDATE string — send a literal null and you get HTTP 200 with "An error has occurred during the JSON parsing" (a payload-shape fault, not a real 4xx).
  • findSubscriptions faults where getSubscriptions succeeds on the exact same NULLTAG inputs — don't assume the two ops share a contract just because they sound like siblings.
  • The news feed saved query rejects its own declared field. __Subscription - Messages for User declares fnd0ApplicationType = Subscription Manager in its own definition, but passing that value (or the entry name, or an empty string) faults with "Invalid list of user entries". entries and values must both be sent empty.
  • fnd0TargetObject on a feed message comes back empty. The object is only identifiable by parsing fnd0MessageBody, a Key: value block: Subscription object / Subscription object type / Notification for event / Event initiated by / Time of event / Site name. The body field is fnd0MessageBody, not fnd0Message. Fnd0Message extends POM_object, so the OOTB General... saved query will never find it — a zero result there proves nothing about whether messages exist.
  • Silent successes (HTTP 200, no partial errors, nothing actually written): setProperties on Item properties; cancelCheckout (leaves checked_out = Y, and the still-reserved object then silently refuses to delete too). Use checkin to actually release a checkout, and always read the value back after any write to confirm it stuck. okToCheckout faults on body shape even in cases where checkout itself works fine.
  • Subscribable types return a synthetic uid like TYPE::ItemRevision::ItemRevision::WorkspaceObject, usable directly as a class-subscription target with typeName inline — don't try to resolve those uids with getProperties, they aren't real object uids.
  • Internal-Query-2008-06-Finder/findObjectsByClassAndAttributes returns 0 for every class, including populated ones — its zeros prove nothing. Same for Query-2014-11-Finder/performSearch against Sub0NotificationProvider / Sub0SubscriptionProvider.

★★★ Verified live 2026-08-06: Attach fires on BOTH the item and its revision

Subscribing Attach at only one level was an open question. Answered by a real Dispatcher run: when a translator (CapitalForward) attached its output dataset to an item revision, separate Attach feed messages fired for both the item-level target and the revision-level target — not one or the other, both, as independent events with their own timestamps. If a downstream consumer only subscribes at one level, it will still catch the event here, but don't assume that generalizes — subscribe both when the stakes are high enough to be worth the extra row. Same held for Check-In and Modify in the same test. Full narrative in the tc-dispatcher-kb memory.

★ Corollary bug this exposed in a real client (worth checking in any consumer you write): a dedup key built by slicing an event timestamp string to a fixed length, rather than parsing it, silently merges events that are minutes apart if the source format has more characters than expected (e.g. 06-Aug- 2026 19:59 is 17 chars, one longer than an ISO-format assumption of 16) — the truncated key collapses two genuinely different events into one and the second is dropped with no error. Parse the timestamp; don't slice it.

Admin preferences worth knowing

SCM_notification_mode (1/2/3 — email/news feed/both), TC_subscription (master ON/OFF), TC_subscriptionmgrd_sleep_minutes, TC_subscriptionmgrd_processing_hours (a time-window gate — a daemon that's running can still appear "dead" outside its processing window), AWS_Notifications_Polling_Interval (Active Workspace's own poll, default 5 min — distinct from the server-side sweep interval), SCM_notification_digest

  • SCM_execution_day/SCM_execution_time (daily/weekly digest scheduling), SCM_newsfeed_purge_threshold (+ the clear_old_newsfeed_messages utility), SCM_notification_history (an audit trail of sends, separate from the general audit log), AWC_followMultiObject_max and AWC_followMultiEventConfig_max (both default 5), TC_MESSAGING_MUX_URL (env var — required for alerts to reach the client at all; check this before debugging anything else if AW shows zero live alerts).

Install features (TEM): Active Workspace > Client > Subscription; Active Workspace > Server Extensions > Subscription; Server Enhancements > Action Manager Service; Server Enhancements > Subscription Manager Service. All four generally need to be present for the full subscribe/notify/unsubscribe loop to work end to end.

Reference implementation

A working Windows app exists at C:\Users\chris\Documents\Siemens\TcSubscriptions (PySide6 + Action Center toasts) implementing subscribe/notify/unsubscribe, detecting fires three ways (news feed, property polling, optional SMTP sink). Its README documents all of the above in more depth, and tools/prove_dispatch.py is a reusable diagnostic that fires a real event, confirms it via the audit log, and tells you which of the three "no notifications" causes above you actually have.

Related skills

tc-workflow-authoring (handlers are conceptually related — ImanActionHandler here vs. EPM task handlers there, but the two systems are separate), tc-soa-payload-shapes (the NULLTAG/NULLDATE pattern generalizes well beyond subscriptions), tc-query-discovery (saved-query traps generalize too).


Generated from skills/tc-subscriptions/SKILL.md in the tc-automation-skills library, which is the canonical copy and also serves as the agent skill set for Teamcenter work.