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

# Permissions

> Three permission maps — types, extensions, edges — and the dual-gate rule

Every credential (API key or OAuth grant) carries three permission maps. Reads and writes are enforced against them. Admin credentials bypass all checks.

## The four maps

```json theme={null}
{
  "type_permissions":      { "<type_pattern>": "read" | "write" | "none" },
  "extension_permissions": { "<namespace_pattern>": "read" | "write" },
  "edge_permissions":      { "<edge_type_pattern>": "read" | "write" },
  "metadata_permissions":  { "<sub_resource>": "read" | "write" }
}
```

### `type_permissions`

Controls read and write access to item types. Patterns support `*` wildcard and `parent.*` subtree matching.

```json theme={null}
{
  "core.note": "write",
  "core.bookmark.*": "read",
  "my-app.session": "write",
  "*": "none"
}
```

Resolution: most specific pattern wins. `core.bookmark.*` beats `*`; `core.bookmark.readwise` beats `core.bookmark.*`.

Reads inherit down the type chain — `read core.media` returns `core.media.*` items (book, article, film, etc.). Writes don't — writing to an inheriting type requires permission on the specific type. This prevents cross-app write-through on inheriting types.

### `extension_permissions`

Controls which extension namespaces the credential can read or write. Extensions are **not** returned by default — a namespace must be explicitly permitted.

```json theme={null}
{
  "my-app.*": "write",
  "readwise-reader.reading_progress": "read"
}
```

A credential with `extension_permissions: {}` cannot read or write any extension.

### `edge_permissions`

Controls which edge types the credential can create, update, or delete.

```json theme={null}
{
  "about": "write",
  "parent-of": "write",
  "in-thread": "read",
  "*": "none"
}
```

New credentials default to `edge_permissions: {}` — edge access is opt-in; apps must declare each edge type they need.

### `metadata_permissions`

Controls metadata-layer mutations that don't fit the type / extension / edge axes — currently registering custom types via `POST /types`.

```json theme={null}
{
  "types": "write"
}
```

Keys are sub-resource names; the only one enforced today is `types` (gates `POST /types` for non-admin credentials). New credentials default to `metadata_permissions: {}`.

OAuth tokens project the `metadata.<sub>:<verb>` scope into this map on the synthetic credential — a token granted `metadata.types:write` carries `metadata_permissions: { types: "write" }`. Admin credentials bypass.

## The dual-gate rule

**Edge writes require permission on both the source item's type AND the edge type.**

Creating an `about` edge from a `core.note` to a `core.entity.person` needs:

* `type_permissions`: write on `core.note` (the source item).
* `edge_permissions`: write on `about`.

Either missing → `403 edge_permission_denied`.

Admin credentials bypass both.

The rationale: an edge is a mutation of the source item's graph view. Without type write, the app can't mutate the item; adding an edge would be a back-door around that. Without edge write on the type, the app can't create that kind of relationship — even if it owns the item.

## Enforcement points

<Accordion title="Enforcement by endpoint (quick reference)">
  | Action                            | Checks                                                                          |
  | --------------------------------- | ------------------------------------------------------------------------------- |
  | `GET /items?type=X`               | `type_permissions[X]: read` (or inheriting pattern)                             |
  | `POST /items` (create X)          | `type_permissions[X]: write`                                                    |
  | `PATCH /items/{id}` (update X)    | `type_permissions[X]: write`                                                    |
  | `DELETE /items/{id}`              | `type_permissions[X]: write`                                                    |
  | `POST /items/{id}/transition`     | `type_permissions[X]: write`                                                    |
  | `POST /items` with `edges`        | `type_permissions[X]: write` AND `edge_permissions[edge_type]: write` per edge  |
  | `POST /edges`                     | `type_permissions[source.type]: write` AND `edge_permissions[edge_type]: write` |
  | `DELETE /edges/{id}`              | same as `POST /edges`                                                           |
  | `PATCH /edges/{id}`               | same as `POST /edges`                                                           |
  | `GET /items/{id}/extensions/{ns}` | `extension_permissions[ns]: read`                                               |
  | `PUT /items/{id}/extensions/{ns}` | `extension_permissions[ns]: write`                                              |
</Accordion>

## Default tier on credentials

Credentials carry a `default_tier` field — `library` or `feed` — that stamps the tier on items written by the credential when the client omits one. Clients can override per-write. There is no read-side tier-gate on the credential; tier filtering is a query concern (`GET /items?tier=feed`), not a permission boundary.

## Patterns and practice

* **A single app typically needs \~3–5 types and one extension namespace.** A notes app might have `type: write` on `core.note`, `metadata: write`, `edge.about: write`, `edge.parent-of: write`, and `extension.notes-app.*: write`.
* **Publishing destinations tend to be narrower than capture apps.** A read-later service mostly writes `core.bookmark.*` and `core.highlight`; it needs edge write on `references`.
* **Start tight.** It's easier to add scopes than audit what's actually in use later.

## Revocation effect

Revoking a credential returns `401 unauthorized` on the next request. In-flight long-lived connections (SSE) terminate on the next heartbeat failure — there's no active push. The audit trail captures the revocation event.
