# Authentication (/authentication)

Every Verify request carries an API key in the `Authorization` header:

```http
Authorization: Bearer fg_live_...
```

<Tabs items={["cURL", "JavaScript", "Python"]}>
<Tab value="cURL">

```bash
curl https://api.fieldgeist.com/v1/verify/parse \
  -H "Authorization: Bearer $FIELDGEIST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"line": "200 W Washington St Ste 1 Phoenix AZ 85003"}'
```

</Tab>
<Tab value="JavaScript">

```js
await fetch("https://api.fieldgeist.com/v1/verify/parse", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.FIELDGEIST_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ line: "200 W Washington St Ste 1 Phoenix AZ 85003" }),
});
```

</Tab>
<Tab value="Python">

```python
requests.post(
    "https://api.fieldgeist.com/v1/verify/parse",
    headers={"Authorization": f"Bearer {os.environ['FIELDGEIST_API_KEY']}"},
    json={"line": "200 W Washington St Ste 1 Phoenix AZ 85003"},
    timeout=10,
)
```

</Tab>
</Tabs>

## API keys [#api-keys]

- **Keys belong to a team**, not a person. Requests made with a key draw from that team's credits and show in its Usage and Logs.
- **Format:** `fg_live_` followed by 43 letters and digits (51 characters in all).
- **Shown once.** The portal shows a new key in full only when you create it. Afterwards it shows the name, the last four characters, when it was created and when it was last used. Fieldgeist stores only a hash of the key, so a lost key can't be recovered: create a new one.
- **Who can manage keys:** every team role (Owner, Admin and Developer) can create, rename and revoke the team's keys.
- **Up to 25 active keys per team.** Key names are up to 64 characters.
- **Unused keys are flagged.** A key older than 30 days that hasn't been used in 30 days shows "Unused for N days" in the portal, so you can revoke it.

### Create a key [#create-a-key]

1. Sign in at [app.fieldgeist.com](https://app.fieldgeist.com) and open **API keys**.
2. Select **Create key** and name it after where it will run, such as "Production server" or "Staging worker".
3. Copy the key, store it in your secrets manager, and confirm **I've stored this key**.

### Revoke a key [#revoke-a-key]

Open **API keys**, find the key by its name and last four characters, and revoke it. Requests with a revoked key get `401 invalid_api_key`. A revocation can take up to about a minute to reach every server; requests made with the key before then are billed to the team.

## Keep keys safe [#keep-keys-safe]

- **Call the API from your server**, never from a browser or mobile app. Anything shipped to a client can be read. The API doesn't accept cross-origin browser requests from your sites.
- **One key per environment or service.** Separate keys for production, staging and each job let you revoke one without touching the others, and make Logs easier to read.
- **Keep keys out of source control.** Load them from environment variables or a secrets manager.
- **Revoke a key you suspect has leaked**, then create a replacement. Requests made with a key before you revoke it are billed to your team.
- **Revoke keys you no longer use.** The portal's "Unused for N days" flag shows candidates.

## Authentication errors [#authentication-errors]

| Status | `error` | When |
| --- | --- | --- |
| `401` | `invalid_api_key` | The header is malformed (not `Bearer <key>`), or the key is unknown or revoked. The response carries `WWW-Authenticate: Bearer`. |
| `429` | `rate_limited` | Too many requests with keys we don't recognize came from your IP address. Wait a minute. See [Rate limits](/rate-limits). |
| `503` | `unavailable` | We couldn't check the key. Retry shortly. |

```json
{
  "error": "invalid_api_key",
  "message": "Send a valid API key as Authorization: Bearer <key>."
}
```

A valid key can still be refused when the team can't use the API: see `402` and `403` in [Errors](/api-reference/errors).
