TL;DR
- When an external system subscribes to your platform events with Pub/Sub API, it normally stores its own replay position. That means the one piece of state governing how many events you are billed for lives in somebody else's codebase.
- A
ManagedEventSubscriptionmoves that state to the server. Salesforce tracks what the client consumed and resumes from the last committed replay ID, so a disconnect no longer risks a replay storm. - The
statefield takesRUNorSTOP, which gives you a stop switch inside your own org. You no longer have to email a partner and wait when their client is consuming your allocation. - Be clear on what it does not do: managed subscriptions carry the same allocations as an ordinary subscribe. They remove waste, they do not give you a discount.
- The thing that genuinely reduces the count is a custom channel with a filter expression, because only matching events are delivered and counted. Managed subscription plus filtered channel is the pattern worth standardising on.
- It is still Beta, under Salesforce's Beta Services Terms, at API v67.0. That is a real consideration and this post treats it as one rather than a footnote.
What You'll Learn
- Why client-side replay management is the weak point in most external event integrations
- What a
ManagedEventSubscriptionactually changes, field by field - How platform event delivery allocations are counted, and what does and does not count
- The replay storm that can consume most of a day's allocation in one reconnect
- Which lever actually reduces delivery counts, and how to combine it with managed subscriptions
- How to decide whether Beta status should stop you
The Problem
You publish platform events. A partner system, a middleware platform, or your own service running outside Salesforce subscribes to them through Pub/Sub API. It works, and then one of two things happens.
The first is that the subscriber disconnects, comes back, and does something unhelpful with its replay position. The replay ID is a pointer into the event bus that says "I have read up to here". If the client stored it badly, lost it during a deploy, or handles the invalid-replay case by starting from the earliest available event, it re-reads up to 72 hours of history. Every one of those redelivered events counts against your daily allocation again.
The second is that you discover this after the fact, from a usage graph rather than an alert, and find you have no way to stop it. The subscription lives in the client. Stopping it means finding out who owns that system, explaining the problem, and waiting for them to deploy a change. In the meantime your allocation is being consumed and other subscribers, including your own Lightning components, start missing events.
Both problems have the same root. The control plane for the subscription sits outside your org.
Common questions this article answers:
- Where does the replay position live, and why does it matter for cost?
- Do managed subscriptions reduce my event delivery allocation usage?
- How do I stop a runaway external subscriber without involving the partner?
Quick Answer
Use a ManagedEventSubscription for any external system subscribing to your platform events through Pub/Sub API. It moves replay tracking from the client to the server, so a client that disconnects resumes after the last replay ID it successfully committed rather than guessing, and you configure what happens when a replay ID falls outside the 72-hour retention window through errorRecoveryReplay instead of inheriting someone else's error handling. It also gives you state, which takes RUN or STOP, so you can halt delivery from Setup rather than asking a partner to redeploy. Create it through the Tooling API or Metadata API, which needs Customize Application, so subscribing becomes a governed change rather than something a partner does with credentials alone. Understand the limits honestly: managed subscriptions have the same allocations as an ordinary subscribe and there is a cap of 200 per org, each unique to one client. If you need to reduce the number of events counted, that comes from a custom channel with a filter expression, because only matching events are delivered and only those count. The feature is still Beta under Salesforce's Beta Services Terms.
How the delivery allocation is actually counted
Before the argument for managed subscriptions makes sense, the cost model has to be clear, because it is counted in a way that surprises people.
Daily event delivery allocations, on a rolling 24-hour window:
| Edition | Events delivered per 24 hours |
|---|---|
| Performance and Unlimited | 50,000 |
| Enterprise | 25,000 |
| Professional (with API add-on) | 25,000 |
| Developer | 10,000 |
The number that matters is not how many events you publish. It is how many are delivered, counted separately for each subscribed client. Publish one event with four subscribers and you have consumed four deliveries. Add a fifth subscriber and every event you publish gets 25 percent more expensive, without a line of publishing code changing.
What counts against the allocation:
- Pub/Sub API subscribers
- CometD clients
empApiLightning components- Event relays
What does not count:
- Apex triggers
- Flows
- Process Builder processes
That last list is why teams underestimate this. Internal automation subscribing to your events is free, so a design that looks cheap in a sandbox full of Apex subscribers gets expensive the moment external clients and Lightning components attach to the same channel. The Lightning side of this problem, where a single user with several tabs open multiplies deliveries, is its own trap and we covered it in How we reduced platform event delivery costs by 60%. This post is the external counterpart.
A platform events add-on license raises the daily allocation by 100,000 and shifts you to a monthly usage-based model rather than strict daily enforcement, which is worth knowing before you architect around a hard 25,000.
The replay storm
Here is the failure mode that justifies the whole argument.
The Salesforce event bus retains events for 72 hours. A subscriber holds a replay ID marking its position. When a client reconnects, it presents that replay ID and resumes from there.
Now suppose the client cannot. Its stored replay ID is older than the retention window, or the value was lost in a restart, or it was never persisted properly in the first place because the original developer treated it as an in-memory variable. Many clients handle this by falling back to the earliest available event, because that is the option that loses no data and therefore looks like the safe choice.
Consider an Enterprise org with a 25,000 daily allocation, publishing 8,000 events a day. Over the 72-hour retention window that is roughly 24,000 events sitting in the bus. A single client that falls back to earliest re-consumes all 24,000, and that is your entire day's allocation gone in one reconnect, for events every other subscriber already received correctly. Your Lightning components stop getting deliveries. Your other integrations stop getting deliveries. Nothing in your org caused it and nothing in your org can stop it.
The reason this is worth dwelling on is that it is not an exotic edge case. It is the default behaviour of a reasonable-looking client written by somebody who was optimising for not losing events, which is the correct instinct applied without knowledge of your allocation.
What a managed subscription changes
A ManagedEventSubscription is a metadata object in your org that describes a subscription. The client then connects using the ManagedSubscribe RPC instead of Subscribe, and Salesforce keeps the state.
Four fields carry the behaviour:
| Field | Values | What it controls |
|---|---|---|
topicName |
e.g. /event/Order_Event__e |
The channel being subscribed to |
defaultReplay |
LATEST or EARLIEST |
Where a brand new subscription starts |
state |
RUN or STOP |
Whether the subscription delivers at all |
errorRecoveryReplay |
LATEST or EARLIEST |
Where to resume if the stored replay ID is no longer valid |
Read that table against the replay storm above and the value is obvious. errorRecoveryReplay is the decision that used to live in a partner's exception handler, and it is now a field in your org. Set it to LATEST and a client whose position has expired resumes at the head of the stream, skipping the backlog, rather than re-reading three days of history at your expense. You may not always want that, and for some workloads you genuinely do want EARLIEST, but it becomes your decision made deliberately rather than their default inherited silently.
The commit model underneath is what makes it safe. The client still commits a replay ID as it processes, and Salesforce stores that server-side. After a disconnect the subscription resumes after the last replay ID the client successfully committed, so this is not "Salesforce guesses where you were". It is the same at-least-once contract, with the bookkeeping moved somewhere you can see it.
The stop switch
state deserves separate treatment because it is the operational argument, and operations is where these integrations actually hurt.
Setting state to STOP halts delivery for that subscription. You do it in your own org, through the Tooling API or Metadata API, with no involvement from whoever owns the client.
Think about what that replaces. Today, an external subscriber consuming your allocation is handled by working out which system it is, finding an owner, explaining a Salesforce-specific cost model to somebody who does not work in Salesforce, and waiting for a deploy. That is hours at best. With state, it is one call, reversible, and you can bring the subscription back with RUN once the client is fixed, at which point it resumes from its committed position rather than starting over.
This also gives you something to put in a runbook. "If platform event delivery usage exceeds 70 percent before midday, stop the non-critical managed subscriptions in this order" is an actual instruction someone on call can follow. Without managed subscriptions the equivalent runbook entry is "escalate to the integration team", which is not a control.
What managed subscriptions do not do
Be clear about this, because it is the thing most likely to be misremembered.
They do not reduce your delivery allocation usage. Salesforce's allocations documentation says plainly that managed subscriptions have the same allocations as subscriptions using the Subscribe RPC method. One delivered event to one managed subscription costs exactly what one delivered event to an ordinary subscription costs.
What they remove is waste: the redelivered backlog, the duplicate subscription nobody knew about, the client that reconnects in a loop. Those are large in practice, and in a bad week they dwarf your legitimate traffic. But the mechanism is governance, not a cheaper rate, and a post that told you otherwise would set you up to miss your budget.
Two other limits to design around:
- 200 managed subscriptions per org. Generous for most, but if you were imagining one per tenant in a multi-tenant product, count first.
- Unique per client, not shareable. A managed subscription is tied to one subscriber client and cannot be shared across clients in the same org. If your consumer is a horizontally scaled cluster, work out how that maps before committing to the design, because it is not simply "point all six instances at the same subscription".
What actually cuts the count
If the goal is fewer delivered events rather than better control of them, the lever is a custom channel with a filter expression.
You create a channel, add your event as a channel member, and define a filter on event fields. Subscribers to that channel receive only events matching the filter, and this is the important part: the event delivery usage counted against your allocation is reduced to only the filtered events that match. The filtering happens before delivery, so unmatched events never cost you anything.
A worked example. Suppose Order_Event__e fires for every order across every region, 8,000 a day, and your Australian partner's system only cares about orders in its own region, which is 15 percent of the volume. Subscribed to the raw event, that partner costs you 8,000 deliveries a day. Subscribed to a filtered channel, it costs 1,200. You have removed 6,800 daily deliveries by configuration, without asking the partner to change anything except the channel they connect to.
Stream filtering is supported for custom platform events and change data capture events, and only for Pub/Sub API and CometD clients, which covers exactly the external-subscriber case this post is about.
The other two levers are less elegant and still worth checking:
- Consolidate duplicate subscribers. Two teams independently subscribing to the same channel for overlapping reasons is common and doubles the cost of that channel. One subscriber fanning out internally is cheaper.
- Do not subscribe to what you do not process. A client that subscribes to a broad channel and discards most of what arrives is paying full price to throw events away. That is a filtered channel waiting to be created.
The pattern worth standardising on
Put the pieces together and the recommendation is specific rather than "use managed subscriptions".
For each external system that needs your events:
- Create a custom channel with a filter expression scoped to what that consumer actually processes. This is where the delivery count drops.
- Create a
ManagedEventSubscriptionon that channel for that client. This is where the replay state and the stop switch come from. - Set
errorRecoveryReplaydeliberately.LATESTfor anything where a three-day backlog would do more harm than good, which is most operational integrations.EARLIESTonly where you genuinely need completeness and have the allocation headroom to survive a recovery. - Give the client its own connected app and integration user, with least privilege, so you can attribute usage and revoke access independently of the subscription. The same argument we make in Connected app least privilege: granted versus used applies here directly.
- Record the subscription in version control as metadata, so the set of external subscribers is reviewable rather than discovered.
Step five is quietly the biggest cultural change. Without managed subscriptions, "who subscribes to our events?" is answered by asking around. With them, it is a query. That alone tends to surface one or two subscribers nobody remembered authorising.
Setting one up
Create it with a POST to the Tooling API:
curl -X POST \
"https://yourcompany.my.salesforce.com/services/data/v67.0/tooling/sobjects/ManagedEventSubscription" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"FullName": "Partner_Order_Sync",
"Metadata": {
"label": "Partner Order Sync",
"topicName": "/event/Order_Event__e",
"defaultReplay": "LATEST",
"state": "RUN",
"errorRecoveryReplay": "LATEST"
}
}'
Stopping it later is a PATCH to the same object with state set to STOP.
Two access notes worth planning around. Viewing a ManagedEventSubscription needs View Setup and Configuration. Creating, updating or deleting one needs Customize Application, which is a heavy permission and not one to hand out so a partner can self-serve. Treat subscription creation as a change your team makes on request, which is the governance benefit rather than an inconvenience to engineer around.
Because it is a metadata type, it also retrieves and deploys like anything else, so it belongs in your repository alongside the events themselves.
The Beta question
Managed event subscriptions are still Beta, at API v67.0, and Salesforce's Beta Services Terms apply. Recommending a Beta feature as a default pattern needs justifying rather than glossing.
What Beta means concretely: no guarantee of general availability, no guarantee the interface stays as it is, and support handled outside the normal production support commitments. Salesforce has kept this one in Beta since API v60.0, which is a long run and can be read either way. It suggests stability of the design, and it also means the promotion to GA has not happened.
The case for adopting now anyway rests on the shape of the risk. The surface area is four fields and one RPC. If the interface changed, the migration is re-creating subscription records, not rewriting your consumer. Your event contract, your channel design and your client's processing logic are untouched by the managed-versus-unmanaged decision, because the client still receives the same events over the same API. That is a genuinely small blast radius.
Where I would be careful:
- Anything with a contractual delivery obligation to a customer. If a missed event breaches an SLA, Beta Services Terms are the wrong place to be standing.
- Regulated workloads where you need a supported configuration on paper for an audit.
- Anything you cannot re-drive. If a gap in delivery cannot be repaired by replaying from your own system of record, do not put it on Beta infrastructure.
For everything else, which is most internal and partner integrations, the control you gain today outweighs a migration risk measured in re-creating a handful of records. Write down which subscriptions are on it, so that if the terms change you know your exposure in minutes rather than auditing.
What to tell the partner team
The people on the other end need a short, specific brief, and it should be about what changes for them rather than about your allocation:
We are moving your subscription to our Salesforce events onto a managed subscription. For your client, one thing changes: connect using the
ManagedSubscribeRPC with the subscription name we will give you, instead ofSubscribewith a topic name and a replay ID you store.You can stop persisting the replay ID. We track your position on our side from the replay IDs your client commits as it processes, so a restart or a deploy on your end resumes where you left off rather than from a stored value that may have gone stale. Keep committing as you process, because that is what we track.
We will also point you at a filtered channel rather than the raw event, so you receive only the records in scope for your integration and not the full stream.
If we ever need to pause delivery during an incident, we can now do that from our side and resume it afterwards without asking you to deploy. We will tell you when that happens.
That last paragraph matters. A stop switch you use without warning reads as an outage on their side, so say up front that it exists and that you will communicate. The control is worth more when it is not a surprise.
Frequently Asked Questions
Q: Do managed subscriptions reduce my platform event delivery allocation usage?
A: No. Salesforce states that managed subscriptions have the same allocations as subscriptions using the Subscribe RPC method. They reduce waste rather than the per-event cost, by preventing replay storms and duplicate subscriptions and by giving you a stop switch. If you want fewer delivered events counted, use a custom channel with a filter expression, which reduces the counted usage to only matching events.
Q: What happens if the client's stored position falls outside the retention window?
A: The event bus retains events for 72 hours. If the replay ID is no longer valid, the subscription restarts according to the errorRecoveryReplay setting on the subscription, which you configure as LATEST or EARLIEST. This is the whole point: the decision is yours rather than the client's error handler's.
Q: Can several instances of the same client share one managed subscription?
A: No. A managed subscription is unique per client and cannot be shared across clients in the same org. If your consumer is a horizontally scaled cluster, design for that explicitly before adopting the pattern, and check your total against the 200 per-org cap.
Q: Does this replace event relays?
A: No, they solve different problems. An event relay forwards events to Amazon EventBridge and is the right choice when the consuming architecture is already on AWS. A managed subscription is for a client that connects to Pub/Sub API directly. Note that relays count against your delivery allocation the same way any other subscriber does.
Q: Should I use this for internal Apex or Flow subscribers?
A: No, and they do not need it. Apex triggers, Flows and Process Builder subscribe inside the platform, are not Pub/Sub API clients, and do not count against the delivery allocation at all. Managed subscriptions are for external clients.
Q: Is it safe to build on while it is Beta?
A: It depends on the workload rather than on the feature. The interface is four fields and one RPC, so a breaking change means re-creating subscription records rather than rewriting your consumer. That is acceptable for most partner and internal integrations. Keep it away from anything with a contractual delivery SLA, a regulatory audit requirement, or events you cannot re-drive from your own system of record.
Key Takeaways
- The replay position is the control plane, and by default it lives in somebody else's codebase. A managed subscription moves it into your org.
- A single client falling back to earliest can consume a day's allocation, because 72 hours of retained events get redelivered and counted again.
state: STOPis the operational win. It converts "escalate to the integration team" into a runbook step you can execute yourself.- Managed subscriptions do not lower your allocation. They remove waste. Filtered custom channels are what reduce the counted delivery volume.
- Standardise on the combination: filtered channel for cost, managed subscription for control, dedicated integration user for attribution.
- It is Beta, and the blast radius is small, but keep it off workloads with contractual delivery obligations or audit requirements.
What's Next?
Recommended Reading:
- Platform event delivery limits: how to measure, attribute and cut usage for the generally available levers, if Beta is not an option for you
- How we reduced platform event delivery costs by 60% for the Lightning side of the same allocation problem
- Connected app least privilege: granted versus used
- Free event monitoring with EventLogFile for building the usage baseline this post assumes
- Salesforce Retires the OAuth Username-Password Flow in Winter '27
- Migrating legacy Named Credentials for the credential side of the same integration review
Action Items:
- Work out your current delivery usage against your edition's allocation, and list every external client subscribing today along with who owns it.
- For the noisiest consumer, create a filtered custom channel scoped to what it actually processes, and measure the drop in counted deliveries.
- Move that consumer onto a
ManagedEventSubscriptionwitherrorRecoveryReplayset deliberately, commit the metadata to version control, and add a stop-switch step to your platform event runbook.
Resources & References
- Managed Event Subscriptions, Beta (Pub/Sub API Developer Guide)
- ManagedEventSubscription (Tooling API Developer Guide)
- Pub/Sub API Allocations
- Platform Event Allocations (Platform Events Developer Guide)
- Filter Your Stream of Platform Events with Custom Channels
- Create a ManagedEventSubscription with Tooling API (Quick Start)