DEV Community

LaunchSignal
LaunchSignal

Posted on

When an agent submits, the error response is the interface

When a person submits a form, the interface is the form. When an agent submits, the interface is whatever comes back.

I didn't think much about this until I sat down to document a small listing API properly. The success path barely needs explaining. An agent that gets a 201 is done. Everything else is where it has to decide what to do next, usually with no human watching.

So I started reading each response as an instruction the agent has to act on.

400 with fields: "fix this, then retry once." A validation error like invalid_category comes back with fields.category listing the allowed values. The agent doesn't have to guess. It reads the list, corrects the payload, and sends it again. A red outline on a form field does nothing for a model.

409 duplicate_domain: "stop, it's already there." It fires whether the existing listing is approved or still pending. For an agent, this is close to a success: the job is already done, or already in the queue. The wrong move is to tweak the URL and try again.

400 rejected_policy: "don't retry, tell your human." There's nothing to fix in the payload. The only honest next step is to report back. I'd rather say that plainly than return something vague and let the agent loop.

429 rate_limited: "not now." On mine it's scoped to pending submissions per email over 24 hours, so retrying right away changes nothing. A distinct code lets the agent stop and hand off instead of hammering.

201 with status: "pending": "received, not live." This is the one I'd underline. The response carries an id, a slug, and next_steps, but a person still reviews the listing. A careful agent then checks its work: it calls get_product (or GET /api/v1/products/:slug) and gets not_found. Read naively, that looks like the submit failed. It didn't. The read endpoints only return approved listings, which is why the 404 message says "not found or not approved." The agent should keep the slug and status from the 201 and read that 404 as "not visible yet," not "missing." The real confirmation comes later, when get_product or list_products returns the listing.

The gap between "accepted" and "visible" is where I'd expect most agent confusion on any site that moderates. If the states aren't spelled out, the agent fills the silence with a retry, and now you have duplicates.

I wrote up the whole flow, with each code and what to do about it, in this guide.

What I'm keeping:

  • Every error gets a stable code, not just a message. Messages are for people. Codes are for branching.
  • "Fix and retry," "stop," and "wait" should look different. An agent can only behave well if they do.
  • Say what's pending. A review queue that's invisible from the API looks like a broken API.
  • Make reads the confirmation step, and document what they won't show.

A pretty form reassures the person who already decided to submit. An honest error tells a machine what actually happened, and that's what it needs so it doesn't make a mess on someone's behalf.

The API I've been describing is LaunchSignal's. Do your agents branch on error codes, or just retry until something sticks?

Top comments (0)