---
title: Authentication
description: Access tokens, refresh tokens, roles, and how the Vespy API scopes every request to one organization.
---

Every endpoint except the [webhook receivers](/getting-started/webhooks/) expects a bearer
token:

```http
Authorization: Bearer <access token>
```

## Tokens

| Token | Lifetime | Where it lives |
| --- | --- | --- |
| Access token | 15 minutes | Returned in the login response body; you store it |
| Refresh token | 7 days | `vespy_refresh_token`, an HttpOnly `SameSite=Lax` cookie set by the server |

`POST /api/auth/login` returns the access token and sets the refresh cookie in the same
response.

### Refreshing

```bash
curl -X POST https://api.getvespy.com/api/auth/token \
  -H 'Content-Type: application/json' \
  --cookie 'vespy_refresh_token=…' \
  -d '{"grantType":"refresh_token"}'
```

The body accepts either `grantType` or `grant_type`. The response has the same shape as
login, including a rotated refresh cookie.

`POST /api/auth/logout` clears the refresh cookie. Access tokens are not revoked
server-side, so an already-issued one stays valid until it expires.

:::note
Because the refresh token is an HttpOnly cookie, a non-browser client has to keep a cookie
jar to stay signed in. `curl --cookie-jar` or an HTTP client with cookie support is enough.
:::

## Organization scoping

The access token carries an `organizationId`, and every query is scoped to it — you cannot
read another organization's data by guessing a UUID. A resource that belongs to a different
organization returns `404`, not `403`, so ID enumeration reveals nothing.

## Roles

| Role | Sees |
| --- | --- |
| `admin` | The whole portfolio, plus billing, integrations, and user management |
| `manager` | The whole portfolio, and most mutations |
| `staff` | The portfolio, read-mostly |
| `tenant` | Only their own leases, charges, payments, and maintenance requests |
| `owner` | Only their own properties, statements, and ledgers |
| `vendor` | Only work orders assigned to them |

Endpoints tagged **Portal** and **Vendor Portal** are the ones scoped to a single tenant,
owner, or vendor; they derive the subject from the token rather than from a path parameter.

An endpoint your role cannot use returns `403` with a message naming the requirement, for
example `Only admins or managers can create vendors`.

## Server-sent events

`GET /api/events/stream` is the one authenticated endpoint that does not take an
`Authorization` header — `EventSource` cannot set headers, so it takes the access token as
a `token` query parameter instead.