SfSkills Domains Docs GitHub

Home / integration / platform-events-integration

platform-events-integration

Use when publishing Platform Events from external systems via REST API, subscribing to Platform Events from outside Salesforce via CometD or Pub/Sub API, designing replay ID strategy for durable external consumers, or handling high-volume event delivery guarantees.

Open the skill folder on GitHub


Platform Events Integration

Use this skill when the integration boundary crosses outside Salesforce: an external system publishes Platform Events into Salesforce via REST, or a middleware consumer subscribes to events using CometD or the newer Pub/Sub API. The skill covers the full external connection lifecycle — auth, replay ID strategy, high-volume vs standard limits, delivery guarantees, and what to do when subscribers fall behind.


Before Starting


Core Concepts

Publishing From External Systems via REST

External systems publish Platform Events by POSTing to the Platform Event sObject REST endpoint:

POST /services/data/vXX.0/sobjects/OrderShipped__e/
Authorization: Bearer <access_token>
Content-Type: application/json

{ "OrderId__c": "801xx000001234", "ShippedDate__c": "2025-10-01T00:00:00Z" }

The response contains a replayId for the published event. Authentication uses standard OAuth 2.0 connected app flows — JWT bearer for server-to-server or User-Agent/Web Server for interactive flows. The REST endpoint imposes the same API governor limits as standard sObject REST calls.

Subscribing From External Systems: CometD vs Pub/Sub API

Two external subscription protocols exist:

CometD (Streaming API): Bayeux-protocol long-polling over HTTPS. Mature, supported in many enterprise middleware stacks. Requires managing handshake, re-subscribe after network disconnect, and replay extension (/meta/subscribe with replay extension field). CometD subscribers must reconnect after 40 seconds of inactivity; failure to reconnect within the replay window causes event loss.

Pub/Sub API: gRPC-based binary API introduced in Summer '22. Supports higher throughput, server-side schema fetch via Apache Avro, and bidirectional streaming. Preferred for new integrations where the middleware stack supports gRPC. Salesforce publishes client libraries for Java, Python, and Node. Auth is the same OAuth 2.0 flow used by REST.

The Pub/Sub API endpoint is separate from the standard instance URL: api.pubsub.salesforce.com:7443.

Replay ID: At-Least-Once Delivery and Durable Subscriptions

Platform Events deliver at-least-once. Every event has a replayId. External consumers must store the last successfully processed replayId durably (database, distributed cache) so they can resume from exactly where they left off after a disconnect or restart.

Three special replay ID values:

If a consumer starts fresh with -1 and fails during processing, events emitted during the outage are lost unless the consumer switches to -2 or a stored position on restart. Design consumers to store replay position before acknowledging processing completion.

High-Volume Platform Events vs Standard Platform Events

This is not a live design choice for new work. After Spring '19 you cannot define a new standard-volume platform event — every event you create in Setup is high-volume. Standard-volume events are a legacy population, and Salesforce is retiring publish and subscribe for them in Winter '27. If an org still has standard-volume events, the task is migration, not selection.

FeatureStandard-Volume (legacy)High-Volume (all new events)
Can be newly definedNo — not since Spring '19Yes (the only option)
Publish allocation per hour (org-wide)100,000 (EE / Perf / Unlimited); 1,000 (Dev, Prof w/ API add-on)250,000 (EE / Perf / Unlimited); 50,000 (Developer)
Event retention window24 hours72 hours
Retention configurableNoNo — 72 hours is fixed
Apex subscriber triggerSupportedSupported
External CometD/Pub/SubSupportedSupported
LifecycleRetiring in Winter '27Current

Two things this table exists to stop you assuming:

  1. The 250,000/hour figure is an org-wide publishing allocation, not a tier feature. It is the ceiling for high-volume events on Enterprise, Performance, and Unlimited. It is not "unlimited above 250k" — moving to a high-volume event does not buy additional hourly headroom beyond that allocation. Capacity plans must size against 250,000/hour and buy the add-on (+25,000/hour) if they need more.
  2. Retention is fixed at 72 hours and cannot be extended by any field or setting. For replay windows longer than 72 hours, the publisher must write a copy of each event to a durable store (Big Object, external queue) and the subscriber backfills from that store. See Pattern 3.

Common Patterns

Pattern 1 — External Publisher via REST with Idempotent Payload

When to use: An external order management or ERP system pushes domain events into Salesforce. The publisher controls event creation and timing.

How it works:

  1. Configure a Connected App with OAuth 2.0 JWT Bearer flow for the external system.
  2. Obtain an access token with the api scope (or the event-specific scope).
  3. POST to /services/data/vXX.0/sobjects/YourEvent__e/ with the event payload.
  4. Include a stable idempotency key field on the event (e.g., CorrelationId__c as a Text field). Apex or Flow subscribers can deduplicate on this key.
  5. Check the HTTP response for success: true and log the returned replayId if audit tracing is needed.

Why not the alternative: Polling a Salesforce query endpoint instead of publishing events couples the integration to Salesforce record shape and misses the decoupled event model.

