---
title: Authentication
url: /docs/developers/authentication
---

# Authentication

Every request to the GrowLocal API carries an API key in its `Authorization` header and goes to the address of the business the key was made in.

## The address

Every call goes to your business's own address:

```
https://api.growlocal.site/api/v1/profiles/{businessId}
```

`{businessId}` is the id in your dashboard's address while the business is open: the part after `/profiles/`. The API has four routes under it:

| Route | What it does |
|---|---|
| `GET /catalog` | Lists the operations this key may call right now ([Pagination](pagination.md)). |
| `GET /catalog/{entryRef}` | One operation's catalogue entry, with its input and result as JSON Schema. |
| `POST /invocations` | Makes a call ([Make a call and read the receipt](calls-and-receipts.md)). |
| `GET /operations/{operationId}` | Looks up the receipt of a change this key made ([Retries without doing it twice](retries.md)). |

## Send your key

Put the key in the `Authorization` header of every request, after `Bearer `:

```curl tabs
curl https://api.growlocal.site/api/v1/profiles/YOUR_BUSINESS_ID/catalog \
  -H "Authorization: Bearer gl_YOUR_API_KEY"
```

```javascript tabs
const response = await fetch(
  "https://api.growlocal.site/api/v1/profiles/YOUR_BUSINESS_ID/catalog",
  { headers: { Authorization: "Bearer gl_YOUR_API_KEY" } },
);
console.log(response.status, await response.json());
```

```python tabs
import requests

response = requests.get(
    "https://api.growlocal.site/api/v1/profiles/YOUR_BUSINESS_ID/catalog",
    headers={"Authorization": "Bearer gl_YOUR_API_KEY"},
    timeout=30,
)
print(response.status_code, response.json())
```

## When the key isn't accepted

Without a key, or with one that isn't accepted, the API answers `401` with a `WWW-Authenticate: Bearer` header and a JSON body whose `detail` says what happened:

| `detail` | What happened |
|---|---|
| `a bearer credential is required` | No `Authorization: Bearer …` header was sent. |
| `API key not recognised` | The key is mistyped, or isn't a GrowLocal key. |
| `API key revoked` | Someone revoked the key. Make a new one. |
| `API key expired` | The key's lifetime ran out. Make a new one. |
| `API key no longer carries any authority` | The person who made the key can no longer act for this business. |

A key works only at the address of the business it was made in. At another business's address the API answers `403` with `{"detail": "this key is not for this profile"}`.

## What a key can reach

A key reaches only the areas, and the level (Read or Act), chosen when it was made, and never more than the person who made it can do at the moment of each call. A call outside that reach is refused with a `rejected` receipt and `403` ([Errors](errors.md)). `GET /catalog` lists exactly what the key can call right now, so read it rather than guessing.

## Keep it secret

Treat a key like a password. Use it from a server or your own computer, never from a web page or an app you hand out, where anyone could read it. Keep it out of public repositories and messages. If a key is lost or might have been seen, revoke it in **Settings** → **Developers & AI** → **API** and make a new one ([Make an API key](api-keys.md)).
