The Return Receipt
Module 5 of 9 in the chapter Reliability, Recovery, and Observability, chapter 14 of the Integration Architect course. Each module stands on its own. Previous: Retries Without Duplicates · Next: Escalation and Recovery
The question this module answers: How does the sender know a message actually arrived, not just that it was sent?
Registered Mail
Section titled “Registered Mail”When you send something important by post, you don’t just drop it in the box. You send it registered, with a return receipt. You keep your copy, and a card comes back, signed by the person who received it. If the card doesn’t come back, you know to follow up.
That’s the design I’ve come to trust most for proving delivery, and I’ve compared it with other architects who arrived at the same place. When a delivery’s status changes, Salesforce writes a small local notification record and publishes a platform event. The integration layer picks up the event and delivers it to the partner. And once it’s delivered, the integration layer calls back into Salesforce and marks the notification delivered. That’s the card coming back. A small batch job looks for notifications with no receipt after, say, three hours, and sends them again.
The Data Architect course walks through it on exactly this arrow, Steve Trucking’s status out to Redrock, in three drawings: send, sign, sweep (Proof of Delivery). Go there for the walk-through. This module is what an integration architect adds: the name the industry gives it, why the record must be saved with the change, what “sent” really means, and when an arrow needs a receipt at all.
Why a Platform Event Alone Isn’t Enough
Section titled “Why a Platform Event Alone Isn’t Enough”The event bus is a good road. It keeps events for 72 hours, and a subscriber that drops off asks for everything after the last one it saw (chapter 11 module 4). So why build anything more?
Because Salesforce is honest about the fine print. Publishing is asynchronous, and “In rare cases, the event message might not be persisted in the distributed system during the initial or subsequent attempts. This means that the events aren’t delivered to subscribers, and they aren’t recoverable.” And publishing “uses the at-least-once pub/sub model, not the exactly-once model”, so once in a while an event arrives twice.
Rare isn’t never. And past the 72 hours, a subscriber that was down too long can’t replay what it missed. If the business has to know every status reached Redrock, the event bus alone can’t tell you. You need your own record of what you sent, and someone to sign for it.
Notice something else in that design. Publishing an event isn’t a callout. Salesforce doesn’t have to know Redrock’s address, its credentials, or how to retry. The integration layer does the calling. But I still track it locally, on the Salesforce side, because Salesforce is the one that needs to know.
The Industry’s Name: the Outbox
Section titled “The Industry’s Name: the Outbox”This isn’t only my design. The industry has a name for its first half: the transactional outbox. Chris Richardson’s pattern catalog puts it in two sentences: “The solution is for the service that sends the message to first store the message in the database as part of the transaction that updates the business entities. A separate process then sends the messages to the message broker.”
The key words are as part of the transaction. The notification record has to be saved in the same transaction as the change it reports. Then the two can’t disagree. If the status change commits, the notification commits with it. If the save fails and rolls back, the notification rolls back too. The pattern’s own claim: “Messages are guaranteed to be sent if and only if the database transaction commits.”
Compare that with publishing on its own. Choose Publish Immediately, and the event goes out “regardless of whether the transaction succeeds”, so Redrock can hear about a delivery that was never saved. Choose Publish After Commit, and the event waits for the save, but if that one event is among the rare few that isn’t stored, nothing on your side remembers it existed. The outbox closes both gaps: the record is the memory, and it lives and dies with the change.
Saved with the change, or not at all.
The outbox makes sure the message gets sent. The second half of my design, the receipt, makes sure it arrived. And the third piece is on the far side: because the sweep can send a status again, the receiver has to be safe to receive it twice. Enterprise Integration Patterns calls that an idempotent receiver: “one that can safely receive the same message multiple times.” Module 4 showed how: the ID that travels with the status, and the time of the change for the order (module 4).
Outbox, receipt, idempotent receiver. Three names for the three parts of registered mail: your copy, the signed card, and the clerk who doesn’t stamp the same letter twice.
Three Kinds of Sent
Section titled “Three Kinds of Sent”Here’s a question I like to ask: when Salesforce says an event was “sent,” what does it actually know? There are three different answers, and they’re easy to mix up.
Queued. When Apex publishes, the immediate answer only says the request was accepted for publishing. Salesforce’s guide: “Without the callback, you can get only the intermediate queueing result in Database.SaveResult of an EventBus.publish call, not the final result.” Chapter 11 called this “published means queued” (chapter 11 module 3).
Published. For the final answer from the bus, Salesforce gives you Apex publish callbacks: a class implementing EventBus.EventPublishSuccessCallback or EventBus.EventPublishFailureCallback, called when the publish finally succeeds or fails. The event’s EventUuid “is used to match the events returned in the callback result with the events in the publish call.” So a failed publish can mark its notification failed, or publish it again, at once, instead of waiting for the sweep. They’re available for high-volume platform events.
Delivered. Neither of those tells you Redrock got it. A successful publish means the bus has the event. Only the receipt, the integration layer’s call back after Redrock accepted the status, means it was delivered.
Published isn’t delivered.
So when someone in a design review says “we know it was sent,” ask them which of the three they mean.
Test knowledge. Know that platform event publishing is asynchronous and at least once: the
SaveResultofEventBus.publishis only the queueing result, Apex publish callbacks give the final result (high-volume events), and in rare cases an event isn’t persisted and “aren’t recoverable.” Know that proof of delivery needs your own tracking: a record of what was sent, saved with the change, and an acknowledgment back.
Receipts Already Built In
Section titled “Receipts Already Built In”Once you start looking for return receipts, you find them all over integration. Some protocols were built with one.
Files. A file written to a partner’s folder isn’t delivered. It’s just there. For Steve Trucking’s nightly status file to Keystone, the contract says plainly: “a file isn’t proof; Keystone’s pickup or acknowledgment is, and a missing one is chased by morning” (chapter 10 module 6). The pickup is the receipt.
EDI. Business-to-business messaging has had receipts for decades. For example, AS2, the standard for sending EDI and other business documents “using the HTTP transfer protocol”, builds in “non-repudiation of receipt”, with a “Signed Receipt: A receipt with a digital signature” coming back to the sender (IETF RFC 4130, 2005). If a partner sends you EDI that way, the receipt is part of the standard. Your job is to make sure someone checks that the receipts came back.
Webhooks. A partner’s 200 answer to your webhook call is a receipt of sorts: their server accepted it. That’s why, in my design, the integration layer only marks the notification delivered after Redrock answers.
So the question isn’t always “should we build a receipt?” Sometimes it’s “this protocol has one already; who’s watching for the missing ones?”
Does Every Arrow Need One?
Section titled “Does Every Arrow Need One?”No. A return receipt costs something: a record per message, a callback, a sweep job, a purge. Build it where the business has to prove delivery.
I’d ask three questions of each arrow:
- Would a lost message cost money, a promise, or a legal duty? A delivery status a partner bills from, a payment, a signed proof of delivery: yes.
- Would anyone notice, and how soon? If Redrock’s customers would phone about a missing status, you want to know before they do.
- Does the next message replace it anyway? FleetLink’s truck position is out of date in minutes. A lost one is replaced by the next. No receipt needed, just as module 1 found it needed no retry.
And remember the notifications are a log like any other. Purge them in tiers, as in module 3: the delivered ones after a few days, the rest once they’re resolved.
One more thing the receipts give you for free: a count. Statuses published today, receipts back, how many sent again. That’s a completeness check you can report on every morning (module 8).
Beyond the exam: what AI changes. An AI assistant will happily build “reliable delivery” when you ask for it, usually as retries around a publish call. That’s the queued and published kinds of sent. Ask it the third question too: how will we know the other side has it? If its answer doesn’t include a record saved with the change and a receipt coming back, it built a hope, not a proof.
What an Architect Decides Here
Section titled “What an Architect Decides Here”- Which arrows need proof of delivery, by what a lost message would cost, and which don’t.
- The outbox: the notification record saved in the same transaction as the change it reports.
- Who signs the receipt, and when: after the far end accepts, not when the middle receives.
- The sweep: how long to wait for a receipt, how often to send again, and who’s told when it keeps failing.
- The receiver, safe to receive the same message twice.
- Receipts the protocol already has, and who watches for the missing ones.
Explore
Section titled “Explore”- Platform Events Developer Guide, Considerations for Defining and Publishing Platform Events (opens in a new tab): at-least-once publishing and the rare event that isn’t stored (checked 2026-11-07).
- Platform Events Developer Guide, Get the Result of Asynchronous Platform Event Publishing with Apex Publish Callbacks (opens in a new tab) (checked 2026-11-07).
- microservices.io, Pattern: Transactional outbox (opens in a new tab) (checked 2026-11-07).
- Enterprise Integration Patterns, Idempotent Receiver (opens in a new tab) (checked 2026-11-07).
- IETF, RFC 4130, AS2 (opens in a new tab): business documents over HTTP, with signed receipts (July 2005, checked 2026-11-07).
- Proof of Delivery: the Data Architect course, the return receipt on this arrow, step by step.
