This is Episode 13 of The Vibe Coder’s Guide to the Machine: computer science for a new generation.
You ask the assistant for a checkout button. Your app sells a keyboard, and when someone pays, the app should confirm it and show the total. The assistant writes a function called pay that sends the order to a payment service and hands back whatever the service replies. It pastes in an example reply, shows that its code reads the reply cleanly, and wires the result into a confirmation screen. You click the button and the screen appears, with a total on it. The summary at the bottom of the reply says the feature works. It is right. The feature works, and that is the part worth looking at closely.
Everything your app did until now happened inside one process on one machine. When one part of a program called another, the function on the other end received the very value that was passed, the same object in the same memory. A language like Python knew whether that value was a number or a piece of text, and it refused to add one to the other. The checkout button is different. The payment service is another program, often on another machine, with its own memory that your process cannot see into. The two programs share nothing except a connection, and the only thing a connection can carry is bytes, one after another, in each direction. That the exchange is a “call”, that a number means dollars or cents, that a reply means the money has been taken: none of that travels. Each side brings it, and each side assumes the other brought the same thing.
What the client actually wrote
To see what travels, I reran the checkout exchange on my own Mac with a small stand-in for a payment service, a Python program listening on 127.0.0.1, the address a machine uses to mean itself. In the words the trade uses, the stand-in is the server, the program that waits to be asked. Your app is the client, the program that asks. An API, short for application programming interface, is the set of requests a server is prepared to answer, and the request your app sends is one message asking for one of them. The client opened a connection and wrote this onto it, exactly as it went:
POST /pay HTTP/1.0\r\nHost: 127.0.0.1\r\nContent-Type: application/json\r\nContent-Length: 39\r\n\r\n{"order": "A-1001", "item": "keyboard"}That is 130 bytes. The \r\n pairs are two invisible characters that end a line, so the message is really a few short lines. The first line says what the client wants: POST, meaning “here is something for you to act on”, sent to /pay, the name the server uses for paying, under the rules of HTTP version 1.0. HTTP is the set of rules for how web requests and replies are laid out, which is why both programs could find the lines at all. Next come the headers, labelled notes about the message: which host it is for, what kind of content follows, and how many bytes of it there are. A blank line, the doubled \r\n, says the notes are over. Then comes the body, the part the app actually cares about, written in JSON, a plain-text way of writing labelled values with quotes and braces.
Look at what is in those bytes and what is not. The word “call” is not there. In the app’s code, pay(order) looks exactly like a function call that returns a value, and on the wire, meaning in the connection itself, it is a stretch of text written into a connection and a stretch of text read back. Nothing in the bytes says the order is a real order, that “keyboard” is one of the things the shop sells, or that the client expects money to move. The server reads /pay and decides what to do because someone wrote code on its side that treats that word as a request to pay. The bytes cannot tell you whether that code exists.
What came back
The server answered with 177 bytes:
HTTP/1.0 200 OK\r\nServer: BaseHTTP/0.6 Python/3.14.6\r\nDate: Fri, 06 Nov 2026 21:25:22 GMT\r\nContent-Type: application/json\r\nContent-Length: 33\r\n\r\n{"status": "paid", "total": 1999}The first line carries the status code, a number that sums up how the server got on with the request. 200 OK means the server received the request, understood it and handled it. The headers name the software that answered and the exact second it answered, and the body, 33 bytes of JSON, says "status": "paid" and "total": 1999.
The reply is generous with detail. It tells you the server’s software and version, the day of the week, and the time to the second. It does not tell you what 1999 is a number of.
A keyboard for $1999
The server meant cents. Somewhere on its side, a person or an assistant decided that money would be counted in whole cents, which is a sensible way to avoid the rounding troubles of fractional dollars, and 1999 cents is $19.99. The client read the same number as dollars and showed $1999 on the confirmation screen. Both readings came from the same four digits.
Nothing failed. The connection opened and closed. The bytes arrived whole: the reply’s header said 33 bytes would follow, and the body was 33 bytes. The client read the JSON without complaint. The status was 200. No line of either program raised an error, because no line of either program was wrong by its own rules. The server wrote what it meant. The client read what it saw. The mistake lives in the space between them, which neither program can look at. A test that checks “the call succeeded” passes. A test that checks “the total is a number” passes too.
The status code has the same gap, smaller but real. A 200 means what HTTP’s published rules say it means: the server handled the request. Whether “handled” means the card was charged or only that the request was taken in is another agreement, and the bytes do not say. The "paid" in the body is a word the server chose. The client believes it because it has no other way to find out.
This is why the assistant’s example reply felt like proof and was not. An example reply shows that the client’s code can read bytes shaped like that. It cannot show that the client and the server read them the same way, because meaning is not in the shape. When the assistant writes both sides, or writes the client from an example someone else wrote, it fills the gap with whatever reading seems natural, and dollars is a very natural reading of a price.
One word on the wire
The fix is not cleverer parsing. It is writing the agreement down where both sides will see it. In the second run, the server named the field for what it holds:
{"status": "paid", "total_cents": 1999}I changed the client to look for total_cents and divide by 100, so both sides moved together, and it showed $19.99. The whole reply grew by 6 bytes, the length of _cents. The number did not change. The status did not change. Nothing on the wire got smarter. What changed is that the unit moved out of two people’s heads and into a word that both programs have to agree on to work at all. If the client still looked for total, it would now find nothing, and finding nothing is a failure someone notices, which is better than finding the wrong thing quietly.
A field name is the smallest written agreement there is, and it is still an agreement made in advance, away from the wire. The bytes carry the word total_cents. They do not carry the fact that both sides read “cents” as hundredths of a dollar, or that the client will divide and not multiply. Those still rest on people having decided the same thing earlier. Every working connection rests on that layer of earlier agreement. Some of it is published, like the HTTP rules that made 200 and Content-Length mean the same thing to both programs here. Some of it is written in a field name, a document or a comment beside a line of code. And some of it, like the unit of total in the first run, lived only in a comment inside the server’s own code, where the client could not see it, which for the client is the same as hoping.
The runs show only so much: one Mac, a local stand-in instead of a real service, plain HTTP with no encryption, and a single request each time. A real payment exchange has far more in it.
What each side believes
The thinking worth keeping is short. When an assistant wires your app to another program’s API, the code it writes on your side is one half of a conversation, and the code proves only that this half can read the bytes it expects. So for every connection, ask two things: what each side believes the bytes mean, and who wrote that belief down. Is a number dollars or cents, seconds or milliseconds, a total before tax or after? Does “paid” mean the money moved, or that the request was taken in? Is the answer in a field name, in the other side’s published rules, or only in the assistant’s guess about what an example probably meant? A connection that runs without error has shown you that the bytes arrived. Whether the keyboard cost $19.99 or $1999 was never a question the wire could answer.
The Vibe Coder’s Guide to the Machine. You can build it. Now understand it.



