APIs for Financial Data: Requesting It Programmatically, and Reading What Comes Back
An application programming interface (API) is an address a question is sent to, plus a stated shape the answer arrives in. Asking that address for the Neelbagh stall returns gives back one object for each of the eight stalls, each holding a list of month objects, 32 in all. Flattened, that answer is the same 32 rows the file carries, rupee for rupee.
The address and the shape have to be held apart. Almost every difficulty in requesting a record comes from treating the two halves as one thing. The address is short, easy to read and easy to write down. The shape is long, invisible from the address, and is the half the arithmetic actually stands on. Because the address never says how much of the record it is going to send, an address can be written perfectly and the figure still come out wrong.
Here is the everyday version. There is a ticket window at a municipal office with a printed slip beside it. The ward number and the year go on the slip, the slip is pushed under the glass, and a clerk pushes back a bundle. The slip states what may be asked for. The slip does not state that the clerk hands over one bundle at a time, that the bundles are of unequal thickness, or that a missing return is marked with a stamp rather than left out. All of that lives on the far side of the glass, and every one of those three habits changes what can honestly be said about the papers in hand. An address behaves in exactly the same way.
What is already settled about the Neelbagh record, and what is put on top?
Four pieces of groundwork arrive already done, and not one of them is laid twice. The Neelbagh market, its 32 row stall record and the nine faults sitting inside that record were fixed earlier in the reading order. So was the named conventionA counting rule fixed and recorded ahead of the work, so that anyone repeating it later arrives at the same number instead of an equally arguable one of their own. for the average takings per stall month. The convention totals only those takings cells holding a usable figure, then divides by how many such cells there are. An empty box holds no figure. The office code standing in for a return that never came holds no figure either. A genuine zero does hold one. So, finally, was the habit of stating a row count before an operation and again after it. Nothing leans on that habit as hard as a record delivered a few rows at a time.
One thing only is new: the same record, requested rather than handed over. Nothing about the Neelbagh stall record changes. The shape it arrives in changes, and so does how much of it arrives at once. A delivery that lands a few rows at a time looks complete at every stage, and the arithmetic done on those rows is arithmetic anybody would call correct. Requesting a record is a smaller subject than it sounds, and a more dangerous one.
What is an API, and what actually travels between the analyst and the record?
An API is two things wearing one name. The first is an address: a short line of text naming a record and carrying the question inside it. The second is a shape: a description, stated in advance by whoever published the address, of the words the answer will use, how those words are spelled, and how deeply they sit inside one another. When code reads the answer, it is the shape it depends on, word by word. Change a spelling on the far side and the code stops working, though the address written never altered by a character.
The address used all the way through, an invented one, reads /stall-returns, with a month and a delivery number written into it. A working address carries a host in front of that path, naming the machine that answers it. The path, and whatever follows the question mark, are the part that carries the question.
# the shape of the question, written into the address itself GET /stall-returns?month=1&delivery=1 # the same address with the month left out, asking for all four months GET /stall-returns?delivery=1 GET /stall-returns?delivery=2 GET /stall-returns?delivery=3 GET /stall-returns?delivery=4
The address and the four requests that walk the whole record ten rows at a time. GET names the kind of request: a read that asks for something and changes nothing.
An address and the shape of the answer are two different things. Code is written to read from that address. Which of the two does it rely on?
What shape does the answer arrive in, and what is JSON made of?
The answer comes back as text in a format called JavaScript Object Notation (JSON), and the whole of that format is built from three things and nothing else. A named value is a word with something attached to it. A list is an ordered run of things inside square brackets. An object is a set of named values inside curly brackets, and any of those values may itself be a list or another object. Named values, lists and objects are the entire vocabulary. Everything ever met in an answer of this kind is those three parts folded into one another.
The Neelbagh answer holds eight stall objects. Each one carries the stall identity, the name the market office wrote, a licence number, a category and a pitch measurement, and then one list called months. The eight month lists hold four, four, five, three, four, four, four and four month objects between them, and those eight counts add to 32. Each month object carries the month, the takings in rupees and the day the return was filed.
// one stall object out of the eight, three of its columns left out for room { "stall_id": "NB-05", "stall_name": "Bansi Flour", "months": [ { "month": 1, "takings_rupees": 55000, "filed_on_day": 6 }, { "month": 2, "takings_rupees": null, "filed_on_day": 7 }, { "month": 3, "takings_rupees": 54000, "filed_on_day": 8 }, { "month": 4, "takings_rupees": 53000, "filed_on_day": 6 } ] }
One of the eight stall objects, printed whole. Bansi Flour filed in all four months but left the takings box empty in month 2, and the answer says so out loud rather than leaving a hole.
Look at what month 2 of Bansi Flour does. In the file that cell is simply empty, and an empty cell is ambiguous: it may mean nothing was earned, or nothing was written, or the line was cut off when somebody exported it. In the answer the same absence arrives as an explicitly empty value sitting in a field that is present. An empty cell is a hole in a record and an explicitly empty value is a statement about the record, and that difference is the one real advantage this shape has over a flat file.
One field on the stall object deserves a second look before anything is computed. The licence number is a whole number, and a whole number invites arithmetic. The licence number is an identifierA value whose entire job is to name one thing so it can be told apart from another. An identifier may be written as digits, but adding two of them together or taking their average produces nothing that means anything., and averaging eight of them gives a figure that is not money, not a size and not a quantity of any kind. The shape gives no warning about this. Nothing in the format distinguishes a number that counts from a number that names.
The eight stall objects hold four, four, five, three, four, four, four and four month objects. Two of those counts are not four. What do those two counts say about the record before anything is computed?
Why is the answer nested when the file it describes is flat?
A file has one grainWhat a single row of a table actually describes, said as a full sentence. Get it wrong and every count taken afterwards is counting something other than the thing named., and the Neelbagh file has a clear one: one row describes one stall in one month. Because that is the grain, the stall identity, the name, the licence number, the category and the pitch measurement are typed again on every row that stall appears in. Four rows for Bansi Flour, four copies of the words Bansi Flour. The repetition is not a flaw in the file. Repeating the stall details on every row is what flat means.
The answer has two levels instead of one. At the outer level an object describes a stall. At the inner level an object describes one month of that stall. Because the stall sits above the months, its details are written once and the months hang underneath. Neither shape is more correct than the other, and the finance task is never to prefer one, but to get from whichever shape was delivered to the grain the arithmetic needs.
There is a consequence worth pausing on. In the file the stall name is typed on all four rows, and four typings mean four chances to type it differently. Harit Greens appears as Harit Greens in months 1 and 2 and as Harit Green in months 3 and 4, and the file cannot object because each row was typed on its own. In the answer the name is written once per stall object, so one stall cannot disagree with itself. Writing the name once per stall object is a genuine advantage of nesting, and the advantage disappears the moment the answer is flattened.
Commit before reading on. The answer writes each stall detail once and the file writes it again on every row. Which of the two can hold two different spellings of one stall name?
How is the answer flattened, and how is it known that all of it is there?
Flattening is the plainest operation of the lot. The procedure walks the eight stall objects, and inside each one walks its list of month objects, writing one row for every month object with the stall details copied down onto it. Eight walks over the outer level, 32 walks over the inner level, 32 rows written. Done on the Neelbagh answer, out come 32 rows across 8 columns. Of those, 31 takings cells carry a number and total Rs 21,40,099/-, and under the named convention that total reads Rs 69,035.45/-. The 32 rows are the file, row for row and rupee for rupee.
# walk the objects and write one row for every month object rows = [] for stall in answer["stalls"]: for m in stall["months"]: rows.append({ "stall_id": stall["stall_id"], "stall_name": stall["stall_name"], "month": m["month"], "takings_rupees": m["takings_rupees"], "filed_on_day": m["filed_on_day"], }) # the check that makes it safe: what was sent, against what was written sent = sum(len(s["months"]) for s in answer["stalls"]) print(sent, len(rows)) # 32 32
Flattening the eight stall objects into rows, and the two line count that proves nothing was lost on the way.
The last two lines are the entire safety of the operation. Count the month objects that arrived, count the rows that were written, and say both numbers out loud in the same breath. If they agree, the flattening was faithful. If the second is smaller, something was skipped, and the commonest cause is a stall object whose month list was empty and quietly contributed nothing. If the second is larger, something was written twice. A flattening that reports no count has said nothing about whether it worked, and no error message will arrive to fill the gap.
Ten shops in one shopping centre each hand the manager a folder of monthly slips, and somebody types the whole lot into one sheet. Nobody in that building can tell by looking whether the sheet is complete. The only honest check is to count the slips in the folders and count the lines in the sheet, and the two numbers either agree or they do not. Flattening an answer is the same act with the folders replaced by objects.
Flattening the answer gives 31 rows. Which single number is the 31 compared against, and what has gone wrong if the two differ?
Ten rows at a time, this record arrives in four deliveries. Does the third delivery look much like the other three?
What is paging, and what does a read that stops early cost?
Whoever publishes an address decides how much of a record one answer may carry, and that decision is called the delivery size. The delivery size has nothing to do with the analyst and nothing to do with the record. At ten rows a delivery the Neelbagh record arrives as four deliveries of 10, 10, 10 and 2 rows, and every one of those deliveries is a complete, well formed, entirely correct answer to the request that produced it.
Read alone, the four deliveries give figures that have almost nothing in common. Delivery one reads Rs 38,500/-. Delivery two reads Rs 34,900/-. Only nine of its ten rows carry a usable figure, the empty takings box of Bansi Flour being the tenth. Both of the rows reading Rs 4,80,000/- and the market office code of 99999 land on delivery three, so delivery three reads Rs 1,35,199.90/-. Delivery four, holding two rows, reads Rs 44,500/-.
| Delivery | Rows | Figures under the line | Read alone | Rows in hand | Running reading |
|---|---|---|---|---|---|
| Delivery one | 10 | 10 | Rs 38,500/- | 10 | Rs 38,500/- |
| Delivery two | 10 | 9 | Rs 34,900/- | 20 | Rs 36,794.74/- |
| Delivery three | 10 | 10 | Rs 1,35,199.90/- | 30 | Rs 70,727.55/- |
| Delivery four | 2 | 2 | Rs 44,500/- | 32 | Rs 69,035.45/- |
Now read the last column downwards. The last column is the one that matters, and it does not behave the way people expect. The running reading starts at Rs 38,500/-, falls to Rs 36,794.74/-, jumps to Rs 70,727.55/- and settles at Rs 69,035.45/-. The running reading goes below the whole record reading, then above it, then back to it. The running reading crosses the whole record reading exactly once, and never sits on that reading until the last delivery has arrived.
The direction of a short read is the easiest thing to get wrong. On this record a read that stops at delivery one reads low, and it is tempting to turn that into a rule. Reading low is not a rule. Reading low is a property of the row orderThe order rows happen to sit in when they are handed over. Row order is a fact about the delivery, not about the record, and reordering the same rows changes it without changing a single figure. the market office typed, and nothing more. Shuffle the same 32 rows and the running reading takes an entirely different path to the same destination. A short read is not a low read; it is a correct answer to a question nobody asked.
The control below adds the deliveries one at a time and redraws the reading. Does the reading climb steadily to the answer, fall steadily to it, or overshoot it?
Add the deliveries one at a time and watch the reading go past the answer.
One control moves: how many of the four deliveries have been read. The record never changes, the delivery size stays at ten rows, and the dashed line at the whole record reading of Rs 69,035.45/- never moves. The line redraws, the strip underneath fills in the rows actually in hand, and the lime connector shows how far the current reading sits from the line. At the opening setting one delivery has been read, 10 rows are in hand with 10 figures under the line, and the reading is Rs 38,500/-, a full Rs 30,535.45/- below the whole record reading.
Educational illustration, and every quantity in it was made up for the purpose. The delivery size of ten rows was chosen by whoever published the address and is held fixed here, so the control moves the number of deliveries read and nothing else. Under the named convention only cells holding a usable figure go under the line, so Bansi Flour month 2 and nothing else is what keeps the count at 31 rather than 32. The fall between the first two stops is only Rs 1,705.26/-, so the vertical scale starts at Rs 36,000/- rather than at nothing and keeps that fall visible.
A colleague reports Rs 38,500/- as the average takings per stall month from this address. The arithmetic is correct and no error was raised anywhere. What is wrong, and what one number printed beside the figure would have shown it?
What does an address refuse to say?
Three things never arrive with the answer, and no field in the shape carries any of them.
The first is when the record behind the address last changed. An answer is a picture of the record at the moment it was written, and nothing in it dates that moment. The second is whether any row already held has since been revised. Harit Greens filed month 2 twice, on day 5 and again on day 19, and the second filing withdrew the first. A read taken before day 19 would hold a figure that has since been taken back, and reading again would not identify which rows had changed unless they were compared directly. The third is what the market office does when a return never arrives. The Chandan Tea row for month 4 reads 99999, a perfectly good whole number and in fact the office code meaning no return was received. Nothing in the shape says so. The field is present, the type is right, and the figure is not money.
All three of these belong to provenanceThe paper trail behind a number: which record it was lifted out of, and every hand that altered it before it was seen. Nobody writes it down and it is simply gone., and provenance is not a field in the answer. Provenance has to be asked for separately, in words, from whoever publishes the address, and if nobody can say then the honest thing is to record that nobody could. An answer that is silent about revisions is not an answer that says there were none.
Three things an address refuses to say. Which of these bites hardest on the Neelbagh record specifically?
What is written down the first time a record is read from an address?
An analyst, a lender or a small business operator reading their own point of sale figures all face the same moment: the first successful read. The note written down in that moment decides whether the figure is defensible six months later, when nobody remembers what was asked. Five things, and every one is a fact rather than a judgement.
- The exact path, and everything written into it. Not the description of the request, the request. A delivery size changed on the far side changes what a repeat of the same request returns, so somebody re-running it later needs the characters, including the delivery size.
- The grain of the answer, in one sentence. One month object describes one stall in one month. A grain nobody wrote down is a grain that changes quietly, so write it as a sentence.
- How many objects came back and how many rows they flatten to. Eight and 32. Two numbers, one line, and it is the only evidence that the flattening was faithful.
- The delivery size, and how many deliveries were actually read. Ten rows, four deliveries read out of four. The delivery count is the line that would have caught the failure below, and it is the line most often left out.
- Every code and special value the answer uses. 99999 for a return that never arrived. An explicitly empty value for a return filed with the box left blank. The codes and the empty values decide the denominatorWhatever the total was divided by. Two people can divide one identical total by two different counts, both be right about the arithmetic, and disagree entirely about what the result describes., so they are not a detail.
A figure computed from an answer that arrived in deliveries, without the delivery count printed beside it, is not slightly incomplete, it is unattributable. Nobody afterwards can tell whether the figure describes the record or a tenth of it. The claim is harder than it sounds. Such a figure cannot be defended, cannot be corrected, and cannot even be shown to be wrong without going back to the address and reading the whole record again.
Somebody supplies a figure computed from an address, and nothing else. Which two of the five things above are asked for first?
The failure: a correct figure computed on a tenth of a record
An analyst requests the Neelbagh stall returns, receives an answer, flattens it, applies the named convention and reports an average takings per stall month of Rs 38,500/-. Walk the work and there is nothing to object to. No error was raised. The answer was well formed and every field was where the shape said it would be. Every rupee in it was correct. The convention was honoured to the letter: every cell holding a usable figure went into the total, and the total was divided by how many such cells there were.
The read simply stopped at delivery one. The answer to the question actually asked is Rs 69,035.45/-, so the report is short by Rs 30,535.45/-, or 44.2316 per cent of the whole record reading. A plainly wrong figure looks wrong, and gets dealt with on the spot. The reported Rs 38,500/- looks exactly like a right one: the shape was honoured, the arithmetic was faultless, and the only thing out of place was that the count under the line was 10 where it should have been 31.
The fix is one line and it costs nothing. Print the count of figures that went under the line in the same sentence as the figure, every time, without exception. Rs 38,500/- over 10 figures and Rs 69,035.45/- over 31 figures are two sentences nobody could confuse. Rs 38,500/- on its own is a sentence nobody can check. And do not take the wrong lesson from the direction: on this record a short read happened to read low, but three deliveries in, the same running reading sits above the answer by Rs 1,692.10/-. The lesson is the count under the line, never which way the figure moved.
Where reading a record from an address stops. Weighing an address against a handed over file is covered separately, with these same 32 rows set out as two deliveries side by side. Four further subjects are covered elsewhere: the place a stored table lives and the shape it has to declare, pulling that table into memory to group it, laying a second table alongside the first, and the run of ordered cells that lets somebody reproduce an answer months afterwards.
Where does every number come from?
The Neelbagh stall record is a made object, so every count, every rupee and every delivery boundary was worked out from the record by hand rather than looked up anywhere. The table below names each quantity, the operation behind it, and a check that can be run against the rows printed further up.
| What is asserted | The operation behind it | Test it yourself on the rows above |
|---|---|---|
| 32 rows and 31 takings figures | Counted off the record as the market office handed it over | Count the lines. Thirty two of them, and Bansi Flour in month 2 has nothing in its takings box |
| Eight stall objects holding 4, 4, 5, 3, 4, 4, 4 and 4 months | Grouped the same 32 rows by stall and counted what fell into each group | The eight counts add to 32, the row count the record started from |
| Rs 21,40,099/- and the reading of Rs 69,035.45/- | Added the 31 usable takings figures and divided by 31, carried exactly and rounded once at the end | Add the column yourself. The division does not terminate, and that is why the paise are a rounded display and not a measurement |
| Deliveries of 10, 10, 10 and 2 rows | Cut the same rows at every tenth line, in the order the file carries them | Count ten lines down from the top three times over and see what is left at the bottom |
| The four readings alone and the four running readings | Summed and divided inside each cut, once per stop, with no figure reused from a rounded one | The empty box falls inside delivery two, so that delivery holds nine usable figures rather than ten |
| Short by Rs 30,535.45/-, or 44.2316 per cent | Subtracted one exact quantity from another before either was rounded for the screen | The shortfall is divided by the whole record reading rather than by the delivery one reading |
| Any rate, threshold, filing period or published standard | None is quoted anywhere above, because counting rows in a made file needs none | Nothing to confirm here. Meet such a value in material near this reading and take it from whoever issues it |
The Neelbagh market, its stalls, its stall record, the market office and the address /stall-returns are invented.
Educational material. Not advice on any investment, tax, budget or market position.
