Your notifications are only doing half the job

Almost every notification tool stops at delivery. It sends the push and then leaves. The interesting part, a human deciding something and that decision landing back in your system, is the half nobody ships. Here's why that gap exists, and what closing it changes.

By The Roundtrip Team

There is a moment, in almost every internal system, where the software has done all it can and now needs a person. A deploy is staged and green, but someone has to say ship it. A refund is over the auto-approve limit. An agent is one step away from deleting a production table. The machine has run out of authority, and a human has to weigh in.

The strange thing is how badly our tools handle that moment. We have spent years making it easy to tell a person something. We have made almost no progress on letting them answer.

The category stops at delivery

Look at how teams wire up operational notifications today. A cron job finishes and pings a channel. A monitor trips and fires an alert. A backup fails and the team gets a push. All of this works, and all of it is one-directional. The message goes out, and that is the end of the tool's job.

The most "interactive" these tools get is a couple of preset buttons that fire a fixed HTTP request — open this URL, hit that endpoint. There is no way to show a form. No way to capture a typed reason. No way to take the person's actual decision and route it, structured, back into the system that asked. The notification is a dead end with a nice icon.

So what happens when a workflow genuinely needs an answer? People leave. They stand up a Slack app with interactive blocks and a request handler. They build a little internal dashboard nobody wanted to build. They send an email and then read the replies by hand and re-key the decision into a ticket. The notification did the easy 20%, and a human is gluing together the hard 80% by hand, every time.

The half that matters is the return trip

A notification that only informs is half a transaction. The valuable half is the answer coming back, and not as more text for someone to parse, but as a structured result your code can act on without a human in the middle a second time.

That is the whole idea behind Roundtrip. One request goes out; one structured answer comes back. We called it Roundtrip because a one-way push is half a trip.

import { roundtrip } from "./roundtrip";
import { content, metric, text, approveReject } from "@roundtrip/sdk";

await roundtrip.requests.create({
  channel: "deploys",
  notification: { title: "Ship api@2.3.0 to production?", priority: "high" },
  content: content({
    title: "Ship api@2.3.0 to production?",
    status: { label: "Awaiting approval", tone: "warning" },
    sections: [
      metric("Diff", "+412 / −98", { tone: "info" }),
      text("CI green. Last deploy was 6 days ago."),
    ],
    actions: approveReject(),
  }),
  response: {
    mode: "required",
    webhook: "https://api.example.com/roundtrip/callbacks",
  },
});

The person gets a real card on their phone: a title, the diff, the context, two buttons. They tap Approve or Reject. Roundtrip POSTs a signed callback to your webhook with the decision, the requestId to correlate it, and any metadata you attached, echoed back verbatim. Your pipeline reads the result and proceeds, or doesn't. Nobody re-keyed anything.

And it does not stop at two buttons. The same request can carry a form with text, email, number, select, multiselect, and switch fields, or accept a free-text reply, or take a file back as an attachment. Whatever shape the answer needs, it returns structured.

What changes when the loop closes

When the answer comes back on its own, a category of glue code simply disappears. The deploy gate is no longer a person watching a channel and clicking a link; it is a request the pipeline waits on. The access grant is no longer a DM and a manual GRANT; it is an approval with the reason captured and audited. The spend approval is no longer an email thread; it is a decision with a number attached, recorded.

You stop building the receiving end over and over. The notification tool finally owns both directions, so the workflow can run through it instead of falling out of it the moment a human is involved.

That is the gap worth caring about. Getting a message in front of a person has been solved for a decade. Getting an answer back, cleanly and structured into your system, is the half that was still missing.

When you are ready to close it, send your first notification. It takes a few minutes, and the answer comes back to your code.