> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vein.finance/llms.txt
> Use this file to discover all available pages before exploring further.

# Authentication

> How Vein API keys work.

<Warning>
  **Breaking change (2026-06-30):** `/v1` financial endpoints (`metrics:read`) now require an
  approved data-access grant from the company. Portfolio membership alone no longer grants metric
  access. Existing integrations must submit `POST /v1/access-requests` and wait for the company's
  approval before financial data is returned. See [Data access & consent](#data-access--consent)
  below.
</Warning>

## API keys

Every request authenticates with a bearer token in the `Authorization` header:

```
Authorization: Bearer vein_sk_live_8aK2nMqP9wF3vR7tB6yX4cZ1jL5hG0sD
```

Keys are formatted `vein_sk_{live|test}_{32 chars}`:

* `vein_sk_live_…` accesses your production data.
* `vein_sk_test_…` is intended for sandbox/non-production use; like all keys, it only sees the company it is bound to.

Keys are shown once at creation and stored only as a SHA-256 hash. If you lose
a key, rotate it: create a new one and revoke the old.

## Scopes

Each key carries a set of scopes. A request to an endpoint whose scope your key
lacks returns `403 permission_error` with code `insufficient_scope`.

| Scope            | Grants                                                                |
| ---------------- | --------------------------------------------------------------------- |
| `companies:read` | `GET /v1/companies`                                                   |
| `metrics:read`   | `GET /v1/companies/:id/metrics`, `GET /v1/companies/:id/metrics/:key` |
| `reports:read`   | `GET /v1/reports` (coming soon)                                       |

## Rate limits

The API is rate limited **per key** (not per IP). Every response carries:

| Header                | Meaning                                   |
| --------------------- | ----------------------------------------- |
| `RateLimit-Limit`     | Requests allowed per window for your key. |
| `RateLimit-Remaining` | Requests left in the current window.      |
| `RateLimit-Reset`     | Seconds until the window resets.          |

When you exceed the limit you get `429 rate_limit_error` (code
`rate_limit_exceeded`) with a `Retry-After` header giving the seconds to wait.
Back off until then rather than retrying immediately.

## Errors

All errors share one shape. Branch on `error.code`, not `error.message`:

```json theme={null}
{
  "error": {
    "type": "authentication_error",
    "code": "invalid_api_key",
    "message": "The provided API key is invalid.",
    "request_id": "req_8a92b1c0",
    "documentation_url": "https://docs.vein.finance/errors/invalid_api_key"
  }
}
```

Cite the `request_id` (also returned as the `Vein-Request-Id` header) in support
tickets so we can find your request in our logs.

## Data access & consent

Financial endpoints (currently `GET /v1/companies/:id/metrics` and
`GET /v1/companies/:id/metrics/:key`) require two things: an API key with the
`metrics:read` scope **and** an approved data-access grant from the company. The
`companies:read` scope (used by `GET /v1/companies`) is unaffected and stays
open; portfolio membership alone is sufficient to list companies.

Each company object returned by `GET /v1/companies` carries an `access` field
with one of four values that tells you the state of your grant for that company:
`none` (no request exists), `pending` (request submitted, awaiting the company's
approval), `approved` (access granted), or `revoked` (a previously approved
grant was revoked by the company).

### Requesting access

Submit `POST /v1/access-requests` with the `company_id` and the `scopes` you
need. The company receives a notification and must approve the request in their
Vein dashboard before the grant activates. If you submit an identical request
(same `company_id` and `scopes`) while an existing request is `pending` or
`approved`, the endpoint is idempotent and returns the existing record with HTTP
200 rather than creating a duplicate.

```json theme={null}
POST /v1/access-requests
{
  "company_id": "startup_acme",
  "scopes": ["metrics:read"],
  "purpose": "Quarterly portfolio review: cash and headcount metrics needed."
}
```

### Polling for approval

Call `GET /v1/access-requests` (optionally with `?status=pending`) to list your
outstanding requests and check their status. When `status` changes to `approved`
you may call the financial endpoints for that company.

### Error codes on 403

When a financial endpoint returns 403, branch on `error.code` to determine next
steps:

| Code                 | Meaning                                           | Action                                  |
| -------------------- | ------------------------------------------------- | --------------------------------------- |
| `insufficient_scope` | API key lacks `metrics:read`                      | Rotate to a key with the correct scope  |
| `access_required`    | No data-access grant exists for this company      | Submit `POST /v1/access-requests`       |
| `access_pending`     | Grant requested; the company has not yet approved | Wait for the company's approval         |
| `access_revoked`     | A previously approved grant was revoked           | Contact the company to reinstate access |
