The API
Version 1, a draft. Two ways in: a live area for apps without a key, and submissions for data partners with a key. Closed days are files, see Use the files.
Today's pins: GET /v1/live
The current pins in an area, while the day is still open. No key, and any
website may call it (CORS *).
GET https://api.openpinsheet.com/v1/live?bbox=<west>,<south>,<east>,<north>
- The box is at most 0.5 degrees wide and 0.5 degrees high, otherwise
400 bbox_too_large. - A box cannot cross the 180th meridian; query both sides separately.
- A ground without any coordinate does not appear here, only in the files.
- For every data partner and ground in the box, only its most recent visible day is returned.
- A day's pins become visible at about 07:00 local time, not when they are sent: at a small club the time the pins were set is one person's working hours.
- Cached for five minutes.
The answer is a GeoJSON FeatureCollection like a published file
(Format), with format, as_of,
license, attribution, notes and
features. Live records can still change until the day closes;
for anything you keep, use the files.
curl 'https://api.openpinsheet.com/v1/live?bbox=13.0,52.0,13.1,52.1'
const box = "13.0,52.0,13.1,52.1";
const url = "https://api.openpinsheet.com/v1/live?bbox=" + box;
const today = await (await fetch(url)).json();
for (const feature of today.features) {
console.log(feature.properties.hole, feature.properties.source,
feature.geometry && feature.geometry.coordinates);
}
{ "type": "FeatureCollection", "format": 1, "as_of": "2027-04-12",
"license": { "name": "Open Database License 1.0", "spdx": "ODbL-1.0", "url": "..." },
"attribution": "Pin positions: OpenPinsheet and its channels ...",
"notes": [ "..." ],
"features": [
{ "type": "Feature",
"geometry": { "type": "Point", "coordinates": [13.1234573, 52.1234561] },
"properties": { "date": "2027-04-12", "date_basis": "local", "hole": "7",
"source": "estimated", "front_m": 12, "left_m": 9.5,
"channel": "..." } }
] }
Deliver pins: POST /v1/submissions
A data partner delivers the pins of one ground for one day, with a key. A key belongs to one partner; ask for one at info@openyardage.com. Partners agree that the pins they deliver are under the Open Database License 1.0.
curl -X POST https://api.openpinsheet.com/v1/submissions \
-H "Authorization: Bearer $OPENPINSHEET_KEY" \
-H "Content-Type: application/json" \
-d '{ "format": 1, "group": "w620181682", "date": "2027-04-12",
"pins": [ { "hole": "7", "lat": 52.1234561, "lon": 13.1234573,
"source": "estimated", "front_m": 12, "left_m": 9.5,
"input": { "front": 12, "offset": 5, "side": "right", "unit": "m" } },
{ "hole": "8", "missing": true } ] }'
Fields
format: the integer1.group: your own label for one ground, 1 to 64 charactersA-Z a-z 0-9 . _ : -. It is never published; it only tells OpenPinsheet which earlier submission a new one replaces.date: the calendar date at the ground,YYYY-MM-DD.pins: 1 to 150 entries, eachholeat most once. A pin carries the columns of the format exceptdate,date_basisandchannel; a lost position is{ "hole": "9", "missing": true }.
Checks
- Every pin passes the rules of the format.
datelies within one day of today's UTC date, and the day is still open.- All pins with a coordinate lie within 5 km of each other: one submission is one ground.
- The body is at most 64 KiB. If any check fails, nothing is stored.
Replacing and withdrawing
A submission replaces everything the same partner sent for the same
group and date; holes it does not name are gone
afterwards. To correct a day, send the whole day again. To withdraw it
while the day is open:
curl -X DELETE "https://api.openpinsheet.com/v1/submissions?group=w620181682&date=2027-04-12" \ -H "Authorization: Bearer $OPENPINSHEET_KEY"
A day closes at D + 3 days, 00:00 UTC and is then written to
the files. After that it cannot be replaced or withdrawn here.
Answers
{ "stored": 3, "group": "w620181682", "date": "2027-04-12",
"replaced": false, "visible_from": "2027-04-12T06:00:00Z" }
With ?dry_run=1 everything is checked and nothing is stored:
the answer says "stored": 0 and "dry_run": true.
Errors carry { "error": "<code>", "message": "<sentence>" }:
| Status | error | Meaning |
|---|---|---|
| 400 | invalid_json | the body is not JSON |
| 401 | unauthorized | key missing, unknown or revoked; always the same answer |
| 409 | day_closed | DELETE only: the day is already published. A POST for a closed day fails the date check (422). |
| 413 | body_too_large | more than 64 KiB |
| 422 | invalid_submission | problems lists each problem with hole, field and message |
Become a data partner
A key belongs to one data partner, and OpenPinsheet stores only its sha256. At most two valid keys exist per partner, so a key can be swapped without a gap. Keys are issued and revoked by the maintainer. Write to info@openyardage.com.
A data partner agrees to the terms of OpenPinsheet, among them that the pins it delivers are under the Open Database License 1.0, before it gets a key.