# Quickstart

> Mint a key and pull your first borehole in about a minute.

<Steps>

<Step title="Mint a key">

In Product OS, go to **Settings → API keys** and click **Create key**. You need
to be a Super Admin on a Pro or legacy licence.

Give it a name describing what it is for, tick only the access it needs, and
choose which projects it can reach. Both of those narrow the blast radius if
the key ever leaks, so be mean with them.

<Callout type="warning">
The key is shown **once**. We store only a SHA-256 hash and genuinely cannot
recover it, so copy it into your password manager before closing the dialog.
If you lose it, revoke it and mint another.
</Callout>

</Step>

<Step title="Check it works">

```bash
curl -H "Authorization: Bearer $GIMLABS_API_KEY" \
  https://api.gimlabs.io/v1/me
```

```json
{
  "data": {
    "company": "GIMLabs",
    "scopes": ["projects:read", "locations:read", "tables:read"],
    "projects": [{ "id": "6512a4b8c9d0e1f234567801", "name": "Riverside Depot" }],
    "rateLimit": { "limit": 120, "remaining": 119, "reset": 1787781060 }
  }
}
```

`/me` needs no scope, so it always answers. It is the fastest way to confirm a
key works and to see exactly what it can reach. `projects` is `null` when the
key is not restricted to particular projects.

</Step>

<Step title="Find a project">

```bash
curl -H "Authorization: Bearer $GIMLABS_API_KEY" \
  "https://api.gimlabs.io/v1/projects?limit=25"
```

```json
{
  "data": [
    {
      "id": "6512a4b8c9d0e1f234567801",
      "projectId": "GL-2201",
      "projectName": "Riverside Depot",
      "status": "open"
    }
  ],
  "meta": { "nextCursor": null }
}
```

`id` is what every other endpoint wants. `projectId` is your own job reference.

</Step>

<Step title="Pull the boreholes">

```bash
curl -H "Authorization: Bearer $GIMLABS_API_KEY" \
  "https://api.gimlabs.io/v1/projects/6512a4b8c9d0e1f234567801/locations"
```

```json
{
  "data": [
    {
      "id": "6512a4b8c9d0e1f234567890",
      "locationId": "BH01",
      "table": "LOCA",
      "easting": null,
      "northing": null,
      "groundLevel": null,
      "finalDepth": 1.65,
      "data": { "LOCA_ID": "BH01", "LOCA_TYPE": "CP", "LOCA_FDEP": "1.65" },
      "updatedAt": "2026-06-14T09:12:44.000Z"
    }
  ],
  "meta": { "nextCursor": null }
}
```

The common survey fields are lifted out and converted to numbers for you.
Everything the location holds is also in `data`, keyed by AGS heading.

</Step>

<Step title="Read the geology">

```bash
curl -H "Authorization: Bearer $GIMLABS_API_KEY" \
  "https://api.gimlabs.io/v1/projects/6512a4b8c9d0e1f234567801/tables/GEOL"
```

```json
{
  "data": [
    {
      "id": "6512a4b8c9d0e1f2345678ab",
      "table": "GEOL",
      "locationId": "6512a4b8c9d0e1f234567890",
      "data": {
        "GEOL_TOP": "0",
        "GEOL_BASE": "0.2",
        "GEOL_DESC": "Firm brown slightly sandy CLAY with rare gravel...",
        "GEOL_GEOL": "TOPSOIL",
        "GEOL_LEG": "101"
      }
    }
  ],
  "meta": { "nextCursor": null, "table": "GEOL" }
}
```

Swap `GEOL` for any table the project holds.

</Step>

</Steps>

## Try it in Postman

There is a ready-made Postman collection covering every endpoint plus the
error cases. Import it, paste your key into the `apiKey` collection variable
(the **Current value** column, which is the one Postman actually sends), and
run it top to bottom. It chains itself: listing projects fills in the project
id for later requests.

## A note on numbers

Values inside `data` are returned as **strings**, exactly as stored, so nothing
is lost to rounding on our side. Convert them yourself if you need numbers. The
lifted location fields (`easting`, `finalDepth` and friends) are the exception
and come back as numbers or `null`.