Pattern 2 — Durable External Subscriber via Pub/Sub API

When to use: A middleware platform must process Salesforce-published events reliably, including recovery after planned maintenance windows or unplanned outages.

How it works:

  1. On first start, subscribe with -2 (earliest) to catch any events already in the retention window, or with a stored replayId if one exists.
  2. Fetch events in batches using the FetchRequest RPC. Pub/Sub API uses a request-credits model: send a FetchRequest with a num_requested count; the server streams responses until the credit is exhausted.
  3. After processing each batch, persist the highest replayId to durable storage before acknowledging or processing the next batch.
  4. On reconnect, always pass the last stored replayId. Never hardcode -1 except for throw-away consumers.
  5. Before replaying from an older stored replayId, use Pub/Sub API's GetTopic / GetSchema RPCs to confirm the schema version — a replayed event carries the schema ID that was current when it was published, which may predate the subscriber's cached schema.

Why not the alternative: CometD requires more client-side reconnect logic and is slower for high-throughput scenarios; Pub/Sub API handles backpressure natively through the credit model.

Pattern 3 — Dead-Letter Handling When Subscribers Fall Behind

When to use: A subscriber has been offline longer than the retention window (72 hours for high-volume events, 24 for standard-volume). Because the window is fixed and cannot be extended, this pattern is mandatory — not optional — for any subscriber whose worst-case outage exceeds three days.

How it works:

  1. Accept that events outside the retention window are permanently lost via normal replay.
  2. Implement a compensating mechanism: the publisher writes the same payload to a durable store (e.g., a Salesforce Platform Cache partition, a BigObject, or an external message queue) when publishing the event.
  3. On subscriber restart after a long outage, the subscriber reads from the durable store to backfill, then resumes live event subscription.
  4. Alternatively, design the subscriber to tolerate gaps by requesting a full-state sync from Salesforce (REST or Bulk API query) before resuming event consumption.

Decision Guidance

SituationRecommended ApproachReason
External system publishes business events into SalesforceREST POST to /sobjects/EventName__e/ with JWT authStandard REST endpoint, no special client library needed
New middleware subscriber, gRPC stack availablePub/Sub APIHigher throughput, Avro schema fetch, better backpressure
Legacy middleware already using Bayeux/CometDStreaming API CometDLess migration effort; still fully supported
Sustained publish rate approaching 250k/hourBuy the event add-on (+25,000/hour) and/or batch domain changes into fewer, coarser events250,000/hour is a hard org-wide allocation on EE/Perf/Unlimited; no event tier exceeds it
Org still has pre-Spring '19 standard-volume eventsMigrate them to high-volume events nowPublish and subscribe for standard-volume events are retired in Winter '27
Subscriber must recover after multi-day outagePublisher writes a durable copy (Big Object / external queue) + subscriber backfills from itThe 72-hour window is fixed and cannot be extended by any setting; backfill is the only path
Subscriber processing is not idempotentAdd correlation ID field + consumer-side dedup tableAt-least-once delivery means duplicates will arrive

Step-by-step instructions for an AI agent or practitioner activating this skill:

  1. Gather context — confirm the org edition, relevant objects, and current configuration state
  2. Review official sources — check the references in this skill's well-architected.md before making changes
  3. Implement or advise — apply the patterns from Core Concepts and Common Patterns sections above
  4. Validate — run the skill's checker script and verify against the Review Checklist below
  5. Document — record any deviations from standard patterns and update the template if needed

Review Checklist


Salesforce-Specific Gotchas

  1. There is no retention-extension field on any Platform Event — not RetainUntilDate, not anything else. Retention is a fixed platform property: 72 hours for high-volume events, 24 hours for legacy standard-volume events. Any design that assumes a publisher can push the expiry out will lose every event past the window, silently, with the subscriber seeing only a gap. Longer windows require a durable ledger written alongside the publish.
  2. CometD connections silently expire after 40 seconds of inactivity — clients must send /meta/connect heartbeats continuously or the server closes the channel without error, leading to missed events that appear as gaps in the subscriber.
  3. Pub/Sub API uses a credit-based flow model — if a client sends a FetchRequest and does not issue new credits after consuming the batch, the stream stalls. Middleware that expects a push model without managing credits will stop receiving events under load.
  4. At-least-once delivery means duplicates are guaranteed in retry scenarios — every external subscriber must be idempotent; not designing for duplicates is the most common production reliability bug.
  5. Replay IDs are not sequential integers across all events — they are opaque per-channel values. Do not subtract or compare replay IDs numerically to detect gaps; use the CometD or Pub/Sub API ordering guarantees instead.

Output Artifacts

ArtifactDescription
REST publish patternEndpoint URL, auth setup, and payload structure for external publishers
Subscriber design recommendationCometD vs Pub/Sub API choice, replay ID storage design, and backpressure handling
Event tier recommendationStandard vs High-Volume guidance based on throughput and retention requirements
Idempotency and dead-letter designCorrelation key field design and compensating backfill strategy

Package files