The API That Said Yes and Saved Nothing

The API That Said Yes and Saved Nothing

Posted by:

|

On:

|

Silent API failure: how three 200s hid an empty database

We ran into a silent API failure while wiring a purchase-to-membership automation: every step reported success, HTTP 200s came back, even valid page IDs — and the log database stayed empty. Silent API failure was the immediate description on the team chat. Silent API failure is what hit us again when the outbound queue looked healthy but events never delivered.

The surprising symptom

The automation run showed green across the board. Three separate HTTP 200 responses arrived during a single flow. The platform returned page IDs. The only symptom was the target database contained zero new rows. No error messages. No obvious exception. We watched the dashboard and scratched our heads.

What we did to prove it — the read-path experiment

We stopped trusting the automation’s success flag and built a read path into the flow. Each automation step wrote its raw API response into the store order note — a place we could read back outside the automation’s own success report. That change produced an immediate diagnostic prize: the saved API responses showed blank pages created at the workspace level instead of database rows. The raw responses matched the 200s the automation reported, but the bodies showed the result was not the row we expected.

Seeing the API response in plain text was the turning point. For the first time we could compare what we asked the API to do with what it actually did. The read-back revealed a missing Content-Type header: when the workflow platform called the API without that header, the request body was silently ignored and a blank workspace-level page got created. That single read-back note changed the investigation from guessing to targeted action.

What happened when we fixed the header

After adding the Content-Type header the same request stopped returning a false 200 and instead failed loudly with a 404 access error. That hard error pointed at a missing database share. Once we granted access, the write created the row as intended and the log database filled. The quiet failure turned into an actionable message the moment the header forced the server to validate the request body properly.

The queue twin — a separate silent mode

We also discovered another silent failure mode that looked similar from the outside. An outbound message queue showed as active and healthy, yet events sat undelivered for over eighteen minutes. The queue’s health metrics never flagged it. Forcing synchronous delivery — one line of code in our outbound path — caused the messages to be processed immediately and the backlog cleared. That was a different beast from the missing-header issue but produced the same symptom: surface-level health, deeper silence.

The rule that fell out

200 means the server accepted the request, not that it saved what you intended. Every write needs an independent read-back. Silence is not health. Those three sentences became our operating rule after this session.

A representative detail (taste, not a recipe)

We changed the client to include a proper Content-Type header and then recorded the raw API response into an order note for each step. That single change—the read-back—revealed the mismatch between “accepted” and “applied.”

A fair counter-example

Not every silent symptom came from headers. The undelivered message queue showed that a system can report healthy and still not process work. That queue issue was fixed by forcing synchronous delivery; it did not relate to the API header problem but produced the same misleading silence.

How we know — provenance

Every assertion above comes from our build log during the purchase-to-membership automation: raw API responses written to store order notes revealed workspace-level blank pages; adding the Content-Type header converted the silent success into a 404 which led to fixing a database share; an outbound queue sat undelivered for eighteen minutes until synchronous delivery was forced.

Questions we got

How did writing raw responses help?

It decoupled visibility from the automation’s own success flag. The automation still showed success, but the stored raw response let us read what the API actually returned and compare it to what we expected.

Did changing the header immediately fix everything?

No. Adding the Content-Type header revealed a 404 access error that pointed to a real access problem; fixing that access completed the chain. The header change turned silence into a meaningful error.

Is the queue problem the same as the header problem?

No. Both produce “looks healthy but doesn’t work” symptoms, but the causes differ: one was a missing request header causing body-drop; the other was messages never being processed until we forced synchronous delivery.

We keep the tested, runnable version of our diagnostic read-path and the exact automation patch in the members’ library.

Sources: internal build log and session notes from the purchase-to-membership automation run, including raw API responses, header fix and queue delivery experiment.


How we know

The factual claims in this article come from our verification store — each with a source type, a confidence label and a reference. The method is documented on How we know.

– The empty-body failure produced no error signal anywhere: the automation run was marked success, the HTTP status was 200, and a valid page ID came back. The only symptom was that the target database stayed empty. | source: first-hand experience | conf: observed | ref: Cowork-økt 2026-07-28: tre separate 200-svar, null rader i måldatabasen
– After adding the Content-Type header, the same request finally failed loudly with a 404 access error — a real, actionable message that pointed to the missing database share and let us fix the whole chain in minutes. | source: first-hand experience | conf: verified | ref: Cowork-økt 2026-07-28: v1.4-kjøring ga eksplisitt 404 etter header-fiks; DB-flytting løste tilgang
– We only found the root cause by building ourselves a read path: each automation step wrote its raw API response into a store order note that we could read back independently of the automation’s own success report. | source: first-hand experience | conf: verified | ref: Cowork-økt 2026-07-28: ordre-notat-diagnosen (NOTION-DIAG 1–4) avslørte parent=workspace
– HTTP 200 does not mean your data was saved. In our test, three separate 200 responses each created a blank page nowhere near the database we targeted — success status only means the server accepted the request, not that it did what you meant. | source: first-hand experience | conf: mythbuster | ref: Cowork-økt 2026-07-28: Success Mirage bekreftet på nytt API-lag (Notion), samme mønster som WP REST-funnene
– A message queue that is never processed looks identical to a healthy one from the outside: our store’s outbound order events sat undelivered for over eighteen minutes with the webhook still reported as active. The fix was one line of code forcing synchronous delivery. | source: first-hand experience | conf: observed | ref: Cowork-økt 2026-07-28: Woo async-levering fyrte aldri; sync-filter lagt i outbound-v1.0-fila
– When our workflow platform called the Notion API without an explicit Content-Type header, the request body was silently ignored: the API returned HTTP 200 and created a blank workspace-level page instead of the database row we asked for. | source: first-hand experience | conf: verified | ref: Cowork-økt 2026-07-28: Fase A-bygg, diag-runde 1–2 (read-back via ordre-notater)

Leave a Reply

Your email address will not be published. Required fields are marked *