# Permissions, errors and limits

> The scope table, the error format (RFC 9457) with stable codes, the rate limits.

URL: https://developers.vimine.network/en/guides/scopes-and-errors/

## Permissions (scopes)

A client asks for permissions when it is registered; the member sees them on the consent page.

| Scope | Who | What |
|---|---|---|
| `profile:read` | member | `GET /v1/me` — name, e-mail, contacts, particulars of birth, the fiscal code when there is one, and how the person is identified (`codicefiscale_check`) |
| `profile:write` | member | `PATCH /v1/me` — phone, gender, and the identification: date, place and country of birth, fiscal code (optional, may be added later; re-validated) |
| `membership:read` | member | `GET /v1/me/membership`, `/events`, `/statuto`, `/card` |
| `membership:request` | member | `POST /v1/me/membership` — membership request |
| `statuto:accept` | member | `POST /v1/me/membership/statuto/accept` |
| `network:manage` | member | the member's consent to circuits (coming soon) |
| `memberships:read` | client | `GET /v1/memberships/{id}/status` |
| `verify:read` | client | card verification beyond the anonymous quota |
| `identity:signup` | client | `POST /v1/signup` — create accounts on behalf of members ([server integrations](https://developers.vimine.network/en/guides/server/#enrol-members-from-your-system)) |
| `enroll:write` | client | `POST /v1/enroll` — submit membership requests, with or without a fiscal code ([guide](https://developers.vimine.network/en/guides/members-without-cf/)) |
| `events:read` | member | `GET /v1/events`, `/v1/events/{slug}`, `/eligibility` — members-only events included ([guide](https://developers.vimine.network/en/guides/events/)) |
| `registrations:read` | member, client | `GET /v1/me/registrations` (member); `GET /v1/events/{slug}/registrations` (client, no personal data) |
| `registrations:write` | member, client | `POST /v1/events/{slug}/registrations` and `DELETE /v1/me/registrations/{id}` (member); `POST …/registrations/guest` (client) |
| `checkins:write` | client | `POST /v1/checkins` — door check-ins from a card or a registration |
| `webhooks:manage` | client | coming soon |

A public or native client may only ask for member permissions; "client" permissions require a confidential
client. Someone who is not a member yet may only grant the enrolment permissions (`profile:*`,
`membership:read`, `membership:request`, `statuto:accept`).

## Errors

Error responses are `application/problem+json` (RFC 9457):

```json
{
  "type": "https://developers.vimine.network/errors/insufficient_scope",
  "title": "Forbidden",
  "status": 403,
  "code": "insufficient_scope",
  "detail": "Missing scope: profile:write",
  "request_id": "…"
}
```

`code` is stable: branch on that. `errors[]` accompanies `validation_failed` and `identification_required`
(`{ field, code }`). A `codicefiscale_mismatch` entry — a fiscal code that disagrees with the person's particulars —
also carries `mismatches`, `hints` and `confirmable`: when `confirmable` is `true` the person may confirm the code and
the request is repeated with `codicefiscale_confirmed: true` (see
[Members without a fiscal code](https://developers.vimine.network/en/guides/members-without-cf/#a-code-that-disagrees-and-the-confirmation)). The OAuth
endpoints (`/v1/oauth/token`, `/revoke`) answer in the OAuth format (`{ error, error_description }`).

| `code` | Meaning |
|---|---|
| `missing_token`, `invalid_token`, `token_expired` | 401 — sign in again (the SDK refreshes and retries by itself) |
| `insufficient_scope` | 403 — the token lacks that permission |
| `api_disabled` | 403 — the association has not enabled the API or does not accept requests |
| `plan_limit` | 403 — the association's plan has no room for one more member (check `aps.accepting_requests` before showing the form) |
| `not_available` | 403 — the association does not take requests right now: it has not accepted the platform's agreements or registered its statuto yet, it is not ready, or it takes only the people it invited ([the private beta](#the-private-beta)); `detail` says which. On `POST /v1/signup`: during the beta, accounts are created by invitation |
| `not_found` | 404 — also for resources of other associations |
| `validation_failed` | 422 — see `errors[]` (`required`, `invalid`, `invalid_codicefiscale`, `codicefiscale_mismatch` with `confirmable`…) |
| `identification_required` | 422 on `POST /v1/me/membership`, 409 on `POST /v1/enroll/confirm` — the person is not identified: a fiscal code, or date, place and country of birth, is needed; `errors[]` names what is missing |
| `statuto_outdated`, `statuto_required` | 422 — indicates the in-force statuto version (`detail`) |
| `rate_limited` | 429 — wait `Retry-After` |
| `unavailable` | 503 — retry shortly |

OAuth: `invalid_grant` (code or refresh token invalid, expired or reused), `invalid_client`, `invalid_scope`,
`unauthorized_client` (client awaiting activation), `access_denied` (the member cancelled).

In the SDK all of this is a [`VimineError`](https://developers.vimine.network/en/sdk/errors/) with the same `code`.

## The private beta

Vimine is in a private beta: people and associations come in **by invitation**. For a client this means:

- `POST /v1/signup` answers `403 not_available` and creates nothing, unless Vimine has opened your association's
  public enrolment;
- an association that takes only the people it invited has `aps.invitation_only: true` and
  `aps.accepting_requests: false` in its public profile ([`association(slug)`](https://developers.vimine.network/en/sdk/public/)); `POST /v1/enroll` and
  `POST /v1/me/membership` answer `403 not_available`. Someone with an invitation joins from the link they receive by mail;
- [sandboxes](https://developers.vimine.network/en/guides/sandbox/) stay open: test clients work as always.

Check `aps.accepting_requests` before showing an enrolment form — for the beta as for everything else;
`<vimine-events>` and `<vimine-enroll>` already do.

## Limits

- Per IP address: 60 requests/minute on the sensitive endpoints (card verification, fiscal code, token),
  120/minute on the rest; `RateLimit-*` and `Retry-After` in the responses.
- `POST /v1/me/membership` accepts `Idempotency-Key`: the same key within 24 hours returns the same response
  (the SDK generates one per call).
- Authenticated responses are `Cache-Control: no-store`.
- Every response carries a `request_id`: quote it when you report a problem.
