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.schtasksdefaultsExecutionTimeLimitto 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 ServiceAccountstores no credential, andTC_ROOT/TC_DATAare machine-level env vars, so a SYSTEM process inherits them. Point each task at a small wrapper.batthat callstc_profilevars.batthen 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/unsubscribeis NOT the unsubscribe call. On a subscription the caller owns, it returns a partial error and leaves the subscription in place. UsedeleteObjectsinstead.getSubscriptionsrejects JSONnull. Optional model-object and date members need the NULLTAG uidAAAAAAAAAAAAAAand a NULLDATE string — send a literalnulland you get HTTP 200 with "An error has occurred during the JSON parsing" (a payload-shape fault, not a real 4xx).findSubscriptionsfaults wheregetSubscriptionssucceeds 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 Userdeclaresfnd0ApplicationType = Subscription Managerin its own definition, but passing that value (or the entry name, or an empty string) faults with "Invalid list of user entries".entriesandvaluesmust both be sent empty. fnd0TargetObjecton a feed message comes back empty. The object is only identifiable by parsingfnd0MessageBody, aKey: valueblock: Subscription object / Subscription object type / Notification for event / Event initiated by / Time of event / Site name. The body field isfnd0MessageBody, notfnd0Message.Fnd0MessageextendsPOM_object, so the OOTBGeneral...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):
setPropertieson Item properties;cancelCheckout(leaveschecked_out = Y, and the still-reserved object then silently refuses to delete too). Usecheckinto actually release a checkout, and always read the value back after any write to confirm it stuck.okToCheckoutfaults on body shape even in cases wherecheckoutitself works fine. - Subscribable types return a synthetic uid like
TYPE::ItemRevision::ItemRevision::WorkspaceObject, usable directly as a class-subscription target withtypeNameinline — don't try to resolve those uids withgetProperties, they aren't real object uids. Internal-Query-2008-06-Finder/findObjectsByClassAndAttributesreturns 0 for every class, including populated ones — its zeros prove nothing. Same forQuery-2014-11-Finder/performSearchagainstSub0NotificationProvider/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(+ theclear_old_newsfeed_messagesutility),SCM_notification_history(an audit trail of sends, separate from the general audit log),AWC_followMultiObject_maxandAWC_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.