Import and export formats
The file is the contract. Export produces CSV files with fixed columns, documented below column by column, which open in any spreadsheet — not only in ours. Import reads the files other apps and timing clocks already produce. If your format is not on the list yet, send us a file: the last section says exactly what to send and what we do with it.
Every file begins with the marker that tells a spreadsheet the text is UTF-8, so
accented characters appear correctly without your configuring anything. Dates
are YYYY-MM-DD, times are HH:MM:SS with optional milliseconds, and decimal
numbers use a point.
The point is not a preference. The file is comma-separated, so a decimal
comma would split one number across two columns. packages/core/src/csv.ts
writes every decimal with toFixed(3), which produces a point whatever language
you are reading in — the same file, byte for byte, for a Romanian fancier and an
English one:
Race Name,Release Date,Distance (km),Bird Ring,Bird Name,Position,Field Size,Velocity (m/min),Ace Points,Clock Time,Designated
Oradea,2099-05-18,342.000,RO 2099 900021,,37,397,1030.120,93.199,11:47:00,
What we export
From Settings, one button per file. Free, with a subscription or without one. You can check this yourself — steps 5 and 6 of Your data.
Photos are not included in the export. A CSV holds records, and a photograph is not a record — it would turn the file into something a spreadsheet can no longer open.
thatpigeon-birds.csv — the birds
The constant in the code is BIRD_HEADERS, in packages/core/src/csv.ts.
| Column | What it is |
|---|---|
Ring Number |
The ring, exactly as you typed it — unmodified |
Name |
The bird's name, if you gave it one |
Sex |
cock or hen, untranslated |
Color |
The colour, in your own words |
Status |
The bird's status, untranslated |
Hatch Date |
YYYY-MM-DD |
Sire Ring |
The father's ring — the ring, not an internal identifier |
Dam Ring |
The mother's ring, likewise |
Strain |
The bloodline |
Breeder |
The breeder the bird came from |
Notes |
Your notes |
Parents are exported as rings, not as internal identifiers. That is why the file can be re-imported into any loft, ours or anyone else's: a ring means something to everybody, an internal identifier means nothing to anybody. A parent that is not in the list exports as an empty cell, never as a code you can do nothing with.
thatpigeon-results.csv — the race results
| Column | What it is |
|---|---|
Race Name |
The name of the race |
Release Date |
The day of liberation, YYYY-MM-DD |
Distance (km) |
The distance from the release point to your loft, to three decimals |
Bird Ring · Bird Name |
Which bird |
Position · Field Size |
The position, and how many birds were in the race |
Velocity (m/min) |
The velocity, three decimals |
Ace Points |
The coefficient, three decimals |
Clock Time |
The time recorded by the clock |
Designated |
yes if the bird was nominated before the race; an empty cell if not |
The Designated column is empty, not no, when the bird was not nominated —
because no looks like a flag in a spreadsheet, whereas an empty cell means
throughout the file what an empty cell means everywhere: "no".
How velocity and the coefficient are calculated, and why the number is sometimes the federation's rather than ours: How we calculate.
thatpigeon-journal.csv — the loft journal
The constant is JOURNAL_HEADERS. Four identifying columns — Loft, Date,
Slot (morning or evening), Compartment — then the journal's eleven
fields (Feed, Feed Supplements, Water Supplements, Grit, Minerals,
Flight, Nostrils, Plumage, Droppings, Loft Conditions, Weather) and
Notes.
An empty Compartment means the whole loft, not "missing". The eleven
fields are your words, not ours: there is no list you have to choose from, and
the file writes them out exactly as you wrote them.
The header the export writes is the header the import reads, by construction: the same map in the code produces both directions, so they cannot come to differ because somebody edited one file and forgot the other.
thatpigeon-health.csv — health events
Bird Ring, Loft, Type (vaccination, medication, treatment or
note), Product, Batch No, Occurred On, Next Due, Notes.
Bird Ring and Loft can both be empty on the same row: a treatment can belong
to one bird, to a whole loft, or to neither if you noted it without saying. Those
are three real states, and the file keeps all three.
thatpigeon-breeding.csv — pairings and youngsters
Season, Cock Ring, Hen Ring, Nest Box, Paired On, Ended On,
Clutch Laid, Eggs, Hatched, Clutch Notes.
One row per clutch, with the pairing's data repeated — the shape a spreadsheet can group. Two things we chose deliberately:
- A pairing with no clutch at all still appears, with the clutch columns empty. A pairing that produced nothing is a fact about the season; a file that skipped it would be a list of successes, not a record.
- Zero eggs is not the same as no clutch. A clutch of zero is written
0; the absence of a clutch is written empty. Otherwise you could not tell a failed round from an unrecorded one.
thatpigeon-listings.csv — listings for sale
Ring Number, Price, Currency, Note, Opened, Closed, Reason.
Every listing you have put up, open and closed. A closed listing is shown nowhere in the app, so this file is where you find its price and note.
- The contact is not a column. When a listing closes its contact is deleted; a file that kept it would hold, on a phone and in a message, exactly what we stopped holding.
What we import
Every importer is tested against a real file, not one we invented. An importer with no sample file is not published, because an importer that has never seen a real file is a guess.
| What we read | Where it comes from |
|---|---|
| Our own bird export | The file above, re-imported — useful when moving data between accounts |
| Our own journal | The same, for the journal |
| MyLoft | That app's exports: cocks, hens, siblings, offspring, results |
| Benzing — race | The clock's basketing and arrival files |
| Benzing — training and career | The clock's register-type files |
| Columba | The federation's classification sheets — see the next section |
The importers are separate modules, registered in one place
(packages/core/src/importers/registry.ts), and the app recognises for itself
which file you gave it. A new format is added without touching any of the rest.
For health and for pairings there is export only, not yet import. It will be added; until then this page will not pretend otherwise.
What the Columba import does
Results in the federation's classification sheets are public and they are yours. How we take them is limited by rules we imposed on ourselves before writing the first line of code, and which you can check against the app's behaviour:
- It asks only when you press. There are no scheduled jobs, nothing runs in the background, nothing is read ahead. A request to the federation's site is always the direct result of a press.
- We identify ourselves honestly. Every request says who we are and leaves a contact address. We do not pretend to be a browser.
- Only your rows are kept. The classification sheet is read whole, in memory, and then reduced: your rows, plus race-level facts that name nobody. Other fanciers' names, codes and localities are discarded before anything is written.
- We republish nothing. Imported results stay in your account. We do not rebuild classifications, we do not offer a "browse all races" page, and we let nobody search the federation's site through us.
- When something fails, we stop politely. If the site refuses, you get an honest error. We do not insist, we do not retry in a loop, and we work around nothing.
What you ask for once is read many times: responses are cached, so ten fanciers who flew the same race mean one request to the federation, not ten.
Send us an export
If your federation or your clock produces a format we do not read yet, send us a file at contact@thatpigeon.app. That is the whole process.
What to send: the file exactly as the program produced it, unmodified, plus one sentence about what it is — which clock or which app produced it, and what it should contain.
What we do with it. We use it to write an importer and a test that runs
against it on every change. A file goes into the code only if it is yours and
you have told us explicitly that we may use it — otherwise it stays a sample we
read and delete. That rule is checked automatically on every check: a document
that has not been through that consent cannot enter the repository.
If the file contains other fanciers' names, tell us — we can work from a version with everything that is not yours removed.
Further reading
- Your data — what we collect, where the data lives, and the steps for checking the export yourself.
- How we calculate — the formulas behind the numbers in the results file.