Sending Data: Your First POST
Everything you have sent so far only looked. This page changes something. Tandem's partner sandbox — a practice copy of the API where nothing is real, formally introduced in Chapter 6 — lets anyone try reserving a bike. You are going to reserve bk_0977 at Old Market, by hand, and when the response comes back, something will exist that did not exist a minute ago, because you asked in the right shape.
curl -i -X POST https://sandbox.api.tandem.example/v1/reservations \
-H "Content-Type: application/json" \
-d '{"bike_id": "bk_0977", "station_id": "st_014"}'
Read it piece by piece, because all three new flags from the curl page just arrived at once. -X POST says the verb out loud — strictly, -d alone already makes the request a POST, but stating it costs nothing and reads clearly. What -d does not do is set the format label: its default is an old form format, which is why the Content-Type header is not optional. -d attaches the body — the cargo, written as JSON. And -H "Content-Type: application/json" is the label on the parcel, announcing the format so the server knows how to read it. The -i is last page's flag, here so the verdict prints with the receipt, and the backslashes at the line ends just split one long command across lines for readability. One honest note for Windows readers: multi-line examples like this one are written for the macOS and Linux shell; the calm Windows route is Git Bash (it installs with Git) or WSL, where they run as printed — in PowerShell the quoting rules differ enough to mangle the JSON.
The Body Comes from the Docs, Not from Guessing
Where did bike_id and station_id come from? The documentation. The reference page for POST /reservations names the required fields, their types, and what comes back on success — the same menu principle as the last page, now applied to cargo. Building a body is an act of reading, not invention: the docs say what the form wants, and you fill exactly that in. One deliberate simplification on this page: the sandbox's reservation door is open, no key needed. The real one is locked, and Chapter 5 is where you get the key.
Reading the Receipt
HTTP/1.1 201 Created
Content-Type: application/json
{"id": "res_3f81", "bike_id": "bk_0977", "station_id": "st_014",
"expires_at": "2026-08-21T10:32:00Z", "status": "active"}
The verdict is 201 Created — Chapter 2's specific success: a new thing now exists. And the body is its receipt: the reservation's own id, res_3f81, and when it expires. Keep the habit this teaches: when a POST succeeds, note the id it returns. That id is the name of the thing you made — the way you will ask about it, change it, or cancel it later. "It worked" is a feeling; "res_3f81 exists" is a fact.
Now Respect the Verb
One more thing before the chapter closes, and it is the lesson this sandbox exists to make cheap. Press the up arrow in your terminal — it recalls the last command — and run the same POST again. Verdict: 201 Created. A second reservation, res_3f82, now also exists. Nothing warned you, nothing deduplicated. POST creates; twice creates twice — Chapter 2's warning, now demonstrated on your own screen where it costs nothing. In Chapter 7 this exact moment returns with money on the table, and you will be ready for it.
- "The body just gets pasted onto the end of the URL." The body travels inside the request, attached with -d. The URL says where; the body is the cargo — different parts of the envelope entirely.
- "The Content-Type header is optional politeness." Without the label, many servers refuse the parcel as unreadable — a 4xx you will formally meet in Chapter 7. Body and label travel together, always.
- "A 201 with a body means something extra happened." The body is the receipt: the new thing's id and details. You will want that id thirty seconds later — noting it is the habit.
- "The single quotes around the JSON are part of JSON." They are the terminal keeping the braces intact, like the URL quotes last page. The JSON is what is inside them.
- Read and write are the two halves of API citizenship, and you now hold both. Every counter in this book — and at work — is open to you in both directions.
- The double-reservation demonstration is this book's cheapest important lesson: you have now personally created a duplicate with a repeated POST, in a place where it cost nothing. Chapter 7 builds the discipline on that memory.
Knowledge Check
What are the three pieces this JSON-carrying POST states beyond the URL?
- The verb (-X POST), the body (-d), and the format label (-H Content-Type)
- The key (-H Authorization), the print flag (-i), and the redirect flag (-L)
- The scheme, the host, and the path of the sandbox address
- The narration flag (-v), the quotes, and the line-splitting backslashes
Why should you note the id that comes back in the 201 receipt?
- Because the server requires you to confirm the id before it commits
- Because the id is the name you will use to ask about, change, or cancel the new thing
- Because the id proves ownership and works like a password for that reservation
- Because the id secretly encodes the expiry time of the new reservation
You run the same POST twice and get 201 both times. What happened?
- The server recognized the repeat and confirmed the original reservation
- The second 201 is a cached copy of the first response, nothing new
- Two separate reservations now exist, each with its own id
- The sandbox allowed it, but the real API would have refused the duplicate
You got correct